1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: tools.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_slideshow.hxx"
34 #include <canvas/debug.hxx>
35 #include <tools/diagnose_ex.h>
36 #include <canvas/canvastools.hxx>
40 #include <com/sun/star/beans/NamedValue.hpp>
41 #include <com/sun/star/awt/Rectangle.hpp>
42 #include <com/sun/star/animations/ValuePair.hpp>
43 #include <com/sun/star/drawing/FillStyle.hpp>
44 #include <com/sun/star/drawing/LineStyle.hpp>
45 #include <com/sun/star/awt/FontSlant.hpp>
47 #include <basegfx/polygon/b2dpolygon.hxx>
48 #include <basegfx/polygon/b2dpolygontools.hxx>
49 #include <basegfx/range/b2drange.hxx>
50 #include <basegfx/vector/b2dvector.hxx>
51 #include <basegfx/vector/b2ivector.hxx>
52 #include <basegfx/matrix/b2dhommatrix.hxx>
53 #include <basegfx/numeric/ftools.hxx>
55 #include <cppcanvas/basegfxfactory.hxx>
58 #include "unoview.hxx"
59 #include "smilfunctionparser.hxx"
65 using namespace ::com::sun::star
;
73 class NamedValueStringComparator
76 NamedValueStringComparator( const ::rtl::OUString
& rSearchString
) :
77 mrSearchString( rSearchString
)
81 bool operator()( const beans::NamedValue
& rValue
)
83 return rValue
.Name
== mrSearchString
;
87 const ::rtl::OUString
& mrSearchString
;
90 class NamedValueComparator
93 NamedValueComparator( const beans::NamedValue
& rKey
) :
98 bool operator()( const beans::NamedValue
& rValue
)
100 return rValue
.Name
== mrKey
.Name
&& rValue
.Value
== mrKey
.Value
;
104 const beans::NamedValue
& mrKey
;
107 ::basegfx::B2DHomMatrix
getAttributedShapeTransformation( const ::basegfx::B2DRectangle
& rShapeBounds
,
108 const ShapeAttributeLayerSharedPtr
& pAttr
)
110 ::basegfx::B2DHomMatrix aTransform
;
111 const ::basegfx::B2DSize
& rSize( rShapeBounds
.getRange() );
113 const double nShearX( pAttr
->isShearXAngleValid() ?
114 pAttr
->getShearXAngle() :
116 const double nShearY( pAttr
->isShearYAngleValid() ?
117 pAttr
->getShearYAngle() :
119 const double nRotation( pAttr
->isRotationAngleValid() ?
120 pAttr
->getRotationAngle()*M_PI
/180.0 :
123 // scale, shear and rotation pivot point is the shape
124 // center - adapt origin accordingly
125 aTransform
.translate( -0.5, -0.5 );
127 // ensure valid size (zero size will inevitably lead
128 // to a singular transformation matrix)
129 aTransform
.scale( ::basegfx::pruneScaleValue(
131 ::basegfx::pruneScaleValue(
134 const bool bNeedShearX( !::basegfx::fTools::equalZero(nShearX
) );
135 const bool bNeedShearY( !::basegfx::fTools::equalZero(nShearY
) );
136 const bool bNeedRotation( !::basegfx::fTools::equalZero(nRotation
) );
138 if( bNeedRotation
|| bNeedShearX
|| bNeedShearY
)
141 aTransform
.shearX( nShearX
);
144 aTransform
.shearY( nShearY
);
147 aTransform
.rotate( nRotation
);
150 // move left, top corner back to position of the
151 // shape. Since we've already translated the
152 // center of the shape to the origin (the
153 // translate( -0.5, -0.5 ) above), translate to
154 // center of final shape position here.
155 aTransform
.translate( rShapeBounds
.getCenterX(),
156 rShapeBounds
.getCenterY() );
162 // Value extraction from Any
163 // =========================
165 /// extract unary double value from Any
166 bool extractValue( double& o_rValue
,
167 const uno::Any
& rSourceAny
,
168 const ShapeSharedPtr
& rShape
,
169 const ::basegfx::B2DVector
& rSlideBounds
)
171 // try to extract numeric value (double, or smaller POD, like float or int)
172 if( (rSourceAny
>>= o_rValue
) )
178 // try to extract string
179 ::rtl::OUString aString
;
180 if( !(rSourceAny
>>= aString
) )
181 return false; // nothing left to try
183 // parse the string into an ExpressionNode
186 // Parse string into ExpressionNode, eval node at time 0.0
187 o_rValue
= (*SmilFunctionParser::parseSmilValue(
189 calcRelativeShapeBounds(rSlideBounds
,
190 rShape
->getBounds()) ))(0.0);
200 /// extract enum/constant group value from Any
201 bool extractValue( sal_Int32
& o_rValue
,
202 const uno::Any
& rSourceAny
,
203 const ShapeSharedPtr
& /*rShape*/,
204 const ::basegfx::B2DVector
& /*rSlideBounds*/ )
206 // try to extract numeric value (int, or smaller POD, like byte)
207 if( (rSourceAny
>>= o_rValue
) )
213 // okay, no plain int. Maybe one of the domain-specific enums?
214 drawing::FillStyle eFillStyle
;
215 if( (rSourceAny
>>= eFillStyle
) )
217 o_rValue
= sal::static_int_cast
<sal_Int16
>(eFillStyle
);
223 drawing::LineStyle eLineStyle
;
224 if( (rSourceAny
>>= eLineStyle
) )
226 o_rValue
= sal::static_int_cast
<sal_Int16
>(eLineStyle
);
232 awt::FontSlant eFontSlant
;
233 if( (rSourceAny
>>= eFontSlant
) )
235 o_rValue
= sal::static_int_cast
<sal_Int16
>(eFontSlant
);
241 // nothing left to try. Failure
245 /// extract enum/constant group value from Any
246 bool extractValue( sal_Int16
& o_rValue
,
247 const uno::Any
& rSourceAny
,
248 const ShapeSharedPtr
& rShape
,
249 const ::basegfx::B2DVector
& rSlideBounds
)
252 if( !extractValue(aValue
,rSourceAny
,rShape
,rSlideBounds
) )
255 if( std::numeric_limits
<sal_Int16
>::max() < aValue
||
256 std::numeric_limits
<sal_Int16
>::min() > aValue
)
261 o_rValue
= static_cast<sal_Int16
>(aValue
);
266 /// extract color value from Any
267 bool extractValue( RGBColor
& o_rValue
,
268 const uno::Any
& rSourceAny
,
269 const ShapeSharedPtr
& /*rShape*/,
270 const ::basegfx::B2DVector
& /*rSlideBounds*/ )
272 // try to extract numeric value (double, or smaller POD, like float or int)
275 if( (rSourceAny
>>= nTmp
) )
277 sal_uInt32
aIntColor( static_cast< sal_uInt32
>(nTmp
) );
279 // TODO(F2): Handle color values correctly, here
280 o_rValue
= unoColor2RGBColor( aIntColor
);
287 // try double sequence
289 uno::Sequence
< double > aTmp
;
290 if( (rSourceAny
>>= aTmp
) )
292 ENSURE_OR_THROW( aTmp
.getLength() == 3,
293 "extractValue(): inappropriate length for RGB color value" );
295 o_rValue
= RGBColor( aTmp
[0], aTmp
[1], aTmp
[2] );
302 // try sal_Int32 sequence
304 uno::Sequence
< sal_Int32
> aTmp
;
305 if( (rSourceAny
>>= aTmp
) )
307 ENSURE_OR_THROW( aTmp
.getLength() == 3,
308 "extractValue(): inappropriate length for RGB color value" );
311 o_rValue
= RGBColor( ::cppcanvas::makeColor(
312 static_cast<sal_uInt8
>(aTmp
[0]),
313 static_cast<sal_uInt8
>(aTmp
[1]),
314 static_cast<sal_uInt8
>(aTmp
[2]),
322 // try sal_Int8 sequence
324 uno::Sequence
< sal_Int8
> aTmp
;
325 if( (rSourceAny
>>= aTmp
) )
327 ENSURE_OR_THROW( aTmp
.getLength() == 3,
328 "extractValue(): inappropriate length for RGB color value" );
330 o_rValue
= RGBColor( ::cppcanvas::makeColor( aTmp
[0], aTmp
[1], aTmp
[2], 255 ) );
337 // try to extract string
338 ::rtl::OUString aString
;
339 if( !(rSourceAny
>>= aString
) )
340 return false; // nothing left to try
342 // TODO(F2): Provide symbolic color values here
343 o_rValue
= RGBColor( 0.5, 0.5, 0.5 );
348 /// extract color value from Any
349 bool extractValue( HSLColor
& o_rValue
,
350 const uno::Any
& rSourceAny
,
351 const ShapeSharedPtr
& /*rShape*/,
352 const ::basegfx::B2DVector
& /*rSlideBounds*/ )
354 // try double sequence
356 uno::Sequence
< double > aTmp
;
357 if( (rSourceAny
>>= aTmp
) )
359 ENSURE_OR_THROW( aTmp
.getLength() == 3,
360 "extractValue(): inappropriate length for HSL color value" );
362 o_rValue
= HSLColor( aTmp
[0], aTmp
[1], aTmp
[2] );
369 // try sal_Int8 sequence
371 uno::Sequence
< sal_Int8
> aTmp
;
372 if( (rSourceAny
>>= aTmp
) )
374 ENSURE_OR_THROW( aTmp
.getLength() == 3,
375 "extractValue(): inappropriate length for HSL color value" );
377 o_rValue
= HSLColor( aTmp
[0]*360.0/255.0, aTmp
[1]/255.0, aTmp
[2]/255.0 );
384 return false; // nothing left to try
387 /// extract plain string from Any
388 bool extractValue( ::rtl::OUString
& o_rValue
,
389 const uno::Any
& rSourceAny
,
390 const ShapeSharedPtr
& /*rShape*/,
391 const ::basegfx::B2DVector
& /*rSlideBounds*/ )
393 // try to extract string
394 if( !(rSourceAny
>>= o_rValue
) )
395 return false; // nothing left to try
400 /// extract bool value from Any
401 bool extractValue( bool& o_rValue
,
402 const uno::Any
& rSourceAny
,
403 const ShapeSharedPtr
& /*rShape*/,
404 const ::basegfx::B2DVector
& /*rSlideBounds*/ )
406 sal_Bool nTmp
= sal_Bool();
407 // try to extract bool value
408 if( (rSourceAny
>>= nTmp
) )
416 // try to extract string
417 ::rtl::OUString aString
;
418 if( !(rSourceAny
>>= aString
) )
419 return false; // nothing left to try
421 // we also take the strings "true" and "false",
422 // as well as "on" and "off" here
423 if( aString
.equalsIgnoreAsciiCaseAscii("true") ||
424 aString
.equalsIgnoreAsciiCaseAscii("on") )
429 if( aString
.equalsIgnoreAsciiCaseAscii("false") ||
430 aString
.equalsIgnoreAsciiCaseAscii("off") )
436 // ultimately failed.
440 /// extract double 2-tuple from Any
441 bool extractValue( ::basegfx::B2DTuple
& o_rPair
,
442 const uno::Any
& rSourceAny
,
443 const ShapeSharedPtr
& rShape
,
444 const ::basegfx::B2DVector
& rSlideBounds
)
446 animations::ValuePair aPair
;
448 if( !(rSourceAny
>>= aPair
) )
452 if( !extractValue( nFirst
, aPair
.First
, rShape
, rSlideBounds
) )
456 if( !extractValue( nSecond
, aPair
.Second
, rShape
, rSlideBounds
) )
459 o_rPair
.setX( nFirst
);
460 o_rPair
.setY( nSecond
);
465 bool findNamedValue( uno::Sequence
< beans::NamedValue
> const& rSequence
,
466 const beans::NamedValue
& rSearchKey
)
468 const beans::NamedValue
* pArray
= rSequence
.getConstArray();
469 const size_t nLen( rSequence
.getLength() );
474 const beans::NamedValue
* pFound
= ::std::find_if( pArray
,
476 NamedValueComparator( rSearchKey
) );
478 if( pFound
== pArray
+ nLen
)
484 bool findNamedValue( beans::NamedValue
* o_pRet
,
485 const uno::Sequence
< beans::NamedValue
>& rSequence
,
486 const ::rtl::OUString
& rSearchString
)
488 const beans::NamedValue
* pArray
= rSequence
.getConstArray();
489 const size_t nLen( rSequence
.getLength() );
494 const beans::NamedValue
* pFound
= ::std::find_if( pArray
,
496 NamedValueStringComparator( rSearchString
) );
497 if( pFound
== pArray
+ nLen
)
506 basegfx::B2DRange
calcRelativeShapeBounds( const basegfx::B2DVector
& rPageSize
,
507 const basegfx::B2DRange
& rShapeBounds
)
509 return basegfx::B2DRange( rShapeBounds
.getMinX() / rPageSize
.getX(),
510 rShapeBounds
.getMinY() / rPageSize
.getY(),
511 rShapeBounds
.getMaxX() / rPageSize
.getX(),
512 rShapeBounds
.getMaxY() / rPageSize
.getY() );
515 // TODO(F2): Currently, the positional attributes DO NOT mirror the XShape properties.
516 // First and foremost, this is because we must operate with the shape boundrect,
517 // not position and size (the conversion between logic rect, snap rect and boundrect
518 // are non-trivial for draw shapes, and I won't duplicate them here). Thus, shapes
519 // rotated on the page will still have 0.0 rotation angle, as the metafile
520 // representation fetched over the API is our default zero case.
522 ::basegfx::B2DHomMatrix
getShapeTransformation( const ::basegfx::B2DRectangle
& rShapeBounds
,
523 const ShapeAttributeLayerSharedPtr
& pAttr
)
527 ::basegfx::B2DHomMatrix aTransform
;
529 aTransform
.scale( rShapeBounds
.getWidth(), rShapeBounds
.getHeight() );
530 aTransform
.translate( rShapeBounds
.getMinX(), rShapeBounds
.getMinY() );
536 return getAttributedShapeTransformation( rShapeBounds
,
541 ::basegfx::B2DHomMatrix
getSpriteTransformation( const ::basegfx::B2DVector
& rPixelSize
,
542 const ::basegfx::B2DVector
& rOrigSize
,
543 const ShapeAttributeLayerSharedPtr
& pAttr
)
545 ::basegfx::B2DHomMatrix aTransform
;
549 const double nShearX( pAttr
->isShearXAngleValid() ?
550 pAttr
->getShearXAngle() :
552 const double nShearY( pAttr
->isShearYAngleValid() ?
553 pAttr
->getShearYAngle() :
555 const double nRotation( pAttr
->isRotationAngleValid() ?
556 pAttr
->getRotationAngle()*M_PI
/180.0 :
559 // scale, shear and rotation pivot point is the
560 // sprite's pixel center - adapt origin accordingly
561 aTransform
.translate( -0.5*rPixelSize
.getX(),
562 -0.5*rPixelSize
.getY() );
564 const ::basegfx::B2DSize
aSize(
565 pAttr
->isWidthValid() ? pAttr
->getWidth() : rOrigSize
.getX(),
566 pAttr
->isHeightValid() ? pAttr
->getHeight() : rOrigSize
.getY() );
568 // ensure valid size (zero size will inevitably lead
569 // to a singular transformation matrix).
570 aTransform
.scale( ::basegfx::pruneScaleValue(
572 ::basegfx::pruneScaleValue(
573 rOrigSize
.getX() ) ),
574 ::basegfx::pruneScaleValue(
576 ::basegfx::pruneScaleValue(
577 rOrigSize
.getY() ) ) );
579 const bool bNeedShearX( !::basegfx::fTools::equalZero(nShearX
) );
580 const bool bNeedShearY( !::basegfx::fTools::equalZero(nShearY
) );
581 const bool bNeedRotation( !::basegfx::fTools::equalZero(nRotation
) );
583 if( bNeedRotation
|| bNeedShearX
|| bNeedShearY
)
586 aTransform
.shearX( nShearX
);
589 aTransform
.shearY( nShearY
);
592 aTransform
.rotate( nRotation
);
595 // move left, top corner back to original position of
596 // the sprite (we've translated the center of the
597 // sprite to the origin above).
598 aTransform
.translate( 0.5*rPixelSize
.getX(),
599 0.5*rPixelSize
.getY() );
602 // return identity transform for un-attributed
603 // shapes. This renders the sprite as-is, in it's
604 // document-supplied size.
608 ::basegfx::B2DRectangle
getShapeUpdateArea( const ::basegfx::B2DRectangle
& rUnitBounds
,
609 const ::basegfx::B2DHomMatrix
& rShapeTransform
,
610 const ShapeAttributeLayerSharedPtr
& pAttr
)
612 ::basegfx::B2DHomMatrix aTransform
;
615 pAttr
->isCharScaleValid() &&
616 fabs(pAttr
->getCharScale()) > 1.0 )
618 // enlarge shape bounds. Have to consider the worst
619 // case here (the text fully fills the shape)
621 const double nCharScale( pAttr
->getCharScale() );
623 // center of scaling is the middle of the shape
624 aTransform
.translate( -0.5, -0.5 );
625 aTransform
.scale( nCharScale
, nCharScale
);
626 aTransform
.translate( 0.5, 0.5 );
629 aTransform
*= rShapeTransform
;
631 ::basegfx::B2DRectangle aRes
;
633 // apply shape transformation to unit rect
634 return ::canvas::tools::calcTransformedRectBounds(
640 ::basegfx::B2DRange
getShapeUpdateArea( const ::basegfx::B2DRange
& rUnitBounds
,
641 const ::basegfx::B2DRange
& rShapeBounds
)
643 return ::basegfx::B2DRectangle(
644 lerp( rShapeBounds
.getMinX(),
645 rShapeBounds
.getMaxX(),
646 rUnitBounds
.getMinX() ),
647 lerp( rShapeBounds
.getMinY(),
648 rShapeBounds
.getMaxY(),
649 rUnitBounds
.getMinY() ),
650 lerp( rShapeBounds
.getMinX(),
651 rShapeBounds
.getMaxX(),
652 rUnitBounds
.getMaxX() ),
653 lerp( rShapeBounds
.getMinY(),
654 rShapeBounds
.getMaxY(),
655 rUnitBounds
.getMaxY() ) );
658 ::basegfx::B2DRectangle
getShapePosSize( const ::basegfx::B2DRectangle
& rOrigBounds
,
659 const ShapeAttributeLayerSharedPtr
& pAttr
)
661 // an already empty shape bound need no further
662 // treatment. In fact, any changes applied below would
663 // actually remove the special empty state, thus, don't
666 rOrigBounds
.isEmpty() )
672 // cannot use maBounds anymore, attributes might have been
674 // Have to use absolute values here, as negative sizes
675 // (aka mirrored shapes) _still_ have the same bounds,
676 // only with mirrored content.
677 ::basegfx::B2DSize aSize
;
678 aSize
.setX( fabs( pAttr
->isWidthValid() ?
680 rOrigBounds
.getWidth() ) );
681 aSize
.setY( fabs( pAttr
->isHeightValid() ?
683 rOrigBounds
.getHeight() ) );
685 ::basegfx::B2DPoint aPos
;
686 aPos
.setX( pAttr
->isPosXValid() ?
688 rOrigBounds
.getCenterX() );
689 aPos
.setY( pAttr
->isPosYValid() ?
691 rOrigBounds
.getCenterY() );
693 // the positional attribute retrieved from the
694 // ShapeAttributeLayer actually denotes the _middle_
695 // of the shape (do it as the PPTs do...)
696 return ::basegfx::B2DRectangle( aPos
- 0.5*aSize
,
701 RGBColor
unoColor2RGBColor( sal_Int32 nColor
)
704 ::cppcanvas::makeColor(
705 // convert from API color to IntSRGBA color
706 // (0xAARRGGBB -> 0xRRGGBBAA)
707 static_cast< sal_uInt8
>( nColor
>> 16U ),
708 static_cast< sal_uInt8
>( nColor
>> 8U ),
709 static_cast< sal_uInt8
>( nColor
),
710 static_cast< sal_uInt8
>( nColor
>> 24U ) ) );
713 void fillRect( const ::cppcanvas::CanvasSharedPtr
& rCanvas
,
714 const ::basegfx::B2DRectangle
& rRect
,
715 ::cppcanvas::Color::IntSRGBA aFillColor
)
717 const ::basegfx::B2DPolygon
aPoly(
718 ::basegfx::tools::createPolygonFromRect( rRect
));
720 ::cppcanvas::PolyPolygonSharedPtr
pPolyPoly(
721 ::cppcanvas::BaseGfxFactory::getInstance().createPolyPolygon( rCanvas
,
726 pPolyPoly
->setRGBAFillColor( aFillColor
);
731 void initSlideBackground( const ::cppcanvas::CanvasSharedPtr
& rCanvas
,
732 const ::basegfx::B2ISize
& rSize
)
734 ::cppcanvas::CanvasSharedPtr
pCanvas( rCanvas
->clone() );
736 // set transformation to identitiy (->device pixel)
737 pCanvas
->setTransformation( ::basegfx::B2DHomMatrix() );
739 // #i42440# Fill the _full_ background in
740 // black. Since we had to extend the bitmap by one
741 // pixel, and the bitmap is initialized white,
742 // depending on the slide content a one pixel wide
743 // line will show to the bottom and the right.
745 ::basegfx::B2DRectangle( 0.0, 0.0,
750 // fill the bounds rectangle in white. Subtract one pixel
751 // from both width and height, because the slide size is
752 // chosen one pixel larger than given by the drawing
753 // layer. This is because shapes with line style, that
754 // have the size of the slide would otherwise be cut
755 // off. OTOH, every other slide background (solid fill,
756 // gradient, bitmap) render one pixel less, thus revealing
757 // ugly white pixel to the right and the bottom.
759 ::basegfx::B2DRectangle( 0.0, 0.0,
765 ::basegfx::B2DRectangle
getAPIShapeBounds( const uno::Reference
< drawing::XShape
>& xShape
)
767 uno::Reference
< beans::XPropertySet
> xPropSet( xShape
,
768 uno::UNO_QUERY_THROW
);
770 awt::Rectangle aTmpRect
;
771 if( !(xPropSet
->getPropertyValue(
772 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("BoundRect") ) ) >>= aTmpRect
) )
774 ENSURE_OR_THROW( false,
775 "getAPIShapeBounds(): Could not get \"BoundRect\" property from shape" );
778 return ::basegfx::B2DRectangle( aTmpRect
.X
,
780 aTmpRect
.X
+aTmpRect
.Width
,
781 aTmpRect
.Y
+aTmpRect
.Height
);
784 double getAPIShapePrio( const uno::Reference
< drawing::XShape
>& xShape
)
786 uno::Reference
< beans::XPropertySet
> xPropSet( xShape
,
787 uno::UNO_QUERY_THROW
);
790 if( !(xPropSet
->getPropertyValue(
791 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ZOrder") ) ) >>= nPrio
) )
793 ENSURE_OR_THROW( false,
794 "getAPIShapePrio(): Could not get \"ZOrder\" property from shape" );
797 // TODO(F2): Check and adapt the range of possible values here.
798 // Maybe we can also take the total number of shapes here
799 return nPrio
/ 65535.0;
802 basegfx::B2IVector
getSlideSizePixel( const basegfx::B2DVector
& rSlideSize
,
803 const UnoViewSharedPtr
& pView
)
805 ENSURE_OR_THROW(pView
, "getSlideSizePixel(): invalid view");
807 // determine transformed page bounds
808 const basegfx::B2DRange
aRect( 0,0,
811 basegfx::B2DRange aTmpRect
;
812 canvas::tools::calcTransformedRectBounds( aTmpRect
,
814 pView
->getTransformation() );
816 // #i42440# Returned slide size is one pixel too small, as
817 // rendering happens one pixel to the right and below the
818 // actual bound rect.
819 return basegfx::B2IVector(
820 basegfx::fround( aTmpRect
.getRange().getX() ) + 1,
821 basegfx::fround( aTmpRect
.getRange().getY() ) + 1 );