xref: /aoo42x/main/slideshow/source/engine/tools.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_slideshow.hxx"
30 
31 #include <canvas/debug.hxx>
32 #include <tools/diagnose_ex.h>
33 #include <canvas/canvastools.hxx>
34 
35 #include <math.h>
36 
37 #include <com/sun/star/beans/NamedValue.hpp>
38 #include <com/sun/star/awt/Rectangle.hpp>
39 #include <com/sun/star/animations/ValuePair.hpp>
40 #include <com/sun/star/drawing/FillStyle.hpp>
41 #include <com/sun/star/drawing/LineStyle.hpp>
42 #include <com/sun/star/awt/FontSlant.hpp>
43 
44 #include <basegfx/polygon/b2dpolygon.hxx>
45 #include <basegfx/polygon/b2dpolygontools.hxx>
46 #include <basegfx/range/b2drange.hxx>
47 #include <basegfx/vector/b2dvector.hxx>
48 #include <basegfx/vector/b2ivector.hxx>
49 #include <basegfx/matrix/b2dhommatrix.hxx>
50 #include <basegfx/numeric/ftools.hxx>
51 #include <basegfx/tools/lerp.hxx>
52 #include <basegfx/matrix/b2dhommatrixtools.hxx>
53 
54 #include <cppcanvas/basegfxfactory.hxx>
55 
56 #include "unoview.hxx"
57 #include "smilfunctionparser.hxx"
58 #include "tools.hxx"
59 
60 #include <limits>
61 
62 
63 using namespace ::com::sun::star;
64 
65 namespace slideshow
66 {
67     namespace internal
68     {
69         namespace
70         {
71             class NamedValueStringComparator
72             {
73             public:
74                 NamedValueStringComparator( const ::rtl::OUString& rSearchString ) :
75                     mrSearchString( rSearchString )
76                 {
77                 }
78 
79                 bool operator()( const beans::NamedValue& rValue )
80                 {
81                     return rValue.Name == mrSearchString;
82                 }
83 
84             private:
85                 const ::rtl::OUString&		mrSearchString;
86             };
87 
88             class NamedValueComparator
89             {
90             public:
91                 NamedValueComparator( const beans::NamedValue& rKey ) :
92                     mrKey( rKey )
93                 {
94                 }
95 
96                 bool operator()( const beans::NamedValue& rValue )
97                 {
98                     return rValue.Name == mrKey.Name && rValue.Value == mrKey.Value;
99                 }
100 
101             private:
102                 const beans::NamedValue&	mrKey;
103             };
104 
105             ::basegfx::B2DHomMatrix getAttributedShapeTransformation( const ::basegfx::B2DRectangle&		rShapeBounds,
106                                                                       const ShapeAttributeLayerSharedPtr&	pAttr )
107             {
108                 ::basegfx::B2DHomMatrix 	aTransform;
109                 const ::basegfx::B2DSize&	rSize( rShapeBounds.getRange() );
110 
111                 const double nShearX( pAttr->isShearXAngleValid() ?
112                                       pAttr->getShearXAngle() :
113                                       0.0 );
114                 const double nShearY( pAttr->isShearYAngleValid() ?
115                                       pAttr->getShearYAngle() :
116                                       0.0 );
117                 const double nRotation( pAttr->isRotationAngleValid() ?
118                                         pAttr->getRotationAngle()*M_PI/180.0 :
119                                         0.0 );
120 
121                 // scale, shear and rotation pivot point is the shape
122                 // center - adapt origin accordingly
123                 aTransform.translate( -0.5, -0.5 );
124 
125                 // ensure valid size (zero size will inevitably lead
126                 // to a singular transformation matrix)
127                 aTransform.scale( ::basegfx::pruneScaleValue(
128                                       rSize.getX() ),
129                                   ::basegfx::pruneScaleValue(
130                                       rSize.getY() ) );
131 
132                 const bool bNeedShearX( !::basegfx::fTools::equalZero(nShearX) );
133                 const bool bNeedShearY( !::basegfx::fTools::equalZero(nShearY) );
134                 const bool bNeedRotation( !::basegfx::fTools::equalZero(nRotation) );
135 
136                 if( bNeedRotation || bNeedShearX || bNeedShearY )
137                 {
138                     if( bNeedShearX )
139                         aTransform.shearX( nShearX );
140 
141                     if( bNeedShearY )
142                         aTransform.shearY( nShearY );
143 
144                     if( bNeedRotation )
145                         aTransform.rotate( nRotation );
146                 }
147 
148                 // move left, top corner back to position of the
149                 // shape. Since we've already translated the
150                 // center of the shape to the origin (the
151                 // translate( -0.5, -0.5 ) above), translate to
152                 // center of final shape position here.
153                 aTransform.translate( rShapeBounds.getCenterX(),
154                                       rShapeBounds.getCenterY() );
155 
156                 return aTransform;
157             }
158         }
159 
160         // Value extraction from Any
161         // =========================
162 
163         /// extract unary double value from Any
164         bool extractValue( double&						o_rValue,
165                            const uno::Any& 				rSourceAny,
166                            const ShapeSharedPtr&		rShape,
167                            const ::basegfx::B2DVector&	rSlideBounds )
168         {
169             // try to extract numeric value (double, or smaller POD, like float or int)
170             if( (rSourceAny >>= o_rValue) )
171             {
172                 // succeeded
173                 return true;
174             }
175 
176             // try to extract string
177             ::rtl::OUString aString;
178             if( !(rSourceAny >>= aString) )
179                 return false; // nothing left to try
180 
181             // parse the string into an ExpressionNode
182             try
183             {
184                 // Parse string into ExpressionNode, eval node at time 0.0
185                 o_rValue = (*SmilFunctionParser::parseSmilValue(
186                                 aString,
187                                 calcRelativeShapeBounds(rSlideBounds,
188                                                         rShape->getBounds()) ))(0.0);
189             }
190             catch( ParseError& )
191             {
192                 return false;
193             }
194 
195             return true;
196         }
197 
198         /// extract enum/constant group value from Any
199         bool extractValue( sal_Int32&						o_rValue,
200                            const uno::Any& 					rSourceAny,
201                            const ShapeSharedPtr&			/*rShape*/,
202                            const ::basegfx::B2DVector&		/*rSlideBounds*/ )
203         {
204             // try to extract numeric value (int, or smaller POD, like byte)
205             if( (rSourceAny >>= o_rValue) )
206             {
207                 // succeeded
208                 return true;
209             }
210 
211             // okay, no plain int. Maybe one of the domain-specific enums?
212             drawing::FillStyle eFillStyle;
213             if( (rSourceAny >>= eFillStyle) )
214             {
215                 o_rValue = sal::static_int_cast<sal_Int16>(eFillStyle);
216 
217                 // succeeded
218                 return true;
219             }
220 
221             drawing::LineStyle eLineStyle;
222             if( (rSourceAny >>= eLineStyle) )
223             {
224                 o_rValue = sal::static_int_cast<sal_Int16>(eLineStyle);
225 
226                 // succeeded
227                 return true;
228             }
229 
230             awt::FontSlant eFontSlant;
231             if( (rSourceAny >>= eFontSlant) )
232             {
233                 o_rValue = sal::static_int_cast<sal_Int16>(eFontSlant);
234 
235                 // succeeded
236                 return true;
237             }
238 
239             // nothing left to try. Failure
240             return false;
241         }
242 
243         /// extract enum/constant group value from Any
244         bool extractValue( sal_Int16&						o_rValue,
245                            const uno::Any& 					rSourceAny,
246                            const ShapeSharedPtr&			rShape,
247                            const ::basegfx::B2DVector&		rSlideBounds )
248         {
249             sal_Int32 aValue;
250             if( !extractValue(aValue,rSourceAny,rShape,rSlideBounds) )
251                 return false;
252 
253             if( std::numeric_limits<sal_Int16>::max() < aValue ||
254                 std::numeric_limits<sal_Int16>::min() > aValue )
255             {
256                 return false;
257             }
258 
259             o_rValue = static_cast<sal_Int16>(aValue);
260 
261             return true;
262         }
263 
264         /// extract color value from Any
265         bool extractValue( RGBColor&					o_rValue,
266                            const uno::Any& 				rSourceAny,
267                            const ShapeSharedPtr&		/*rShape*/,
268                            const ::basegfx::B2DVector&	/*rSlideBounds*/ )
269         {
270             // try to extract numeric value (double, or smaller POD, like float or int)
271             {
272                 double nTmp = 0;
273                 if( (rSourceAny >>= nTmp) )
274                 {
275                     sal_uInt32 aIntColor( static_cast< sal_uInt32 >(nTmp) );
276 
277                     // TODO(F2): Handle color values correctly, here
278                     o_rValue = unoColor2RGBColor( aIntColor );
279 
280                     // succeeded
281                     return true;
282                 }
283             }
284 
285             // try double sequence
286             {
287                 uno::Sequence< double > aTmp;
288                 if( (rSourceAny >>= aTmp) )
289                 {
290                     ENSURE_OR_THROW( aTmp.getLength() == 3,
291                                       "extractValue(): inappropriate length for RGB color value" );
292 
293                     o_rValue = RGBColor( aTmp[0], aTmp[1], aTmp[2] );
294 
295                     // succeeded
296                     return true;
297                 }
298             }
299 
300             // try sal_Int32 sequence
301             {
302                 uno::Sequence< sal_Int32 > aTmp;
303                 if( (rSourceAny >>= aTmp) )
304                 {
305                     ENSURE_OR_THROW( aTmp.getLength() == 3,
306                                       "extractValue(): inappropriate length for RGB color value" );
307 
308                     // truncate to byte
309                     o_rValue = RGBColor( ::cppcanvas::makeColor(
310                                              static_cast<sal_uInt8>(aTmp[0]),
311                                              static_cast<sal_uInt8>(aTmp[1]),
312                                              static_cast<sal_uInt8>(aTmp[2]),
313                                              255 ) );
314 
315                     // succeeded
316                     return true;
317                 }
318             }
319 
320             // try sal_Int8 sequence
321             {
322                 uno::Sequence< sal_Int8 > aTmp;
323                 if( (rSourceAny >>= aTmp) )
324                 {
325                     ENSURE_OR_THROW( aTmp.getLength() == 3,
326                                       "extractValue(): inappropriate length for RGB color value" );
327 
328                     o_rValue = RGBColor( ::cppcanvas::makeColor( aTmp[0], aTmp[1], aTmp[2], 255 ) );
329 
330                     // succeeded
331                     return true;
332                 }
333             }
334 
335             // try to extract string
336             ::rtl::OUString aString;
337             if( !(rSourceAny >>= aString) )
338                 return false; // nothing left to try
339 
340             // TODO(F2): Provide symbolic color values here
341             o_rValue = RGBColor( 0.5, 0.5, 0.5 );
342 
343             return true;
344         }
345 
346         /// extract color value from Any
347         bool extractValue( HSLColor&					o_rValue,
348                            const uno::Any& 				rSourceAny,
349                            const ShapeSharedPtr&		/*rShape*/,
350                            const ::basegfx::B2DVector&	/*rSlideBounds*/ )
351         {
352             // try double sequence
353             {
354                 uno::Sequence< double > aTmp;
355                 if( (rSourceAny >>= aTmp) )
356                 {
357                     ENSURE_OR_THROW( aTmp.getLength() == 3,
358                                       "extractValue(): inappropriate length for HSL color value" );
359 
360                     o_rValue = HSLColor( aTmp[0], aTmp[1], aTmp[2] );
361 
362                     // succeeded
363                     return true;
364                 }
365             }
366 
367             // try sal_Int8 sequence
368             {
369                 uno::Sequence< sal_Int8 > aTmp;
370                 if( (rSourceAny >>= aTmp) )
371                 {
372                     ENSURE_OR_THROW( aTmp.getLength() == 3,
373                                       "extractValue(): inappropriate length for HSL color value" );
374 
375                     o_rValue = HSLColor( aTmp[0]*360.0/255.0, aTmp[1]/255.0, aTmp[2]/255.0 );
376 
377                     // succeeded
378                     return true;
379                 }
380             }
381 
382             return false; // nothing left to try
383         }
384 
385         /// extract plain string from Any
386         bool extractValue( ::rtl::OUString&				o_rValue,
387                            const uno::Any& 				rSourceAny,
388                            const ShapeSharedPtr&		/*rShape*/,
389                            const ::basegfx::B2DVector&	/*rSlideBounds*/ )
390         {
391             // try to extract string
392             if( !(rSourceAny >>= o_rValue) )
393                 return false; // nothing left to try
394 
395             return true;
396         }
397 
398         /// extract bool value from Any
399         bool extractValue( bool&						o_rValue,
400                            const uno::Any& 				rSourceAny,
401                            const ShapeSharedPtr&		/*rShape*/,
402                            const ::basegfx::B2DVector&	/*rSlideBounds*/ )
403         {
404             sal_Bool nTmp = sal_Bool();
405             // try to extract bool value
406             if( (rSourceAny >>= nTmp) )
407             {
408                 o_rValue = nTmp;
409 
410                 // succeeded
411                 return true;
412             }
413 
414             // try to extract string
415             ::rtl::OUString aString;
416             if( !(rSourceAny >>= aString) )
417                 return false; // nothing left to try
418 
419             // we also take the strings "true" and "false",
420             // as well as "on" and "off" here
421             if( aString.equalsIgnoreAsciiCaseAscii("true") ||
422                 aString.equalsIgnoreAsciiCaseAscii("on") )
423             {
424                 o_rValue = true;
425                 return true;
426             }
427             if( aString.equalsIgnoreAsciiCaseAscii("false") ||
428                 aString.equalsIgnoreAsciiCaseAscii("off") )
429             {
430                 o_rValue = false;
431                 return true;
432             }
433 
434             // ultimately failed.
435             return false;
436         }
437 
438         /// extract double 2-tuple from Any
439         bool extractValue( ::basegfx::B2DTuple&			o_rPair,
440                            const uno::Any& 				rSourceAny,
441                            const ShapeSharedPtr&		rShape,
442                            const ::basegfx::B2DVector&	rSlideBounds )
443         {
444             animations::ValuePair aPair;
445 
446             if( !(rSourceAny >>= aPair) )
447                 return false;
448 
449             double nFirst;
450             if( !extractValue( nFirst, aPair.First, rShape, rSlideBounds ) )
451                 return false;
452 
453             double nSecond;
454             if( !extractValue( nSecond, aPair.Second, rShape, rSlideBounds ) )
455                 return false;
456 
457             o_rPair.setX( nFirst );
458             o_rPair.setY( nSecond );
459 
460             return true;
461         }
462 
463         bool findNamedValue( uno::Sequence< beans::NamedValue > const& rSequence,
464                              const beans::NamedValue&				rSearchKey )
465         {
466             const beans::NamedValue* 	pArray = rSequence.getConstArray();
467             const size_t 				nLen( rSequence.getLength() );
468 
469             if( nLen == 0 )
470                 return false;
471 
472             const beans::NamedValue* pFound = ::std::find_if( pArray,
473                                                               pArray + nLen,
474                                                               NamedValueComparator( rSearchKey ) );
475 
476             if( pFound == pArray + nLen )
477                 return false;
478 
479             return true;
480         }
481 
482         bool findNamedValue( beans::NamedValue* 						o_pRet,
483                              const uno::Sequence< beans::NamedValue >& 	rSequence,
484                              const ::rtl::OUString&						rSearchString )
485         {
486             const beans::NamedValue* 	pArray = rSequence.getConstArray();
487             const size_t 				nLen( rSequence.getLength() );
488 
489             if( nLen == 0 )
490                 return false;
491 
492             const beans::NamedValue* pFound = ::std::find_if( pArray,
493                                                               pArray + nLen,
494                                                               NamedValueStringComparator( rSearchString ) );
495             if( pFound == pArray + nLen )
496                 return false;
497 
498             if( o_pRet )
499                 *o_pRet = *pFound;
500 
501             return true;
502         }
503 
504         basegfx::B2DRange calcRelativeShapeBounds( const basegfx::B2DVector& rPageSize,
505                                                    const basegfx::B2DRange&  rShapeBounds )
506         {
507             return basegfx::B2DRange( rShapeBounds.getMinX() / rPageSize.getX(),
508                                       rShapeBounds.getMinY() / rPageSize.getY(),
509                                       rShapeBounds.getMaxX() / rPageSize.getX(),
510                                       rShapeBounds.getMaxY() / rPageSize.getY() );
511 		}
512 
513         // TODO(F2): Currently, the positional attributes DO NOT mirror the XShape properties.
514         // First and foremost, this is because we must operate with the shape boundrect,
515         // not position and size (the conversion between logic rect, snap rect and boundrect
516         // are non-trivial for draw shapes, and I won't duplicate them here). Thus, shapes
517         // rotated on the page will still have 0.0 rotation angle, as the metafile
518         // representation fetched over the API is our default zero case.
519 
520         ::basegfx::B2DHomMatrix getShapeTransformation( const ::basegfx::B2DRectangle&		rShapeBounds,
521                                                         const ShapeAttributeLayerSharedPtr&	pAttr )
522         {
523             if( !pAttr )
524             {
525                 const basegfx::B2DHomMatrix aTransform(basegfx::tools::createScaleTranslateB2DHomMatrix(
526                     rShapeBounds.getWidth(), rShapeBounds.getHeight(),
527                     rShapeBounds.getMinX(), rShapeBounds.getMinY()));
528 
529                 return aTransform;
530             }
531             else
532             {
533                 return getAttributedShapeTransformation( rShapeBounds,
534                                                          pAttr );
535             }
536         }
537 
538         ::basegfx::B2DHomMatrix getSpriteTransformation( const ::basegfx::B2DVector&			rPixelSize,
539                                                          const ::basegfx::B2DVector&			rOrigSize,
540                                                          const ShapeAttributeLayerSharedPtr&	pAttr )
541         {
542             ::basegfx::B2DHomMatrix aTransform;
543 
544             if( pAttr )
545             {
546                 const double nShearX( pAttr->isShearXAngleValid() ?
547                                       pAttr->getShearXAngle() :
548                                       0.0 );
549                 const double nShearY( pAttr->isShearYAngleValid() ?
550                                       pAttr->getShearYAngle() :
551                                       0.0 );
552                 const double nRotation( pAttr->isRotationAngleValid() ?
553                                         pAttr->getRotationAngle()*M_PI/180.0 :
554                                         0.0 );
555 
556                 // scale, shear and rotation pivot point is the
557                 // sprite's pixel center - adapt origin accordingly
558                 aTransform.translate( -0.5*rPixelSize.getX(),
559                                       -0.5*rPixelSize.getY() );
560 
561                 const ::basegfx::B2DSize aSize(
562                     pAttr->isWidthValid() ? pAttr->getWidth() : rOrigSize.getX(),
563                     pAttr->isHeightValid() ? pAttr->getHeight() : rOrigSize.getY() );
564 
565                 // ensure valid size (zero size will inevitably lead
566                 // to a singular transformation matrix).
567                 aTransform.scale( ::basegfx::pruneScaleValue(
568                                       aSize.getX() /
569                                       ::basegfx::pruneScaleValue(
570                                           rOrigSize.getX() ) ),
571                                   ::basegfx::pruneScaleValue(
572                                       aSize.getY() /
573                                       ::basegfx::pruneScaleValue(
574                                           rOrigSize.getY() ) ) );
575 
576                 const bool bNeedShearX( !::basegfx::fTools::equalZero(nShearX) );
577                 const bool bNeedShearY( !::basegfx::fTools::equalZero(nShearY) );
578                 const bool bNeedRotation( !::basegfx::fTools::equalZero(nRotation) );
579 
580                 if( bNeedRotation || bNeedShearX || bNeedShearY )
581                 {
582                     if( bNeedShearX )
583                         aTransform.shearX( nShearX );
584 
585                     if( bNeedShearY )
586                         aTransform.shearY( nShearY );
587 
588                     if( bNeedRotation )
589                         aTransform.rotate( nRotation );
590                 }
591 
592                 // move left, top corner back to original position of
593                 // the sprite (we've translated the center of the
594                 // sprite to the origin above).
595                 aTransform.translate( 0.5*rPixelSize.getX(),
596                                       0.5*rPixelSize.getY() );
597             }
598 
599             // return identity transform for un-attributed
600             // shapes. This renders the sprite as-is, in it's
601             // document-supplied size.
602             return aTransform;
603         }
604 
605         ::basegfx::B2DRectangle getShapeUpdateArea( const ::basegfx::B2DRectangle&		rUnitBounds,
606                                                     const ::basegfx::B2DHomMatrix&		rShapeTransform,
607                                                     const ShapeAttributeLayerSharedPtr&	pAttr )
608         {
609             ::basegfx::B2DHomMatrix aTransform;
610 
611             if( pAttr &&
612                 pAttr->isCharScaleValid() &&
613                 fabs(pAttr->getCharScale()) > 1.0 )
614             {
615                 // enlarge shape bounds. Have to consider the worst
616                 // case here (the text fully fills the shape)
617 
618                 const double nCharScale( pAttr->getCharScale() );
619 
620                 // center of scaling is the middle of the shape
621                 aTransform.translate( -0.5, -0.5 );
622                 aTransform.scale( nCharScale, nCharScale );
623                 aTransform.translate( 0.5, 0.5 );
624             }
625 
626             aTransform *= rShapeTransform;
627 
628             ::basegfx::B2DRectangle aRes;
629 
630             // apply shape transformation to unit rect
631             return ::canvas::tools::calcTransformedRectBounds(
632                 aRes,
633                 rUnitBounds,
634                 aTransform );
635         }
636 
637         ::basegfx::B2DRange getShapeUpdateArea( const ::basegfx::B2DRange&		rUnitBounds,
638                                                     const ::basegfx::B2DRange&		rShapeBounds )
639         {
640             return ::basegfx::B2DRectangle(
641                 basegfx::tools::lerp( rShapeBounds.getMinX(),
642                                       rShapeBounds.getMaxX(),
643                                       rUnitBounds.getMinX() ),
644                 basegfx::tools::lerp( rShapeBounds.getMinY(),
645                                       rShapeBounds.getMaxY(),
646                                       rUnitBounds.getMinY() ),
647                 basegfx::tools::lerp( rShapeBounds.getMinX(),
648                                       rShapeBounds.getMaxX(),
649                                       rUnitBounds.getMaxX() ),
650                 basegfx::tools::lerp( rShapeBounds.getMinY(),
651                                       rShapeBounds.getMaxY(),
652                                       rUnitBounds.getMaxY() ) );
653         }
654 
655         ::basegfx::B2DRectangle getShapePosSize( const ::basegfx::B2DRectangle&			rOrigBounds,
656                                                  const ShapeAttributeLayerSharedPtr&	pAttr )
657         {
658             // an already empty shape bound need no further
659             // treatment. In fact, any changes applied below would
660             // actually remove the special empty state, thus, don't
661             // change!
662             if( !pAttr ||
663                 rOrigBounds.isEmpty() )
664             {
665                 return rOrigBounds;
666             }
667             else
668             {
669                 // cannot use maBounds anymore, attributes might have been
670                 // changed by now.
671                 // Have to use absolute values here, as negative sizes
672                 // (aka mirrored shapes) _still_ have the same bounds,
673                 // only with mirrored content.
674                 ::basegfx::B2DSize aSize;
675                 aSize.setX( fabs( pAttr->isWidthValid() ?
676                                   pAttr->getWidth() :
677                                   rOrigBounds.getWidth() ) );
678                 aSize.setY( fabs( pAttr->isHeightValid() ?
679                                   pAttr->getHeight() :
680                                   rOrigBounds.getHeight() ) );
681 
682                 ::basegfx::B2DPoint aPos;
683                 aPos.setX( pAttr->isPosXValid() ?
684                            pAttr->getPosX() :
685                            rOrigBounds.getCenterX() );
686                 aPos.setY( pAttr->isPosYValid() ?
687                            pAttr->getPosY() :
688                            rOrigBounds.getCenterY() );
689 
690                 // the positional attribute retrieved from the
691                 // ShapeAttributeLayer actually denotes the _middle_
692                 // of the shape (do it as the PPTs do...)
693                 return ::basegfx::B2DRectangle( aPos - 0.5*aSize,
694                                                 aPos + 0.5*aSize );
695             }
696         }
697 
698         RGBColor unoColor2RGBColor( sal_Int32 nColor )
699         {
700             return RGBColor(
701                 ::cppcanvas::makeColor(
702                     // convert from API color to IntSRGBA color
703                     // (0xAARRGGBB -> 0xRRGGBBAA)
704                     static_cast< sal_uInt8 >( nColor >> 16U ),
705                     static_cast< sal_uInt8 >( nColor >> 8U ),
706                     static_cast< sal_uInt8 >( nColor ),
707                     static_cast< sal_uInt8 >( nColor >> 24U ) ) );
708         }
709 
710         sal_Int32 RGBAColor2UnoColor( ::cppcanvas::Color::IntSRGBA aColor )
711         {
712             return ::cppcanvas::makeColorARGB(
713                 // convert from IntSRGBA color to API color
714                 // (0xRRGGBBAA -> 0xAARRGGBB)
715                 static_cast< sal_uInt8 >(0),
716                 ::cppcanvas::getRed(aColor),
717                 ::cppcanvas::getGreen(aColor),
718                 ::cppcanvas::getBlue(aColor));
719         }
720 
721         /*sal_Int32 RGBAColor2UnoColor( ::cppcanvas::Color::IntSRGBA aColor )
722         {
723             return ::cppcanvas::unMakeColor(
724                                                     // convert from IntSRGBA color to API color
725                                                     // (0xRRGGBBAA -> 0xAARRGGBB)
726                                                     static_cast< sal_uInt8 >(0),
727                                                     ::cppcanvas::getRed(aColor),
728                                                     ::cppcanvas::getGreen(aColor),
729                                                     ::cppcanvas::getBlue(aColor));
730         }*/
731 
732         sal_Int8 unSignedToSigned(sal_Int8 nInt)
733         {
734             if(nInt < 0 ){
735                 sal_Int8 nInt2 = nInt >> 1U;
736                 return nInt2;
737             }else{
738                 return nInt;
739             }
740         }
741 
742         void fillRect( const ::cppcanvas::CanvasSharedPtr& rCanvas,
743                        const ::basegfx::B2DRectangle&	   rRect,
744                        ::cppcanvas::Color::IntSRGBA        aFillColor )
745         {
746             const ::basegfx::B2DPolygon aPoly(
747                 ::basegfx::tools::createPolygonFromRect( rRect ));
748 
749             ::cppcanvas::PolyPolygonSharedPtr pPolyPoly(
750                 ::cppcanvas::BaseGfxFactory::getInstance().createPolyPolygon( rCanvas,
751                                                                               aPoly ) );
752 
753             if( pPolyPoly )
754             {
755                 pPolyPoly->setRGBAFillColor( aFillColor );
756                 pPolyPoly->draw();
757             }
758         }
759 
760         void initSlideBackground( const ::cppcanvas::CanvasSharedPtr& rCanvas,
761                                   const ::basegfx::B2ISize&			  rSize )
762         {
763             ::cppcanvas::CanvasSharedPtr pCanvas( rCanvas->clone() );
764 
765             // set transformation to identitiy (->device pixel)
766             pCanvas->setTransformation( ::basegfx::B2DHomMatrix() );
767 
768             // #i42440# Fill the _full_ background in
769             // black. Since we had to extend the bitmap by one
770             // pixel, and the bitmap is initialized white,
771             // depending on the slide content a one pixel wide
772             // line will show to the bottom and the right.
773             fillRect( pCanvas,
774                       ::basegfx::B2DRectangle( 0.0, 0.0,
775                                                rSize.getX(),
776                                                rSize.getY() ),
777                       0x000000FFU );
778 
779             // fill the bounds rectangle in white. Subtract one pixel
780             // from both width and height, because the slide size is
781             // chosen one pixel larger than given by the drawing
782             // layer. This is because shapes with line style, that
783             // have the size of the slide would otherwise be cut
784             // off. OTOH, every other slide background (solid fill,
785             // gradient, bitmap) render one pixel less, thus revealing
786             // ugly white pixel to the right and the bottom.
787             fillRect( pCanvas,
788                       ::basegfx::B2DRectangle( 0.0, 0.0,
789                                                rSize.getX()-1,
790                                                rSize.getY()-1 ),
791                       0xFFFFFFFFU );
792         }
793 
794         ::basegfx::B2DRectangle getAPIShapeBounds( const uno::Reference< drawing::XShape >& xShape )
795         {
796             uno::Reference< beans::XPropertySet > xPropSet( xShape,
797                                                             uno::UNO_QUERY_THROW );
798             // read bound rect
799             awt::Rectangle aTmpRect;
800             if( !(xPropSet->getPropertyValue(
801                       ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("BoundRect") ) ) >>= aTmpRect) )
802             {
803                 ENSURE_OR_THROW( false,
804                                   "getAPIShapeBounds(): Could not get \"BoundRect\" property from shape" );
805             }
806 
807             return ::basegfx::B2DRectangle( aTmpRect.X,
808                                             aTmpRect.Y,
809                                             aTmpRect.X+aTmpRect.Width,
810                                             aTmpRect.Y+aTmpRect.Height );
811         }
812 
813         double getAPIShapePrio( const uno::Reference< drawing::XShape >& xShape )
814         {
815             uno::Reference< beans::XPropertySet > xPropSet( xShape,
816                                                             uno::UNO_QUERY_THROW );
817             // read prio
818             sal_Int32 nPrio(0);
819             if( !(xPropSet->getPropertyValue(
820                       ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ZOrder") ) ) >>= nPrio) )
821             {
822                 ENSURE_OR_THROW( false,
823                                   "getAPIShapePrio(): Could not get \"ZOrder\" property from shape" );
824             }
825 
826             // TODO(F2): Check and adapt the range of possible values here.
827             // Maybe we can also take the total number of shapes here
828             return nPrio / 65535.0;
829         }
830 
831         basegfx::B2IVector getSlideSizePixel( const basegfx::B2DVector& rSlideSize,
832                                               const UnoViewSharedPtr&   pView )
833         {
834             ENSURE_OR_THROW(pView, "getSlideSizePixel(): invalid view");
835 
836             // determine transformed page bounds
837             const basegfx::B2DRange aRect( 0,0,
838                                            rSlideSize.getX(),
839                                            rSlideSize.getY() );
840             basegfx::B2DRange aTmpRect;
841             canvas::tools::calcTransformedRectBounds( aTmpRect,
842                                                       aRect,
843                                                       pView->getTransformation() );
844 
845             // #i42440# Returned slide size is one pixel too small, as
846             // rendering happens one pixel to the right and below the
847             // actual bound rect.
848             return basegfx::B2IVector(
849                 basegfx::fround( aTmpRect.getRange().getX() ) + 1,
850                 basegfx::fround( aTmpRect.getRange().getY() ) + 1 );
851         }
852     }
853 }
854