Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/slideshow/source/engine/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 31 kB image not shown  

Quelle  tools.cxx   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */



#include <comphelper/diagnose_ex.hxx>
#include <canvas/canvastools.hxx>

#include <math.h>

#include <com/sun/star/beans/NamedValue.hpp>
#include <com/sun/star/awt/Rectangle.hpp>
#include <com/sun/star/animations/ValuePair.hpp>
#include <com/sun/star/drawing/FillStyle.hpp>
#include <com/sun/star/drawing/LineStyle.hpp>
#include <com/sun/star/awt/FontSlant.hpp>

#include <basegfx/polygon/b2dpolygon.hxx>
#include <basegfx/polygon/b2dpolygontools.hxx>
#include <basegfx/range/b2drange.hxx>
#include <basegfx/vector/b2dvector.hxx>
#include <basegfx/vector/b2ivector.hxx>
#include <basegfx/matrix/b2dhommatrix.hxx>
#include <basegfx/numeric/ftools.hxx>
#include <basegfx/utils/lerp.hxx>
#include <basegfx/matrix/b2dhommatrixtools.hxx>

#include <cppcanvas/basegfxfactory.hxx>

#include <svtools/colorcfg.hxx>

#include <unoview.hxx>
#include <slideshowexceptions.hxx>
#include <smilfunctionparser.hxx>
#include <tools.hxx>

#include <limits>


using namespace ::com::sun::star;

namespace slideshow::internal
{
        namespace
        {
            class NamedValueComparator
            {
            public:
                explicit NamedValueComparator( const beans::NamedValue& rKey ) :
                    mrKey( rKey )
                {
                }

                bool operator()( const beans::NamedValue& rValue ) const
                {
                    return rValue.Name == mrKey.Name && rValue.Value == mrKey.Value;
                }

            private:
                const beans::NamedValue&    mrKey;
            };

            ::basegfx::B2DHomMatrix getAttributedShapeTransformation( const ::basegfx::B2DRectangle&        rShapeBounds,
                                                                      const ShapeAttributeLayerSharedPtr&   pAttr )
            {
                ::basegfx::B2DHomMatrix     aTransform;
                const basegfx::B2DSize rSize(rShapeBounds.getRange().getX(), rShapeBounds.getRange().getY());

                const double nShearX( pAttr->isShearXAngleValid() ?
                                      pAttr->getShearXAngle() :
                                      0.0 );
                const double nShearY( pAttr->isShearYAngleValid() ?
                                      pAttr->getShearYAngle() :
                                      0.0 );
                const double nRotation( pAttr->isRotationAngleValid() ?
                                        basegfx::deg2rad(pAttr->getRotationAngle()) :
                                        0.0 );

                // scale, shear and rotation pivot point is the shape
                // center - adapt origin accordingly
                aTransform.translate( -0.5, -0.5 );

                // ensure valid size (zero size will inevitably lead
                // to a singular transformation matrix)
                aTransform.scale( ::basegfx::pruneScaleValue(
                                      rSize.getWidth() ),
                                  ::basegfx::pruneScaleValue(
                                      rSize.getHeight() ) );

                const bool bNeedShearX( !::basegfx::fTools::equalZero(nShearX) );
                const bool bNeedShearY( !::basegfx::fTools::equalZero(nShearY) );
                const bool bNeedRotation( !::basegfx::fTools::equalZero(nRotation) );

                if( bNeedRotation || bNeedShearX || bNeedShearY )
                {
                    if( bNeedShearX )
                        aTransform.shearX( nShearX );

                    if( bNeedShearY )
                        aTransform.shearY( nShearY );

                    if( bNeedRotation )
                        aTransform.rotate( nRotation );
                }

                // move left, top corner back to position of the
                // shape. Since we've already translated the
                // center of the shape to the origin (the
                // translate( -0.5, -0.5 ) above), translate to
                // center of final shape position here.
                aTransform.translate( rShapeBounds.getCenterX(),
                                      rShapeBounds.getCenterY() );

                return aTransform;
            }
        }

        // Value extraction from Any
        // =========================

        /// extract unary double value from Any
        bool extractValue( double&                      o_rValue,
                           const uno::Any&              rSourceAny,
                           const ShapeSharedPtr&        rShape,
                           const ::basegfx::B2DVector&  rSlideBounds )
        {
            // try to extract numeric value (double, or smaller POD, like float or int)
            if( rSourceAny >>= o_rValue)
            {
                // succeeded
                return true;
            }

            // try to extract string
            OUString aString;
            if( !(rSourceAny >>= aString) )
                return false// nothing left to try

            // parse the string into an ExpressionNode
            try
            {
                // Parse string into ExpressionNode, eval node at time 0.0
                o_rValue = (*SmilFunctionParser::parseSmilValue(
                                aString,
                                calcRelativeShapeBounds(rSlideBounds,
                                                        rShape->getBounds()) ))(0.0);
            }
            catch( ParseError& )
            {
                return false;
            }

            return true;
        }

        /// extract enum/constant group value from Any
        bool extractValue( sal_Int32&                       o_rValue,
                           const uno::Any&                  rSourceAny,
                           const ShapeSharedPtr&            /*rShape*/,
                           const ::basegfx::B2DVector&      /*rSlideBounds*/ )
        {
            // try to extract numeric value (int, or smaller POD, like byte)
            if( rSourceAny >>= o_rValue)
            {
                // succeeded
                return true;
            }

            // okay, no plain int. Maybe one of the domain-specific enums?
            drawing::FillStyle eFillStyle;
            if( rSourceAny >>= eFillStyle )
            {
                o_rValue = sal::static_int_cast<sal_Int16>(eFillStyle);

                // succeeded
                return true;
            }

            drawing::LineStyle eLineStyle;
            if( rSourceAny >>= eLineStyle )
            {
                o_rValue = sal::static_int_cast<sal_Int16>(eLineStyle);

                // succeeded
                return true;
            }

            awt::FontSlant eFontSlant;
            if( rSourceAny >>= eFontSlant )
            {
                o_rValue = sal::static_int_cast<sal_Int16>(eFontSlant);

                // succeeded
                return true;
            }

            // nothing left to try. Failure
            return false;
        }

        /// extract enum/constant group value from Any
        bool extractValue( sal_Int16&                       o_rValue,
                           const uno::Any&                  rSourceAny,
                           const ShapeSharedPtr&            rShape,
                           const ::basegfx::B2DVector&      rSlideBounds )
        {
            sal_Int32 aValue;
            if( !extractValue(aValue,rSourceAny,rShape,rSlideBounds) )
                return false;

            if( std::numeric_limits<sal_Int16>::max() < aValue ||
                std::numeric_limits<sal_Int16>::min() > aValue )
            {
                return false;
            }

            o_rValue = static_cast<sal_Int16>(aValue);

            return true;
        }

        /// extract color value from Any
        bool extractValue( RGBColor&                    o_rValue,
                           const uno::Any&              rSourceAny,
                           const ShapeSharedPtr&        /*rShape*/,
                           const ::basegfx::B2DVector&  /*rSlideBounds*/ )
        {
            // try to extract numeric value (double, or smaller POD, like float or int)
            {
                double nTmp = 0;
                if( rSourceAny >>= nTmp )
                {
                    sal_uInt32 aIntColor( static_cast< sal_uInt32 >(nTmp) );

                    // TODO(F2): Handle color values correctly, here
                    o_rValue = unoColor2RGBColor( aIntColor );

                    // succeeded
                    return true;
                }
            }

            // try double sequence
            {
                uno::Sequence< double > aTmp;
                if( rSourceAny >>= aTmp )
                {
                    ENSURE_OR_THROW( aTmp.getLength() == 3,
                                      "extractValue(): inappropriate length for RGB color value" );

                    o_rValue = RGBColor( aTmp[0], aTmp[1], aTmp[2] );

                    // succeeded
                    return true;
                }
            }

            // try sal_Int32 sequence
            {
                uno::Sequence< sal_Int32 > aTmp;
                if( rSourceAny >>= aTmp )
                {
                    ENSURE_OR_THROW( aTmp.getLength() == 3,
                                      "extractValue(): inappropriate length for RGB color value" );

                    // truncate to byte
                    o_rValue = RGBColor( ::cppcanvas::makeColor(
                                             static_cast<sal_uInt8>(aTmp[0]),
                                             static_cast<sal_uInt8>(aTmp[1]),
                                             static_cast<sal_uInt8>(aTmp[2]),
                                             255 ) );

                    // succeeded
                    return true;
                }
            }

            // try sal_Int8 sequence
            {
                uno::Sequence< sal_Int8 > aTmp;
                if( rSourceAny >>= aTmp )
                {
                    ENSURE_OR_THROW( aTmp.getLength() == 3,
                                      "extractValue(): inappropriate length for RGB color value" );

                    o_rValue = RGBColor( ::cppcanvas::makeColor( aTmp[0], aTmp[1], aTmp[2], 255 ) );

                    // succeeded
                    return true;
                }
            }

            // try to extract string
            OUString aString;
            if( !(rSourceAny >>= aString) )
                return false// nothing left to try

            // TODO(F2): Provide symbolic color values here
            o_rValue = RGBColor( 0.5, 0.5, 0.5 );

            return true;
        }

        /// extract color value from Any
        bool extractValue( HSLColor&                    o_rValue,
                           const uno::Any&              rSourceAny,
                           const ShapeSharedPtr&        /*rShape*/,
                           const ::basegfx::B2DVector&  /*rSlideBounds*/ )
        {
            // try double sequence
            {
                uno::Sequence< double > aTmp;
                if( rSourceAny >>= aTmp )
                {
                    ENSURE_OR_THROW( aTmp.getLength() == 3,
                                      "extractValue(): inappropriate length for HSL color value" );

                    o_rValue = HSLColor( aTmp[0], aTmp[1], aTmp[2] );

                    // succeeded
                    return true;
                }
            }

            // try sal_Int8 sequence
            {
                uno::Sequence< sal_Int8 > aTmp;
                if( rSourceAny >>= aTmp )
                {
                    ENSURE_OR_THROW( aTmp.getLength() == 3,
                                      "extractValue(): inappropriate length for HSL color value" );

                    o_rValue = HSLColor( aTmp[0]*360.0/255.0, aTmp[1]/255.0, aTmp[2]/255.0 );

                    // succeeded
                    return true;
                }
            }

            return false// nothing left to try
        }

        /// extract plain string from Any
        bool extractValue( OUString&             o_rValue,
                           const uno::Any&              rSourceAny,
                           const ShapeSharedPtr&        /*rShape*/,
                           const ::basegfx::B2DVector&  /*rSlideBounds*/ )
        {
            // try to extract string
            return rSourceAny >>= o_rValue;
        }

        /// extract bool value from Any
        bool extractValue( bool&                        o_rValue,
                           const uno::Any&              rSourceAny,
                           const ShapeSharedPtr&        /*rShape*/,
                           const ::basegfx::B2DVector&  /*rSlideBounds*/ )
        {
            bool bTmp;
            // try to extract bool value
            if( rSourceAny >>= bTmp )
            {
                o_rValue = bTmp;

                // succeeded
                return true;
            }

            // try to extract string
            OUString aString;
            if( !(rSourceAny >>= aString) )
                return false// nothing left to try

            // we also take the strings "true" and "false",
            // as well as "on" and "off" here
            if( aString.equalsIgnoreAsciiCase("true") ||
                aString.equalsIgnoreAsciiCase("on") )
            {
                o_rValue = true;
                return true;
            }
            if( aString.equalsIgnoreAsciiCase("false") ||
                aString.equalsIgnoreAsciiCase("off") )
            {
                o_rValue = false;
                return true;
            }

            // ultimately failed.
            return false;
        }

        /// extract double 2-tuple from Any
        bool extractValue( ::basegfx::B2DTuple&         o_rPair,
                           const uno::Any&              rSourceAny,
                           const ShapeSharedPtr&        rShape,
                           const ::basegfx::B2DVector&  rSlideBounds )
        {
            animations::ValuePair aPair;

            if( !(rSourceAny >>= aPair) )
                return false;

            double nFirst;
            if( !extractValue( nFirst, aPair.First, rShape, rSlideBounds ) )
                return false;

            double nSecond;
            if( !extractValue( nSecond, aPair.Second, rShape, rSlideBounds ) )
                return false;

            o_rPair.setX( nFirst );
            o_rPair.setY( nSecond );

            return true;
        }

        bool findNamedValue( uno::Sequence< beans::NamedValue > const& rSequence,
                             const beans::NamedValue&               rSearchKey )
        {
            return ::std::any_of( rSequence.begin(), rSequence.end(),
                                  NamedValueComparator( rSearchKey ) );
        }

        basegfx::B2DRange calcRelativeShapeBounds( const basegfx::B2DVector& rPageSize,
                                                   const basegfx::B2DRange&  rShapeBounds )
        {
            return basegfx::B2DRange( rShapeBounds.getMinX() / rPageSize.getX(),
                                      rShapeBounds.getMinY() / rPageSize.getY(),
                                      rShapeBounds.getMaxX() / rPageSize.getX(),
                                      rShapeBounds.getMaxY() / rPageSize.getY() );
        }

        // TODO(F2): Currently, the positional attributes DO NOT mirror the XShape properties.
        // First and foremost, this is because we must operate with the shape boundrect,
        // not position and size (the conversion between logic rect, snap rect and boundrect
        // are non-trivial for draw shapes, and I won't duplicate them here). Thus, shapes
        // rotated on the page will still have 0.0 rotation angle, as the metafile
        // representation fetched over the API is our default zero case.

        ::basegfx::B2DHomMatrix getShapeTransformation( const ::basegfx::B2DRectangle&      rShapeBounds,
                                                        const ShapeAttributeLayerSharedPtr& pAttr )
        {
            if( !pAttr )
            {
                const basegfx::B2DHomMatrix aTransform(basegfx::utils::createScaleTranslateB2DHomMatrix(
                    rShapeBounds.getWidth(), rShapeBounds.getHeight(),
                    rShapeBounds.getMinX(), rShapeBounds.getMinY()));

                return aTransform;
            }
            else
            {
                return getAttributedShapeTransformation( rShapeBounds,
                                                         pAttr );
            }
        }

        ::basegfx::B2DHomMatrix getSpriteTransformation( const ::basegfx::B2DVector&            rPixelSize,
                                                         const ::basegfx::B2DVector&            rOrigSize,
                                                         const ShapeAttributeLayerSharedPtr&    pAttr )
        {
            ::basegfx::B2DHomMatrix aTransform;

            if( pAttr )
            {
                const double nShearX( pAttr->isShearXAngleValid() ?
                                      pAttr->getShearXAngle() :
                                      0.0 );
                const double nShearY( pAttr->isShearYAngleValid() ?
                                      pAttr->getShearYAngle() :
                                      0.0 );
                const double nRotation( pAttr->isRotationAngleValid() ?
                                        basegfx::deg2rad(pAttr->getRotationAngle()) :
                                        0.0 );

                // scale, shear and rotation pivot point is the
                // sprite's pixel center - adapt origin accordingly
                aTransform.translate( -0.5*rPixelSize.getX(),
                                      -0.5*rPixelSize.getY() );

                const ::basegfx::B2DSize aSize(
                    pAttr->isWidthValid() ? pAttr->getWidth() : rOrigSize.getX(),
                    pAttr->isHeightValid() ? pAttr->getHeight() : rOrigSize.getY() );

                // ensure valid size (zero size will inevitably lead
                // to a singular transformation matrix).
                aTransform.scale( ::basegfx::pruneScaleValue(
                                      aSize.getWidth() /
                                      ::basegfx::pruneScaleValue(
                                          rOrigSize.getX() ) ),
                                  ::basegfx::pruneScaleValue(
                                      aSize.getHeight() /
                                      ::basegfx::pruneScaleValue(
                                          rOrigSize.getY() ) ) );

                const bool bNeedShearX( !::basegfx::fTools::equalZero(nShearX) );
                const bool bNeedShearY( !::basegfx::fTools::equalZero(nShearY) );
                const bool bNeedRotation( !::basegfx::fTools::equalZero(nRotation) );

                if( bNeedRotation || bNeedShearX || bNeedShearY )
                {
                    if( bNeedShearX )
                        aTransform.shearX( nShearX );

                    if( bNeedShearY )
                        aTransform.shearY( nShearY );

                    if( bNeedRotation )
                        aTransform.rotate( nRotation );
                }

                // move left, top corner back to original position of
                // the sprite (we've translated the center of the
                // sprite to the origin above).
                aTransform.translate( 0.5*rPixelSize.getX(),
                                      0.5*rPixelSize.getY() );
            }

            // return identity transform for un-attributed
            // shapes. This renders the sprite as-is, in its
            // document-supplied size.
            return aTransform;
        }

        ::basegfx::B2DRectangle getShapeUpdateArea( const ::basegfx::B2DRectangle&      rUnitBounds,
                                                    const ::basegfx::B2DHomMatrix&      rShapeTransform,
                                                    const ShapeAttributeLayerSharedPtr& pAttr )
        {
            ::basegfx::B2DHomMatrix aTransform;

            if( pAttr &&
                pAttr->isCharScaleValid() &&
                fabs(pAttr->getCharScale()) > 1.0 )
            {
                // enlarge shape bounds. Have to consider the worst
                // case here (the text fully fills the shape)

                const double nCharScale( pAttr->getCharScale() );

                // center of scaling is the middle of the shape
                aTransform.translate( -0.5, -0.5 );
                aTransform.scale( nCharScale, nCharScale );
                aTransform.translate( 0.5, 0.5 );
            }

            aTransform *= rShapeTransform;

            // apply shape transformation to unit rect
            return ::canvas::tools::calcTransformedRectBounds(
                rUnitBounds,
                aTransform );
        }

        ::basegfx::B2DRange getShapeUpdateArea( const ::basegfx::B2DRange&      rUnitBounds,
                                                    const ::basegfx::B2DRange&      rShapeBounds )
        {
            return ::basegfx::B2DRectangle(
                basegfx::utils::lerp( rShapeBounds.getMinX(),
                                      rShapeBounds.getMaxX(),
                                      rUnitBounds.getMinX() ),
                basegfx::utils::lerp( rShapeBounds.getMinY(),
                                      rShapeBounds.getMaxY(),
                                      rUnitBounds.getMinY() ),
                basegfx::utils::lerp( rShapeBounds.getMinX(),
                                      rShapeBounds.getMaxX(),
                                      rUnitBounds.getMaxX() ),
                basegfx::utils::lerp( rShapeBounds.getMinY(),
                                      rShapeBounds.getMaxY(),
                                      rUnitBounds.getMaxY() ) );
        }

        ::basegfx::B2DRectangle getShapePosSize( const ::basegfx::B2DRectangle&         rOrigBounds,
                                                 const ShapeAttributeLayerSharedPtr&    pAttr )
        {
            // an already empty shape bound need no further
            // treatment. In fact, any changes applied below would
            // actually remove the special empty state, thus, don't
            // change!
            if( !pAttr ||
                rOrigBounds.isEmpty() )
            {
                return rOrigBounds;
            }
            else
            {
                // cannot use maBounds anymore, attributes might have been
                // changed by now.
                // Have to use absolute values here, as negative sizes
                // (aka mirrored shapes) _still_ have the same bounds,
                // only with mirrored content.
                ::basegfx::B2DSize aSize;
                aSize.setWidth( fabs( pAttr->isWidthValid() ?
                                  pAttr->getWidth() :
                                  rOrigBounds.getWidth() ) );
                aSize.setHeight( fabs( pAttr->isHeightValid() ?
                                  pAttr->getHeight() :
                                  rOrigBounds.getHeight() ) );

                ::basegfx::B2DPoint aPos;
                aPos.setX( pAttr->isPosXValid() ?
                           pAttr->getPosX() :
                           rOrigBounds.getCenterX() );
                aPos.setY( pAttr->isPosYValid() ?
                           pAttr->getPosY() :
                           rOrigBounds.getCenterY() );

                // the positional attribute retrieved from the
                // ShapeAttributeLayer actually denotes the _middle_
                // of the shape (do it as the PPTs do...)
                return ::basegfx::B2DRectangle(aPos - 0.5 * basegfx::B2DPoint(aSize),
                                               aPos + 0.5 * basegfx::B2DPoint(aSize));
            }
        }

        RGBColor unoColor2RGBColor( sal_Int32 nColor )
        {
            return RGBColor(
                ::cppcanvas::makeColor(
                    // convert from API color to IntSRGBA color
                    // (0xAARRGGBB -> 0xRRGGBBAA)
                    static_cast< sal_uInt8 >( nColor >> 16U ),
                    static_cast< sal_uInt8 >( nColor >> 8U ),
                    static_cast< sal_uInt8 >( nColor ),
                    static_cast< sal_uInt8 >( nColor >> 24U ) ) );
        }

        sal_Int32 RGBAColor2UnoColor( ::cppcanvas::IntSRGBA aColor )
        {
            return ::cppcanvas::makeColorARGB(
                // convert from IntSRGBA color to API color
                // (0xRRGGBBAA -> 0xAARRGGBB)
                static_cast< sal_uInt8 >(0),
                ::cppcanvas::getRed(aColor),
                ::cppcanvas::getGreen(aColor),
                ::cppcanvas::getBlue(aColor));
        }

        void fillRect( const ::cppcanvas::CanvasSharedPtr& rCanvas,
                       const ::basegfx::B2DRectangle&      rRect,
                       ::cppcanvas::IntSRGBA        aFillColor )
        {
            const ::basegfx::B2DPolygon aPoly(
                ::basegfx::utils::createPolygonFromRect( rRect ));

            ::cppcanvas::PolyPolygonSharedPtr pPolyPoly(
                ::cppcanvas::BaseGfxFactory::createPolyPolygon( rCanvas, aPoly ) );

            if( pPolyPoly )
            {
                pPolyPoly->setRGBAFillColor( aFillColor );
                pPolyPoly->draw();
            }
        }

        void initSlideBackground( const ::cppcanvas::CanvasSharedPtr& rCanvas,
                                  const ::basegfx::B2ISize&           rSize )
        {
            ::cppcanvas::CanvasSharedPtr pCanvas( rCanvas->clone() );

            // set transformation to identity (->device pixel)
            pCanvas->setTransformation( ::basegfx::B2DHomMatrix() );

            // #i42440# Fill the _full_ background in
            // black. Since we had to extend the bitmap by one
            // pixel, and the bitmap is initialized white,
            // depending on the slide content a one pixel wide
            // line will show to the bottom and the right.
            fillRect( pCanvas,
                      ::basegfx::B2DRectangle( 0.0, 0.0,
                                               rSize.getWidth(),
                                               rSize.getHeight() ),
                      0x000000FFU );

            // tdf#148884 in dark mode impress's auto text color assumes it will render against
            // the DOCCOLOR by default, so leaving this as white gives white on white, this
            // looks the simplest approach, propagate dark mode into slideshow mode instead
            // of reformatting to render onto a white slideshow
            svtools::ColorConfig aColorConfig;
            Color aApplicationDocumentColor = aColorConfig.GetColorValue(svtools::DOCCOLOR).nColor;
            cppcanvas::IntSRGBA nCanvasColor = cppcanvas::makeColor(aApplicationDocumentColor.GetRed(),
                                                                    aApplicationDocumentColor.GetGreen(),
                                                                    aApplicationDocumentColor.GetBlue(),
                                                                    0xFF);

            // fill the bounds rectangle in DOCCOLOR (typically white).
            // Subtract one pixel from both width and height, because the slide
            // size is chosen one pixel larger than given by the drawing layer.
            // This is because shapes with line style, that have the size of
            // the slide would otherwise be cut off. OTOH, every other slide
            // background (solid fill, gradient, bitmap) render one pixel less,
            // thus revealing ugly white pixel to the right and the bottom.
            fillRect( pCanvas,
                      ::basegfx::B2DRectangle( 0.0, 0.0,
                                               rSize.getWidth()-1,
                                               rSize.getHeight()-1 ),
                      nCanvasColor );
        }

        ::basegfx::B2DRectangle getAPIShapeBounds( const uno::Reference< drawing::XShape >& xShape )
        {
            uno::Reference< beans::XPropertySet > xPropSet( xShape,
                                                            uno::UNO_QUERY_THROW );
            // read bound rect
            awt::Rectangle aTmpRect;
            if( !(xPropSet->getPropertyValue(u"BoundRect"_ustr) >>= aTmpRect) )
            {
                ENSURE_OR_THROW( false,
                                  "getAPIShapeBounds(): Could not get \"BoundRect\" property from shape" );
            }

            return ::basegfx::B2DRectangle( aTmpRect.X,
                                            aTmpRect.Y,
                                            aTmpRect.X+aTmpRect.Width,
                                            aTmpRect.Y+aTmpRect.Height );
        }

/*
        TODO(F1): When ZOrder someday becomes usable enable this

        double getAPIShapePrio( const uno::Reference< drawing::XShape >& xShape )
        {
            uno::Reference< beans::XPropertySet > xPropSet( xShape,
                                                            uno::UNO_QUERY_THROW );
            // read prio
            sal_Int32 nPrio(0);
            if( !(xPropSet->getPropertyValue(
                      OUString("ZOrder") ) >>= nPrio) )
            {
                ENSURE_OR_THROW( false,
                                  "getAPIShapePrio(): Could not get \"ZOrder\" property from shape" );
            }

            // TODO(F2): Check and adapt the range of possible values here.
            // Maybe we can also take the total number of shapes here
            return nPrio / 65535.0;
        }
*/


        basegfx::B2IVector getSlideSizePixel( const basegfx::B2DVector& rSlideSize,
                                              const UnoViewSharedPtr&   pView )
        {
            ENSURE_OR_THROW(pView, "getSlideSizePixel(): invalid view");

            // determine transformed page bounds
            const basegfx::B2DRange aRect( 0,0,
                                           rSlideSize.getX(),
                                           rSlideSize.getY() );
            basegfx::B2DRange aTmpRect = canvas::tools::calcTransformedRectBounds(
                                                      aRect,
                                                      pView->getTransformation() );

            // #i42440# Returned slide size is one pixel too small, as
            // rendering happens one pixel to the right and below the
            // actual bound rect.
            return basegfx::B2IVector(
                basegfx::fround( aTmpRect.getRange().getX() ) + 1,
                basegfx::fround( aTmpRect.getRange().getY() ) + 1 );
        }

#if defined(DBG_UTIL)
bool isShowingMoreDebugInfo()
{
    static const bool bMoreInfo = getenv("SLIDESHOW_MORE_DEBUG_INFO") != nullptr;
    return bMoreInfo;
}
#endif
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5
C=85 H=94 G=89

¤ Dauer der Verarbeitung: 0.8 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.