1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_slideshow.hxx"
26 
27 // must be first
28 #include <canvas/debug.hxx>
29 #include <tools/diagnose_ex.h>
30 #include <canvas/verbosetrace.hxx>
31 
32 #include <rtl/logfile.hxx>
33 #include <osl/diagnose.hxx>
34 #include <com/sun/star/awt/Rectangle.hpp>
35 #include <com/sun/star/beans/XPropertySet.hpp>
36 #include <com/sun/star/awt/FontWeight.hpp>
37 #include <comphelper/anytostring.hxx>
38 #include <cppuhelper/exc_hlp.hxx>
39 
40 #include <vcl/metaact.hxx>
41 #include <vcl/gdimtf.hxx>
42 #include <vcl/wrkwin.hxx>
43 
44 #include <basegfx/numeric/ftools.hxx>
45 #include <basegfx/range/rangeexpander.hxx>
46 
47 #include <rtl/math.hxx>
48 
49 #include <com/sun/star/drawing/TextAnimationKind.hpp>
50 
51 #include <vcl/svapp.hxx>
52 #include <vcl/window.hxx>
53 #include <tools/stream.hxx>
54 #include <com/sun/star/frame/XModel.hpp>
55 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
56 #include <com/sun/star/datatransfer/XTransferable.hpp>
57 
58 #include <comphelper/scopeguard.hxx>
59 #include <canvas/canvastools.hxx>
60 
61 #include <cmath> // for trigonometry and fabs
62 #include <algorithm>
63 #include <functional>
64 #include <limits>
65 
66 #include "drawshapesubsetting.hxx"
67 #include "drawshape.hxx"
68 #include "eventqueue.hxx"
69 #include "wakeupevent.hxx"
70 #include "subsettableshapemanager.hxx"
71 #include "intrinsicanimationactivity.hxx"
72 #include "slideshowexceptions.hxx"
73 #include "tools.hxx"
74 #include "gdimtftools.hxx"
75 #include "drawinglayeranimation.hxx"
76 
77 #include <boost/bind.hpp>
78 #include <math.h>
79 
80 using namespace ::com::sun::star;
81 
82 
83 namespace slideshow
84 {
85     namespace internal
86     {
87         //#i75867# poor quality of ole's alternative view with 3D scenes and zoomfactors besides 100%
88         //metafiles are resolution dependent when bitmaps are contained with is the case for 3D scenes for example
89         //in addition a chart has resolution dependent content as it might skip points that are not visible for a given resolution (this is done for performance reasons)
90         bool local_getMetafileForChart( const uno::Reference< lang::XComponent >& 	  xSource,
91                   const uno::Reference< drawing::XDrawPage >&     xContainingPage,
92                   GDIMetaFile&                                    rMtf )
93         {
94             //get the chart model
95             uno::Reference< beans::XPropertySet > xPropSet( xSource, uno::UNO_QUERY );
96             uno::Reference< frame::XModel > xChartModel;
97             getPropertyValue( xChartModel, xPropSet, OUSTR("Model"));
98             uno::Reference< lang::XMultiServiceFactory > xFact( xChartModel, uno::UNO_QUERY );
99             OSL_ENSURE( xFact.is(), "Chart cannot be painted pretty!\n" );
100             if(!xFact.is())
101                 return false;
102 
103             //get the chart view
104             uno::Reference< datatransfer::XTransferable > xChartViewTransferable(
105                 xFact->createInstance( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.chart2.ChartView" ) ) ), uno::UNO_QUERY );
106             uno::Reference< beans::XPropertySet > xChartViewProp( xChartViewTransferable, uno::UNO_QUERY );
107             OSL_ENSURE( xChartViewProp.is(), "Chart cannot be painted pretty!\n" );
108             if( !xChartViewProp.is() )
109                 return false;
110 
111             //estimate zoom and resolution (this is only a workaround, correct would be to know and use the exact zoom and resoltion during slideshow display)
112             sal_Int32 nScaleXNumerator = 100;//zoom factor -> exact values are important for the quality of the created bitmap especially for 3D charts
113             sal_Int32 nScaleYNumerator = 100;
114             sal_Int32 nScaleXDenominator = 100;
115             sal_Int32 nScaleYDenominator = 100;
116             awt::Size aPixelPerChart( 1000, 1000 );//when data points happen to be on the same pixel as their predecessor no shape is created to safe performance
117 
118             Window* pActiveTopWindow( Application::GetActiveTopWindow() );
119             WorkWindow* pWorkWindow( dynamic_cast<WorkWindow*>(pActiveTopWindow));
120             if( pWorkWindow && pWorkWindow->IsPresentationMode() )
121             {
122                 Size aPixScreenSize( pActiveTopWindow->GetOutputSizePixel() );
123                 aPixelPerChart = awt::Size( aPixScreenSize.getWidth(), aPixScreenSize.getHeight() );//this is still to much (but costs only seldom performance), correct would be pixel per chart object
124 
125                 uno::Reference< beans::XPropertySet > xPageProp( xContainingPage, uno::UNO_QUERY );
126                 sal_Int32 nLogicPageWidth=1;
127                 sal_Int32 nLogicPageHeight=1;
128                 if( getPropertyValue( nLogicPageWidth, xPageProp, OUSTR("Width")) &&
129                     getPropertyValue( nLogicPageHeight, xPageProp, OUSTR("Height")) )
130                 {
131                     Size aLogicScreenSize( pActiveTopWindow->PixelToLogic( aPixScreenSize, MAP_100TH_MM ) );
132                     nScaleXNumerator = aLogicScreenSize.getWidth();
133                     nScaleYNumerator = aLogicScreenSize.getHeight();
134                     nScaleXDenominator = nLogicPageWidth;
135                     nScaleYDenominator = nLogicPageHeight;
136                 }
137             }
138             else
139             {
140                 long nMaxPixWidth = 0;
141                 long nMaxPixHeight = 0;
142                 unsigned int nScreenCount( Application::GetScreenCount() );
143                 for( unsigned int nScreen=0; nScreen<nScreenCount; nScreen++ )
144                 {
145                     Rectangle aCurScreenRect( Application::GetScreenPosSizePixel( nScreen ) );
146                     if( aCurScreenRect.GetWidth() > nMaxPixWidth )
147                         nMaxPixWidth = aCurScreenRect.GetWidth();
148                     if( aCurScreenRect.GetHeight() > nMaxPixHeight )
149                         nMaxPixHeight = aCurScreenRect.GetHeight();
150                 }
151                 if(nMaxPixWidth>1 && nMaxPixHeight>1)
152                     aPixelPerChart = awt::Size( nMaxPixWidth, nMaxPixHeight );//this is still to much (but costs only seldom performance), correct would be pixel per chart object
153             }
154 
155             try
156             {
157                 uno::Sequence< beans::PropertyValue > aZoomFactors(4);
158                 aZoomFactors[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ScaleXNumerator") );
159                 aZoomFactors[0].Value = uno::makeAny( nScaleXNumerator );
160                 aZoomFactors[1].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ScaleXDenominator") );
161                 aZoomFactors[1].Value = uno::makeAny( nScaleXDenominator );
162                 aZoomFactors[2].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ScaleYNumerator") );
163                 aZoomFactors[2].Value = uno::makeAny( nScaleYNumerator );
164                 aZoomFactors[3].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ScaleYDenominator") );
165                 aZoomFactors[3].Value = uno::makeAny( nScaleYDenominator );
166 
167                 xChartViewProp->setPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ZoomFactors") ), uno::makeAny( aZoomFactors ));
168                 xChartViewProp->setPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Resolution") ), uno::makeAny( aPixelPerChart ));
169             }
170             catch (uno::Exception &)
171             {
172                 OSL_ENSURE( false, rtl::OUStringToOString(
173                                 comphelper::anyToString(
174                                     cppu::getCaughtException() ),
175                                 RTL_TEXTENCODING_UTF8 ).getStr() );
176             }
177 
178             //get a metafile from the prepared chart view
179             datatransfer::DataFlavor aDataFlavor(
180                     ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"") ),
181                     ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "GDIMetaFile" ) ),
182                     ::getCppuType( (const uno::Sequence< sal_Int8 >*) 0 ) );
183             uno::Any aData( xChartViewTransferable->getTransferData( aDataFlavor ) );
184             uno::Sequence< sal_Int8 > aSeq;
185             if( aData >>= aSeq )
186             {
187 		        ::std::auto_ptr< SvMemoryStream > pSrcStm( new SvMemoryStream( (char*) aSeq.getConstArray(), aSeq.getLength(), STREAM_WRITE | STREAM_TRUNC ) );
188 	            *(pSrcStm.get() ) >> rMtf;
189                 return true;
190             }
191             return false;
192         }
193 
194         //same as getMetafile with an exception for charts
195         //for charts a metafile with a higher resolution is created, because charts have resolution dependent content
196         bool local_getMetaFile_WithSpecialChartHandling( const uno::Reference< lang::XComponent >& 	  xSource,
197                   const uno::Reference< drawing::XDrawPage >&     xContainingPage,
198                   GDIMetaFile&                                    rMtf,
199                   int                                             mtfLoadFlags,
200                   const uno::Reference< uno::XComponentContext >& rxContext )
201         {
202             uno::Reference<beans::XPropertySet> xProp( xSource, uno::UNO_QUERY );
203             rtl::OUString sCLSID;
204             getPropertyValue( sCLSID, xProp, OUSTR("CLSID"));
205             if( sCLSID.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("12DCAE26-281F-416F-a234-c3086127382e")) && local_getMetafileForChart( xSource, xContainingPage, rMtf ) )
206                 return true;
207             return getMetaFile( xSource, xContainingPage, rMtf, mtfLoadFlags, rxContext );
208         }
209 
210 
211         //////////////////////////////////////////////////////////////////////
212         //
213         // Private methods
214         //
215         //////////////////////////////////////////////////////////////////////
216 
217         GDIMetaFileSharedPtr DrawShape::forceScrollTextMetaFile()
218         {
219             if ((mnCurrMtfLoadFlags & MTF_LOAD_SCROLL_TEXT_MTF) != MTF_LOAD_SCROLL_TEXT_MTF)
220             {
221                 // reload with added flags:
222                 mpCurrMtf.reset( new GDIMetaFile );
223                 mnCurrMtfLoadFlags |= MTF_LOAD_SCROLL_TEXT_MTF;
224                 local_getMetaFile_WithSpecialChartHandling(
225                     uno::Reference<lang::XComponent>(mxShape, uno::UNO_QUERY),
226                     mxPage, *mpCurrMtf, mnCurrMtfLoadFlags,
227                     mxComponentContext );
228 
229                 // TODO(F1): Currently, the scroll metafile will
230                 // never contain any verbose text comments. Thus,
231                 // can only display the full mtf content, no
232                 // subsets.
233                 maSubsetting.reset( mpCurrMtf );
234 
235                 // adapt maBounds. the requested scroll text metafile
236                 // will typically have dimension different from the
237                 // actual shape
238                 ::basegfx::B2DRectangle aScrollRect, aPaintRect;
239                 ENSURE_OR_THROW( getRectanglesFromScrollMtf( aScrollRect,
240                                                               aPaintRect,
241                                                               mpCurrMtf ),
242                                   "DrawShape::forceScrollTextMetaFile(): Could "
243                                   "not extract scroll anim rectangles from mtf" );
244 
245                 // take the larger one of the two rectangles (that
246                 // should be the bound rect of the retrieved
247                 // metafile)
248                 if( aScrollRect.isInside( aPaintRect ) )
249                     maBounds = aScrollRect;
250                 else
251                     maBounds = aPaintRect;
252             }
253             return mpCurrMtf;
254         }
255 
256         void DrawShape::updateStateIds() const
257         {
258             // Update the states, we've just redrawn or created a new
259             // attribute layer.
260             if( mpAttributeLayer )
261             {
262                 mnAttributeTransformationState = mpAttributeLayer->getTransformationState();
263                 mnAttributeClipState = mpAttributeLayer->getClipState();
264                 mnAttributeAlphaState = mpAttributeLayer->getAlphaState();
265                 mnAttributePositionState = mpAttributeLayer->getPositionState();
266                 mnAttributeContentState = mpAttributeLayer->getContentState();
267                 mnAttributeVisibilityState = mpAttributeLayer->getVisibilityState();
268             }
269         }
270 
271         void DrawShape::ensureVerboseMtfComments() const
272         {
273             // TODO(F1): Text effects don't currently work for drawing
274             // layer animations.
275 
276             // only touch mpCurrMtf, if we're not a DrawingLayer
277             // animation.
278             if( (mnCurrMtfLoadFlags & MTF_LOAD_VERBOSE_COMMENTS) == 0 &&
279                 maAnimationFrames.empty() )
280             {
281                 ENSURE_OR_THROW( !maSubsetting.hasSubsetShapes(),
282                                   "DrawShape::ensureVerboseMtfComments(): reloading the metafile "
283                                   "with active child subsets will wreak havoc on the view!" );
284                 ENSURE_OR_THROW( maSubsetting.getSubsetNode().isEmpty(),
285                                   "DrawShape::ensureVerboseMtfComments(): reloading the metafile "
286                                   "for an ALREADY SUBSETTED shape is not possible!" );
287 
288                 // re-fetch metafile with comments
289                 // note that, in case of shapes without text, the new
290                 // metafile might still not provide any useful
291                 // subsetting information!
292                 mpCurrMtf.reset( new GDIMetaFile );
293                 mnCurrMtfLoadFlags |= MTF_LOAD_VERBOSE_COMMENTS;
294                 local_getMetaFile_WithSpecialChartHandling(
295                     uno::Reference<lang::XComponent>(mxShape, uno::UNO_QUERY),
296                     mxPage, *mpCurrMtf, mnCurrMtfLoadFlags,
297                     mxComponentContext );
298 
299                 maSubsetting.reset( maSubsetting.getSubsetNode(),
300                                     mpCurrMtf );
301             }
302         }
303 
304         ViewShape::RenderArgs DrawShape::getViewRenderArgs() const
305         {
306             return ViewShape::RenderArgs(
307                 maBounds,
308                 getUpdateArea(),
309                 getBounds(),
310                 getActualUnitShapeBounds(),
311                 mpAttributeLayer,
312                 maSubsetting.getActiveSubsets(),
313                 mnPriority);
314         }
315 
316         bool DrawShape::implRender( int nUpdateFlags ) const
317         {
318             RTL_LOGFILE_CONTEXT( aLog, "::presentation::internal::DrawShape::implRender()" );
319             RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::presentation::internal::DrawShape: 0x%X", this );
320 
321             // will perform the update now, clear update-enforcing
322             // flags
323             mbForceUpdate = false;
324             mbAttributeLayerRevoked = false;
325 
326             ENSURE_OR_RETURN_FALSE( !maViewShapes.empty(),
327                                "DrawShape::implRender(): render called on DrawShape without views" );
328 
329             if( maBounds.isEmpty() )
330             {
331                 // zero-sized shapes are effectively invisible,
332                 // thus, we save us the rendering...
333                 return true;
334             }
335 
336             // redraw all view shapes, by calling their update() method
337             if( ::std::count_if( maViewShapes.begin(),
338                                  maViewShapes.end(),
339                                  ::boost::bind<bool>(
340                                      ::boost::mem_fn( &ViewShape::update ), // though _theoretically_,
341                                      										// bind should eat this even
342                                      										// with _1 being a shared_ptr,
343                                      										// it does _not_ for MSVC without
344                                      										// the extra mem_fn. WTF.
345                                      _1,
346                                      ::boost::cref( mpCurrMtf ),
347                                      ::boost::cref(
348                                          getViewRenderArgs() ),
349                                      nUpdateFlags,
350                                      isVisible() ) )
351                 != static_cast<ViewShapeVector::difference_type>(maViewShapes.size()) )
352             {
353                 // at least one of the ViewShape::update() calls did return
354                 // false - update failed on at least one ViewLayer
355                 return false;
356             }
357 
358             // successfully redrawn - update state IDs to detect next changes
359             updateStateIds();
360 
361             return true;
362         }
363 
364         int DrawShape::getUpdateFlags() const
365         {
366             // default: update nothing, unless ShapeAttributeStack
367             // tells us below, or if the attribute layer was revoked
368             int nUpdateFlags(ViewShape::NONE);
369 
370             // possibly the whole shape content changed
371             if( mbAttributeLayerRevoked )
372                 nUpdateFlags = ViewShape::CONTENT;
373 
374 
375             // determine what has to be updated
376             // --------------------------------
377 
378             // do we have an attribute layer?
379             if( mpAttributeLayer )
380             {
381                 // Prevent nUpdateFlags to be modified when the shape is not
382                 // visible, except when it just was hidden.
383                 if (mpAttributeLayer->getVisibility()
384                     || mpAttributeLayer->getVisibilityState() != mnAttributeVisibilityState )
385                 {
386                     if (mpAttributeLayer->getVisibilityState() != mnAttributeVisibilityState )
387                     {
388                         // Change of the visibility state is mapped to
389                         // content change because when the visibility
390                         // changes then usually a sprite is shown or hidden
391                         // and the background under has to be painted once.
392                         nUpdateFlags |= ViewShape::CONTENT;
393                     }
394 
395                     // TODO(P1): This can be done without conditional branching.
396                     // See HAKMEM.
397                     if( mpAttributeLayer->getPositionState() != mnAttributePositionState )
398                     {
399                         nUpdateFlags |= ViewShape::POSITION;
400                     }
401                     if( mpAttributeLayer->getAlphaState() != mnAttributeAlphaState )
402                     {
403                         nUpdateFlags |= ViewShape::ALPHA;
404                     }
405                     if( mpAttributeLayer->getClipState() != mnAttributeClipState )
406                     {
407                         nUpdateFlags |= ViewShape::CLIP;
408                     }
409                     if( mpAttributeLayer->getTransformationState() != mnAttributeTransformationState )
410                     {
411                         nUpdateFlags |= ViewShape::TRANSFORMATION;
412                     }
413                     if( mpAttributeLayer->getContentState() != mnAttributeContentState )
414                     {
415                         nUpdateFlags |= ViewShape::CONTENT;
416                     }
417                 }
418             }
419 
420             return nUpdateFlags;
421         }
422 
423         ::basegfx::B2DRectangle DrawShape::getActualUnitShapeBounds() const
424         {
425             ENSURE_OR_THROW( !maViewShapes.empty(),
426                               "DrawShape::getActualUnitShapeBounds(): called on DrawShape without views" );
427 
428             const VectorOfDocTreeNodes& rSubsets(
429                 maSubsetting.getActiveSubsets() );
430 
431             const ::basegfx::B2DRectangle aDefaultBounds( 0.0,0.0,1.0,1.0 );
432 
433             // perform the cheapest check first
434             if( rSubsets.empty() )
435             {
436                 // if subset contains the whole shape, no need to call
437                 // the somewhat expensive bound calculation, since as
438                 // long as the subset is empty, this branch will be
439                 // taken.
440                 return aDefaultBounds;
441             }
442             else
443             {
444                 OSL_ENSURE( rSubsets.size() != 1 ||
445                             !rSubsets.front().isEmpty(),
446                             "DrawShape::getActualUnitShapeBounds() expects a "
447                             "_non-empty_ subset vector for a subsetted shape!" );
448 
449                 // are the cached bounds still valid?
450                 if( !maCurrentShapeUnitBounds )
451                 {
452                     // no, (re)generate them
453                     // =====================
454 
455                     // setup cached values to defaults (might fail to
456                     // retrieve true bounds below)
457                     maCurrentShapeUnitBounds.reset( aDefaultBounds );
458 
459                     // TODO(P2): the subset of the master shape (that from
460                     // which the subsets are subtracted) changes
461                     // relatively often (every time a subset shape is
462                     // added or removed). Maybe we should exclude it here,
463                     // always assuming full bounds?
464 
465                     ::cppcanvas::CanvasSharedPtr pDestinationCanvas(
466                         maViewShapes.front()->getViewLayer()->getCanvas() );
467 
468                     // TODO(Q2): Although this _is_ currently
469                     // view-agnostic, it might not stay like
470                     // that. Maybe this method should again be moved
471                     // to the ViewShape
472                     ::cppcanvas::RendererSharedPtr pRenderer(
473                         maViewShapes.front()->getRenderer(
474                             pDestinationCanvas, mpCurrMtf, mpAttributeLayer ) );
475 
476                     // If we cannot not prefetch, be defensive and assume
477                     // full shape size
478                     if( pRenderer )
479                     {
480                         // temporarily, switch total transformation to identity
481                         // (need the bounds in the [0,1]x[0,1] unit coordinate
482                         // system.
483                         ::basegfx::B2DHomMatrix 	 aEmptyTransformation;
484 
485                         ::basegfx::B2DHomMatrix 	 aOldTransform( pDestinationCanvas->getTransformation() );
486                         pDestinationCanvas->setTransformation( aEmptyTransformation );
487                         pRenderer->setTransformation( aEmptyTransformation );
488 
489                         // restore old transformation when leaving the scope
490                         const ::comphelper::ScopeGuard aGuard(
491                             boost::bind( &::cppcanvas::Canvas::setTransformation,
492                                          pDestinationCanvas, aOldTransform ) );
493 
494 
495                         // retrieve bounds for subset of whole metafile
496                         // --------------------------------------------
497 
498                         ::basegfx::B2DRange aTotalBounds;
499 
500                         // cannot use ::boost::bind, ::basegfx::B2DRange::expand()
501                         // is overloaded.
502                         VectorOfDocTreeNodes::const_iterator 		aCurr( rSubsets.begin() );
503                         const VectorOfDocTreeNodes::const_iterator	aEnd( rSubsets.end() );
504                         while( aCurr != aEnd )
505                         {
506                             aTotalBounds.expand( pRenderer->getSubsetArea(
507                                                      aCurr->getStartIndex(),
508                                                      aCurr->getEndIndex() )  );
509                             ++aCurr;
510                         }
511 
512                         OSL_ENSURE( aTotalBounds.getMinX() >= -0.1 &&
513                                     aTotalBounds.getMinY() >= -0.1 &&
514                                     aTotalBounds.getMaxX() <= 1.1 &&
515                                     aTotalBounds.getMaxY() <= 1.1,
516                                     "DrawShape::getActualUnitShapeBounds(): bounds noticeably larger than original shape - clipping!" );
517 
518                         // really make sure no shape appears larger than its
519                         // original bounds (there _are_ some pathologic cases,
520                         // especially when imported from PPT, that have
521                         // e.g. obscenely large polygon bounds)
522                         aTotalBounds.intersect(
523                             ::basegfx::B2DRange( 0.0, 0.0,
524                                                  1.0, 1.0 ));
525 
526                         maCurrentShapeUnitBounds.reset( aTotalBounds );
527                     }
528                 }
529 
530                 return *maCurrentShapeUnitBounds;
531             }
532         }
533 
534         DrawShape::DrawShape( const uno::Reference< drawing::XShape >& 		xShape,
535                               const uno::Reference< drawing::XDrawPage >&	xContainingPage,
536                               double										nPrio,
537                               bool											bForeignSource,
538                               const SlideShowContext&                       rContext ) :
539             mxShape( xShape ),
540             mxPage( xContainingPage ),
541             maAnimationFrames(), // empty, we don't have no intrinsic animation
542             mnCurrFrame(0),
543             mpCurrMtf(),
544             mnCurrMtfLoadFlags( bForeignSource
545                                 ? MTF_LOAD_FOREIGN_SOURCE : MTF_LOAD_NONE ),
546             maCurrentShapeUnitBounds(),
547             mnPriority( nPrio ), // TODO(F1): When ZOrder someday becomes usable: make this ( getAPIShapePrio( xShape ) ),
548             maBounds( getAPIShapeBounds( xShape ) ),
549             mpAttributeLayer(),
550             mpIntrinsicAnimationActivity(),
551             mnAttributeTransformationState(0),
552             mnAttributeClipState(0),
553             mnAttributeAlphaState(0),
554             mnAttributePositionState(0),
555             mnAttributeContentState(0),
556             mnAttributeVisibilityState(0),
557             maViewShapes(),
558             mxComponentContext( rContext.mxComponentContext ),
559             maHyperlinkIndices(),
560             maHyperlinkRegions(),
561             maSubsetting(),
562             mnIsAnimatedCount(0),
563             mnAnimationLoopCount(0),
564             meCycleMode(CYCLE_LOOP),
565             mbIsVisible( true ),
566             mbForceUpdate( false ),
567             mbAttributeLayerRevoked( false ),
568             mbDrawingLayerAnim( false )
569         {
570             ENSURE_OR_THROW( mxShape.is(), "DrawShape::DrawShape(): Invalid XShape" );
571             ENSURE_OR_THROW( mxPage.is(), "DrawShape::DrawShape(): Invalid containing page" );
572 
573             // check for drawing layer animations:
574             drawing::TextAnimationKind eKind = drawing::TextAnimationKind_NONE;
575             uno::Reference<beans::XPropertySet> xPropSet( mxShape,
576                                                           uno::UNO_QUERY );
577             if( xPropSet.is() )
578                 getPropertyValue( eKind, xPropSet,
579                                   OUSTR("TextAnimationKind") );
580             mbDrawingLayerAnim = (eKind != drawing::TextAnimationKind_NONE);
581 
582             // must NOT be called from within initializer list, uses
583             // state from mnCurrMtfLoadFlags!
584             mpCurrMtf.reset( new GDIMetaFile );
585             local_getMetaFile_WithSpecialChartHandling(
586                 uno::Reference<lang::XComponent>(xShape, uno::UNO_QUERY),
587                 xContainingPage, *mpCurrMtf, mnCurrMtfLoadFlags,
588                 mxComponentContext );
589             ENSURE_OR_THROW( mpCurrMtf,
590                               "DrawShape::DrawShape(): Invalid metafile" );
591             maSubsetting.reset( mpCurrMtf );
592 
593             prepareHyperlinkIndices();
594         }
595 
596         DrawShape::DrawShape( const uno::Reference< drawing::XShape >& 		xShape,
597                               const uno::Reference< drawing::XDrawPage >&	xContainingPage,
598                               double										nPrio,
599                               const Graphic&								rGraphic,
600                               const SlideShowContext&                       rContext ) :
601             mxShape( xShape ),
602             mxPage( xContainingPage ),
603             maAnimationFrames(),
604             mnCurrFrame(0),
605             mpCurrMtf(),
606             mnCurrMtfLoadFlags( MTF_LOAD_NONE ),
607             maCurrentShapeUnitBounds(),
608             mnPriority( nPrio ), // TODO(F1): When ZOrder someday becomes usable: make this ( getAPIShapePrio( xShape ) ),
609             maBounds( getAPIShapeBounds( xShape ) ),
610             mpAttributeLayer(),
611             mpIntrinsicAnimationActivity(),
612             mnAttributeTransformationState(0),
613             mnAttributeClipState(0),
614             mnAttributeAlphaState(0),
615             mnAttributePositionState(0),
616             mnAttributeContentState(0),
617             mnAttributeVisibilityState(0),
618             maViewShapes(),
619             mxComponentContext( rContext.mxComponentContext ),
620             maHyperlinkIndices(),
621             maHyperlinkRegions(),
622             maSubsetting(),
623             mnIsAnimatedCount(0),
624             mnAnimationLoopCount(0),
625             meCycleMode(CYCLE_LOOP),
626             mbIsVisible( true ),
627             mbForceUpdate( false ),
628             mbAttributeLayerRevoked( false ),
629             mbDrawingLayerAnim( false )
630         {
631             ENSURE_OR_THROW( rGraphic.IsAnimated(),
632                               "DrawShape::DrawShape(): Graphic is no animation" );
633 
634             getAnimationFromGraphic( maAnimationFrames,
635                                      mnAnimationLoopCount,
636                                      meCycleMode,
637                                      rGraphic );
638 
639             ENSURE_OR_THROW( !maAnimationFrames.empty() &&
640                               maAnimationFrames.front().mpMtf,
641                               "DrawShape::DrawShape(): " );
642             mpCurrMtf = maAnimationFrames.front().mpMtf;
643 
644             ENSURE_OR_THROW( mxShape.is(), "DrawShape::DrawShape(): Invalid XShape" );
645             ENSURE_OR_THROW( mxPage.is(), "DrawShape::DrawShape(): Invalid containing page" );
646             ENSURE_OR_THROW( mpCurrMtf, "DrawShape::DrawShape(): Invalid metafile" );
647         }
648 
649         DrawShape::DrawShape( const DrawShape& 		rSrc,
650                               const DocTreeNode& 	rTreeNode,
651                               double				nPrio ) :
652             mxShape( rSrc.mxShape ),
653             mxPage( rSrc.mxPage ),
654             maAnimationFrames(), // don't copy animations for subsets,
655                                  // only the current frame!
656             mnCurrFrame(0),
657             mpCurrMtf( rSrc.mpCurrMtf ),
658             mnCurrMtfLoadFlags( rSrc.mnCurrMtfLoadFlags ),
659             maCurrentShapeUnitBounds(),
660             mnPriority( nPrio ),
661             maBounds( rSrc.maBounds ),
662             mpAttributeLayer(),
663             mpIntrinsicAnimationActivity(),
664             mnAttributeTransformationState(0),
665             mnAttributeClipState(0),
666             mnAttributeAlphaState(0),
667             mnAttributePositionState(0),
668             mnAttributeContentState(0),
669             mnAttributeVisibilityState(0),
670             maViewShapes(),
671             mxComponentContext( rSrc.mxComponentContext ),
672             maHyperlinkIndices(),
673             maHyperlinkRegions(),
674             maSubsetting( rTreeNode, mpCurrMtf ),
675             mnIsAnimatedCount(0),
676             mnAnimationLoopCount(0),
677             meCycleMode(CYCLE_LOOP),
678             mbIsVisible( rSrc.mbIsVisible ),
679             mbForceUpdate( false ),
680             mbAttributeLayerRevoked( false ),
681             mbDrawingLayerAnim( false )
682         {
683             ENSURE_OR_THROW( mxShape.is(), "DrawShape::DrawShape(): Invalid XShape" );
684             ENSURE_OR_THROW( mpCurrMtf, "DrawShape::DrawShape(): Invalid metafile" );
685 
686             // xxx todo: currently not implemented for subsetted shapes;
687             //           would mean modifying set of hyperlink regions when
688             //           subsetting text portions. N.B.: there's already an
689             //           issue for this #i72828#
690         }
691 
692         //////////////////////////////////////////////////////////////////////
693         //
694         // Public methods
695         //
696         //////////////////////////////////////////////////////////////////////
697 
698         DrawShapeSharedPtr DrawShape::create(
699             const uno::Reference< drawing::XShape >& 	xShape,
700             const uno::Reference< drawing::XDrawPage >&	xContainingPage,
701             double										nPrio,
702             bool										bForeignSource,
703             const SlideShowContext&                     rContext )
704         {
705             DrawShapeSharedPtr pShape( new DrawShape(xShape,
706                                                      xContainingPage,
707                                                      nPrio,
708                                                      bForeignSource,
709                                                      rContext) );
710 
711             if( pShape->hasIntrinsicAnimation() )
712             {
713                 OSL_ASSERT( pShape->maAnimationFrames.empty() );
714                 if( pShape->getNumberOfTreeNodes(
715                         DocTreeNode::NODETYPE_LOGICAL_PARAGRAPH) > 0 )
716                 {
717                     pShape->mpIntrinsicAnimationActivity =
718                         createDrawingLayerAnimActivity(
719                             rContext,
720                             pShape);
721                 }
722             }
723 
724             if( pShape->hasHyperlinks() )
725                 rContext.mpSubsettableShapeManager->addHyperlinkArea( pShape );
726 
727             return pShape;
728         }
729 
730         DrawShapeSharedPtr DrawShape::create(
731             const uno::Reference< drawing::XShape >& 	xShape,
732             const uno::Reference< drawing::XDrawPage >&	xContainingPage,
733             double										nPrio,
734             const Graphic&								rGraphic,
735             const SlideShowContext&                     rContext )
736         {
737             DrawShapeSharedPtr pShape( new DrawShape(xShape,
738                                                      xContainingPage,
739                                                      nPrio,
740                                                      rGraphic,
741                                                      rContext) );
742 
743             if( pShape->hasIntrinsicAnimation() )
744             {
745                 OSL_ASSERT( !pShape->maAnimationFrames.empty() );
746 
747                 std::vector<double> aTimeout;
748                 std::transform(
749                     pShape->maAnimationFrames.begin(),
750                     pShape->maAnimationFrames.end(),
751                     std::back_insert_iterator< std::vector<double> >( aTimeout ),
752                     boost::mem_fn(&MtfAnimationFrame::getDuration) );
753 
754                 WakeupEventSharedPtr pWakeupEvent(
755                     new WakeupEvent( rContext.mrEventQueue.getTimer(),
756                                      rContext.mrActivitiesQueue ) );
757 
758                 ActivitySharedPtr pActivity =
759                     createIntrinsicAnimationActivity(
760                         rContext,
761                         pShape,
762                         pWakeupEvent,
763                         aTimeout,
764                         pShape->mnAnimationLoopCount,
765                         pShape->meCycleMode);
766 
767                 pWakeupEvent->setActivity( pActivity );
768                 pShape->mpIntrinsicAnimationActivity = pActivity;
769             }
770 
771             OSL_ENSURE( !pShape->hasHyperlinks(),
772                         "DrawShape::create(): graphic-only shapes must not have hyperlinks!" );
773 
774             return pShape;
775         }
776 
777         DrawShape::~DrawShape()
778         {
779             try
780             {
781                 // dispose intrinsic animation activity, else, it will
782                 // linger forever
783                 ActivitySharedPtr pActivity( mpIntrinsicAnimationActivity.lock() );
784                 if( pActivity )
785                     pActivity->dispose();
786             }
787             catch (uno::Exception &)
788             {
789                 OSL_ENSURE( false, rtl::OUStringToOString(
790                                 comphelper::anyToString(
791                                     cppu::getCaughtException() ),
792                                 RTL_TEXTENCODING_UTF8 ).getStr() );
793             }
794         }
795 
796         uno::Reference< drawing::XShape > DrawShape::getXShape() const
797         {
798             return mxShape;
799         }
800 
801         void DrawShape::addViewLayer( const ViewLayerSharedPtr& rNewLayer,
802                                       bool						bRedrawLayer )
803         {
804             ViewShapeVector::iterator aEnd( maViewShapes.end() );
805 
806             // already added?
807             if( ::std::find_if( maViewShapes.begin(),
808                                 aEnd,
809                                 ::boost::bind<bool>(
810                                     ::std::equal_to< ViewLayerSharedPtr >(),
811                                     ::boost::bind( &ViewShape::getViewLayer,
812                                                    _1 ),
813                                     ::boost::cref( rNewLayer ) ) ) != aEnd )
814             {
815                 // yes, nothing to do
816                 return;
817             }
818 
819             ViewShapeSharedPtr pNewShape( new ViewShape( rNewLayer ) );
820 
821             maViewShapes.push_back( pNewShape );
822 
823             // pass on animation state
824             if( mnIsAnimatedCount )
825             {
826                 for( int i=0; i<mnIsAnimatedCount; ++i )
827                     pNewShape->enterAnimationMode();
828             }
829 
830             // render the Shape on the newly added ViewLayer
831             if( bRedrawLayer )
832             {
833                 pNewShape->update( mpCurrMtf,
834                                    getViewRenderArgs(),
835                                    ViewShape::FORCE,
836                                    isVisible() );
837             }
838         }
839 
840         bool DrawShape::removeViewLayer( const ViewLayerSharedPtr& rLayer )
841         {
842             const ViewShapeVector::iterator aEnd( maViewShapes.end() );
843 
844             OSL_ENSURE( ::std::count_if(maViewShapes.begin(),
845                                         aEnd,
846                                         ::boost::bind<bool>(
847                                             ::std::equal_to< ViewLayerSharedPtr >(),
848                                             ::boost::bind( &ViewShape::getViewLayer,
849                                                            _1 ),
850                                             ::boost::cref( rLayer ) ) ) < 2,
851                         "DrawShape::removeViewLayer(): Duplicate ViewLayer entries!" );
852 
853             ViewShapeVector::iterator aIter;
854 
855             if( (aIter=::std::remove_if( maViewShapes.begin(),
856                                          aEnd,
857                                          ::boost::bind<bool>(
858                                              ::std::equal_to< ViewLayerSharedPtr >(),
859                                              ::boost::bind( &ViewShape::getViewLayer,
860                                                             _1 ),
861                                              ::boost::cref( rLayer ) ) )) == aEnd )
862             {
863                 // view layer seemingly was not added, failed
864                 return false;
865             }
866 
867             // actually erase from container
868             maViewShapes.erase( aIter, aEnd );
869 
870             return true;
871         }
872 
873         bool DrawShape::clearAllViewLayers()
874         {
875             maViewShapes.clear();
876             return true;
877         }
878 
879         bool DrawShape::update() const
880         {
881             if( mbForceUpdate )
882             {
883                 return render();
884             }
885             else
886             {
887                 return implRender( getUpdateFlags() );
888             }
889         }
890 
891         bool DrawShape::render() const
892         {
893             // force redraw. Have to also pass on the update flags,
894             // because e.g. content update (regeneration of the
895             // metafile renderer) is normally not performed. A simple
896             // ViewShape::FORCE would only paint the metafile in its
897             // old state.
898             return implRender( ViewShape::FORCE | getUpdateFlags() );
899         }
900 
901         bool DrawShape::isContentChanged() const
902         {
903             return mbForceUpdate ?
904                 true :
905                 getUpdateFlags() != ViewShape::NONE;
906         }
907 
908 
909         ::basegfx::B2DRectangle DrawShape::getBounds() const
910         {
911             // little optimization: for non-modified shapes, we don't
912             // create an ShapeAttributeStack, and therefore also don't
913             // have to check it.
914             return getShapePosSize( maBounds,
915                                     mpAttributeLayer );
916         }
917 
918         ::basegfx::B2DRectangle DrawShape::getDomBounds() const
919         {
920             return maBounds;
921         }
922 
923         namespace
924         {
925             /** Functor expanding AA border for each passed ViewShape
926 
927             	Could not use ::boost::bind here, since
928             	B2DRange::expand is overloaded (which yields one or
929             	the other template type deduction ambiguous)
930              */
931             class Expander
932             {
933             public:
934                 Expander( ::basegfx::B2DSize& rBounds ) :
935                     mrBounds( rBounds )
936                 {
937                 }
938 
939                 void operator()( const ViewShapeSharedPtr& rShape ) const
940                 {
941                     const ::basegfx::B2DSize& rShapeBorder( rShape->getAntialiasingBorder() );
942 
943                     mrBounds.setX(
944                         ::std::max(
945                             rShapeBorder.getX(),
946                             mrBounds.getX() ) );
947                     mrBounds.setY(
948                         ::std::max(
949                             rShapeBorder.getY(),
950                             mrBounds.getY() ) );
951                 }
952 
953             private:
954                 ::basegfx::B2DSize& mrBounds;
955             };
956         }
957 
958         ::basegfx::B2DRectangle DrawShape::getUpdateArea() const
959         {
960             ::basegfx::B2DRectangle aBounds;
961 
962             // an already empty shape bound need no further
963             // treatment. In fact, any changes applied below would
964             // actually remove the special empty state, thus, don't
965             // change!
966             if( !maBounds.isEmpty() )
967             {
968                 basegfx::B2DRectangle aUnitBounds(0.0,0.0,1.0,1.0);
969 
970                 if( !maViewShapes.empty() )
971                     aUnitBounds = getActualUnitShapeBounds();
972 
973                 if( !aUnitBounds.isEmpty() )
974                 {
975                     if( mpAttributeLayer )
976                     {
977                         // calc actual shape area (in user coordinate
978                         // space) from the transformation as given by the
979                         // shape attribute layer
980                         aBounds = getShapeUpdateArea( aUnitBounds,
981                                                       getShapeTransformation( getBounds(),
982                                                                               mpAttributeLayer ),
983                                                       mpAttributeLayer );
984                     }
985                     else
986                     {
987                         // no attribute layer, thus, the true shape bounds
988                         // can be directly derived from the XShape bound
989                         // attribute
990                         aBounds = getShapeUpdateArea( aUnitBounds,
991                                                       maBounds );
992                     }
993 
994                     if( !maViewShapes.empty() )
995                     {
996                         // determine border needed for antialiasing the shape
997                         ::basegfx::B2DSize aAABorder(0.0,0.0);
998 
999                         // for every view, get AA border and 'expand' aAABorder
1000                         // appropriately.
1001                         ::std::for_each( maViewShapes.begin(),
1002                                          maViewShapes.end(),
1003                                          Expander( aAABorder ) );
1004 
1005                         // add calculated AA border to aBounds
1006                         aBounds = ::basegfx::B2DRectangle( aBounds.getMinX() - aAABorder.getX(),
1007                                                            aBounds.getMinY() - aAABorder.getY(),
1008                                                            aBounds.getMaxX() + aAABorder.getX(),
1009                                                            aBounds.getMaxY() + aAABorder.getY() );
1010                     }
1011                 }
1012             }
1013 
1014             return aBounds;
1015         }
1016 
1017         bool DrawShape::isVisible() const
1018         {
1019             bool bIsVisible( mbIsVisible );
1020 
1021             if( mpAttributeLayer )
1022             {
1023                 // check whether visibility and alpha are not default
1024                 // (mpAttributeLayer->isVisibilityValid() returns true
1025                 // then): bVisible becomes true, if shape visibility
1026                 // is on and alpha is not 0.0 (fully transparent)
1027                 if( mpAttributeLayer->isVisibilityValid() )
1028                     bIsVisible = mpAttributeLayer->getVisibility();
1029 
1030                 // only touch bIsVisible, if the shape is still
1031                 // visible - if getVisibility already made us
1032                 // invisible, no alpha value will make us appear
1033                 // again.
1034                 if( bIsVisible && mpAttributeLayer->isAlphaValid() )
1035                     bIsVisible = !::basegfx::fTools::equalZero( mpAttributeLayer->getAlpha() );
1036             }
1037 
1038             return bIsVisible;
1039         }
1040 
1041         double DrawShape::getPriority() const
1042         {
1043             return mnPriority;
1044         }
1045 
1046         bool DrawShape::isBackgroundDetached() const
1047         {
1048             return mnIsAnimatedCount > 0;
1049         }
1050 
1051         bool DrawShape::hasIntrinsicAnimation() const
1052         {
1053             return (!maAnimationFrames.empty() || mbDrawingLayerAnim);
1054         }
1055 
1056         bool DrawShape::setIntrinsicAnimationFrame( ::std::size_t nCurrFrame )
1057         {
1058             ENSURE_OR_RETURN_FALSE( nCurrFrame < maAnimationFrames.size(),
1059                                "DrawShape::setIntrinsicAnimationFrame(): frame index out of bounds" );
1060 
1061             if( mnCurrFrame != nCurrFrame )
1062             {
1063                 mnCurrFrame   = nCurrFrame;
1064                 mpCurrMtf     = maAnimationFrames[ mnCurrFrame ].mpMtf;
1065                 mbForceUpdate = true;
1066             }
1067 
1068             return true;
1069         }
1070 
1071         // hyperlink support
1072         void DrawShape::prepareHyperlinkIndices() const
1073         {
1074             if ( !maHyperlinkIndices.empty())
1075             {
1076                 maHyperlinkIndices.clear();
1077                 maHyperlinkRegions.clear();
1078             }
1079 
1080             sal_Int32 nIndex = 0;
1081             for ( MetaAction * pCurrAct = mpCurrMtf->FirstAction();
1082                   pCurrAct != 0; pCurrAct = mpCurrMtf->NextAction() )
1083             {
1084                 if (pCurrAct->GetType() == META_COMMENT_ACTION) {
1085                     MetaCommentAction * pAct =
1086                         static_cast<MetaCommentAction *>(pCurrAct);
1087                     // skip comment if not a special XTEXT comment
1088                     if (pAct->GetComment().CompareIgnoreCaseToAscii(
1089                             RTL_CONSTASCII_STRINGPARAM("FIELD_SEQ_BEGIN") ) ==
1090                         COMPARE_EQUAL &&
1091                         // e.g. date field doesn't have data!
1092                         // currently assuming that only url field, this is
1093                         // somehow fragile! xxx todo if possible
1094                         pAct->GetData() != 0 &&
1095                         pAct->GetDataSize() > 0)
1096                     {
1097                         if (!maHyperlinkIndices.empty() &&
1098                             maHyperlinkIndices.back().second == -1) {
1099                             OSL_ENSURE( false, "### pending FIELD_SEQ_END!" );
1100                             maHyperlinkIndices.pop_back();
1101                             maHyperlinkRegions.pop_back();
1102                         }
1103                         maHyperlinkIndices.push_back(
1104                             HyperlinkIndexPair( nIndex + 1,
1105                                                 -1 /* to be filled below */ ) );
1106                         maHyperlinkRegions.push_back(
1107                             HyperlinkRegion(
1108                                 basegfx::B2DRectangle(),
1109                                 rtl::OUString(
1110                                     reinterpret_cast<sal_Unicode const*>(
1111                                         pAct->GetData()),
1112                                     pAct->GetDataSize() / sizeof(sal_Unicode) )
1113                                 ) );
1114                     }
1115                     else if (pAct->GetComment().CompareIgnoreCaseToAscii(
1116                                  RTL_CONSTASCII_STRINGPARAM("FIELD_SEQ_END")) ==
1117                              COMPARE_EQUAL &&
1118                              // pending end is expected:
1119                              !maHyperlinkIndices.empty() &&
1120                              maHyperlinkIndices.back().second == -1)
1121                     {
1122                         maHyperlinkIndices.back().second = nIndex;
1123                     }
1124                     ++nIndex;
1125                 }
1126                 else
1127                     nIndex += getNextActionOffset(pCurrAct);
1128             }
1129             if (!maHyperlinkIndices.empty() &&
1130                 maHyperlinkIndices.back().second == -1) {
1131                 OSL_ENSURE( false, "### pending FIELD_SEQ_END!" );
1132                 maHyperlinkIndices.pop_back();
1133                 maHyperlinkRegions.pop_back();
1134             }
1135             OSL_ASSERT( maHyperlinkIndices.size() == maHyperlinkRegions.size());
1136         }
1137 
1138         bool DrawShape::hasHyperlinks() const
1139         {
1140             return ! maHyperlinkRegions.empty();
1141         }
1142 
1143         HyperlinkArea::HyperlinkRegions DrawShape::getHyperlinkRegions() const
1144         {
1145             OSL_ASSERT( !maViewShapes.empty() );
1146 
1147             if( !isVisible() )
1148                 return HyperlinkArea::HyperlinkRegions();
1149 
1150             // late init, determine regions:
1151             if( !maHyperlinkRegions.empty() &&
1152                 !maViewShapes.empty() &&
1153                 // region already inited?
1154                 maHyperlinkRegions.front().first.getWidth() == 0 &&
1155                 maHyperlinkRegions.front().first.getHeight() == 0 &&
1156                 maHyperlinkRegions.size() == maHyperlinkIndices.size() )
1157             {
1158                 // TODO(Q2): Although this _is_ currently
1159                 // view-agnostic, it might not stay like that.
1160                 ViewShapeSharedPtr const& pViewShape = maViewShapes.front();
1161                 cppcanvas::CanvasSharedPtr const pCanvas(
1162                     pViewShape->getViewLayer()->getCanvas() );
1163 
1164                 // reuse Renderer of first view shape:
1165                 cppcanvas::RendererSharedPtr const pRenderer(
1166                     pViewShape->getRenderer(
1167                         pCanvas, mpCurrMtf, mpAttributeLayer ) );
1168 
1169                 OSL_ASSERT( pRenderer );
1170 
1171                 if (pRenderer)
1172                 {
1173                     basegfx::B2DHomMatrix const aOldTransform(
1174                         pCanvas->getTransformation() );
1175                     basegfx::B2DHomMatrix aTransform;
1176                     pCanvas->setTransformation( aTransform /* empty */ );
1177 
1178                     comphelper::ScopeGuard const resetOldTransformation(
1179                         boost::bind( &cppcanvas::Canvas::setTransformation,
1180                                      pCanvas.get(),
1181                                      boost::cref(aOldTransform) ));
1182 
1183                     aTransform.scale( maBounds.getWidth(),
1184                                       maBounds.getHeight() );
1185                     pRenderer->setTransformation( aTransform );
1186                     pRenderer->setClip();
1187 
1188                     for( std::size_t pos = maHyperlinkRegions.size(); pos--; )
1189                     {
1190                         // get region:
1191                         HyperlinkIndexPair const& rIndices = maHyperlinkIndices[pos];
1192                         basegfx::B2DRectangle const region(
1193                             pRenderer->getSubsetArea( rIndices.first,
1194                                                       rIndices.second ));
1195                         maHyperlinkRegions[pos].first = region;
1196                     }
1197                 }
1198             }
1199 
1200             // shift shape-relative hyperlink regions to
1201             // slide-absolute position
1202 
1203             HyperlinkRegions aTranslatedRegions;
1204             const basegfx::B2DPoint& rOffset(getBounds().getMinimum());
1205             HyperlinkRegions::const_iterator       aIter( maHyperlinkRegions.begin() );
1206             HyperlinkRegions::const_iterator const aEnd ( maHyperlinkRegions.end() );
1207             while( aIter != aEnd )
1208             {
1209                 basegfx::B2DRange const& relRegion( aIter->first );
1210                 aTranslatedRegions.push_back(
1211                     std::make_pair(
1212                         basegfx::B2DRange(
1213                             relRegion.getMinimum() + rOffset,
1214                             relRegion.getMaximum() + rOffset),
1215                         aIter->second) );
1216                 ++aIter;
1217             }
1218 
1219             return aTranslatedRegions;
1220         }
1221 
1222         double DrawShape::getHyperlinkPriority() const
1223         {
1224             return getPriority();
1225         }
1226 
1227 
1228         // AnimatableShape methods
1229         // ======================================================
1230 
1231         void DrawShape::enterAnimationMode()
1232         {
1233             OSL_ENSURE( !maViewShapes.empty(),
1234                         "DrawShape::enterAnimationMode(): called on DrawShape without views" );
1235 
1236             if( mnIsAnimatedCount == 0 )
1237             {
1238                 // notify all ViewShapes, by calling their enterAnimationMode method.
1239                 // We're now entering animation mode
1240                 ::std::for_each( maViewShapes.begin(),
1241                                  maViewShapes.end(),
1242                                  ::boost::mem_fn( &ViewShape::enterAnimationMode ) );
1243             }
1244 
1245             ++mnIsAnimatedCount;
1246         }
1247 
1248         void DrawShape::leaveAnimationMode()
1249         {
1250             OSL_ENSURE( !maViewShapes.empty(),
1251                         "DrawShape::leaveAnimationMode(): called on DrawShape without views" );
1252 
1253             --mnIsAnimatedCount;
1254 
1255             if( mnIsAnimatedCount == 0 )
1256             {
1257                 // notify all ViewShapes, by calling their leaveAnimationMode method.
1258                 // we're now leaving animation mode
1259                 ::std::for_each( maViewShapes.begin(),
1260                                  maViewShapes.end(),
1261                                  ::boost::mem_fn( &ViewShape::leaveAnimationMode ) );
1262             }
1263         }
1264 
1265 
1266         // AttributableShape methods
1267         // ======================================================
1268 
1269         ShapeAttributeLayerSharedPtr DrawShape::createAttributeLayer()
1270         {
1271             // create new layer, with last as its new child
1272             mpAttributeLayer.reset( new ShapeAttributeLayer( mpAttributeLayer ) );
1273 
1274             // Update the local state ids to reflect those of the new layer.
1275             updateStateIds();
1276 
1277             return mpAttributeLayer;
1278         }
1279 
1280         bool DrawShape::revokeAttributeLayer( const ShapeAttributeLayerSharedPtr& rLayer )
1281         {
1282             if( !mpAttributeLayer )
1283                 return false; // no layers
1284 
1285             if( mpAttributeLayer == rLayer )
1286             {
1287                 // it's the toplevel layer
1288                 mpAttributeLayer = mpAttributeLayer->getChildLayer();
1289 
1290                 // force content redraw, all state variables have
1291                 // possibly changed
1292                 mbAttributeLayerRevoked = true;
1293 
1294                 return true;
1295             }
1296             else
1297             {
1298                 // pass on to the layer, to try its children
1299                 return mpAttributeLayer->revokeChildLayer( rLayer );
1300             }
1301         }
1302 
1303         ShapeAttributeLayerSharedPtr DrawShape::getTopmostAttributeLayer() const
1304         {
1305             return mpAttributeLayer;
1306         }
1307 
1308         void DrawShape::setVisibility( bool bVisible )
1309         {
1310             if( mbIsVisible != bVisible )
1311             {
1312                 mbIsVisible = bVisible;
1313                 mbForceUpdate = true;
1314             }
1315         }
1316 
1317         const DocTreeNodeSupplier& DrawShape::getTreeNodeSupplier() const
1318         {
1319             return *this;
1320         }
1321 
1322         DocTreeNodeSupplier& DrawShape::getTreeNodeSupplier()
1323         {
1324             return *this;
1325         }
1326 
1327         DocTreeNode DrawShape::getSubsetNode() const
1328         {
1329             ensureVerboseMtfComments();
1330 
1331             // forward to delegate
1332             return maSubsetting.getSubsetNode();
1333         }
1334 
1335         AttributableShapeSharedPtr DrawShape::getSubset( const DocTreeNode& rTreeNode ) const
1336         {
1337             ENSURE_OR_THROW( (mnCurrMtfLoadFlags & MTF_LOAD_VERBOSE_COMMENTS) != 0,
1338                               "DrawShape::getSubset(): subset query on shape with apparently no subsets" );
1339 
1340             // forward to delegate
1341             return maSubsetting.getSubsetShape( rTreeNode );
1342         }
1343 
1344         bool DrawShape::createSubset( AttributableShapeSharedPtr& 	o_rSubset,
1345                                       const DocTreeNode& 			rTreeNode )
1346         {
1347             ENSURE_OR_THROW( (mnCurrMtfLoadFlags & MTF_LOAD_VERBOSE_COMMENTS) != 0,
1348                               "DrawShape::createSubset(): subset query on shape with apparently no subsets" );
1349 
1350             // subset shape already created for this DocTreeNode?
1351             AttributableShapeSharedPtr pSubset( maSubsetting.getSubsetShape( rTreeNode ) );
1352 
1353             // when true, this method has created a new subset
1354             // DrawShape
1355             bool bNewlyCreated( false );
1356 
1357             if( pSubset )
1358             {
1359                 o_rSubset = pSubset;
1360 
1361                 // reusing existing subset
1362             }
1363             else
1364             {
1365                 // not yet created, init entry
1366                 o_rSubset.reset( new DrawShape( *this,
1367                                                 rTreeNode,
1368                                                 // TODO(Q3): That's a
1369                                                 // hack. We assume
1370                                                 // that start and end
1371                                                 // index will always
1372                                                 // be less than 65535
1373                                                 mnPriority +
1374                                                 rTreeNode.getStartIndex()/double(SAL_MAX_INT16) ));
1375 
1376                 bNewlyCreated = true; // subset newly created
1377             }
1378 
1379             // always register shape at DrawShapeSubsetting, to keep
1380             // refcount up-to-date
1381             maSubsetting.addSubsetShape( o_rSubset );
1382 
1383             // flush bounds cache
1384             maCurrentShapeUnitBounds.reset();
1385 
1386             return bNewlyCreated;
1387         }
1388 
1389         bool DrawShape::revokeSubset( const AttributableShapeSharedPtr& rShape )
1390         {
1391             ENSURE_OR_THROW( (mnCurrMtfLoadFlags & MTF_LOAD_VERBOSE_COMMENTS) != 0,
1392                               "DrawShape::createSubset(): subset query on shape with apparently no subsets" );
1393 
1394             // flush bounds cache
1395             maCurrentShapeUnitBounds.reset();
1396 
1397             // forward to delegate
1398             if( maSubsetting.revokeSubsetShape( rShape ) )
1399             {
1400                 // force redraw, our content has possibly changed (as
1401                 // one of the subsets now display within our shape
1402                 // again).
1403                 mbForceUpdate = true;
1404 
1405                 // #i47428# TEMP FIX: synchronize visibility of subset
1406                 // with parent.
1407 
1408                 // TODO(F3): Remove here, and implement
1409                 // TEXT_ONLY/BACKGROUND_ONLY with the proverbial
1410                 // additional level of indirection: create a
1411                 // persistent subset, containing all text/only the
1412                 // background respectively. From _that_ object,
1413                 // generate the temporary character subset shapes.
1414                 const ShapeAttributeLayerSharedPtr& rAttrLayer(
1415                     rShape->getTopmostAttributeLayer() );
1416                 if( rAttrLayer &&
1417                     rAttrLayer->isVisibilityValid() &&
1418                     rAttrLayer->getVisibility() != isVisible() )
1419                 {
1420                     const bool bVisibility( rAttrLayer->getVisibility() );
1421 
1422                     // visibilities differ - adjust ours, then
1423                     if( mpAttributeLayer )
1424                         mpAttributeLayer->setVisibility( bVisibility );
1425                     else
1426                         mbIsVisible = bVisibility;
1427                 }
1428 
1429                 // END TEMP FIX
1430 
1431                 return true;
1432             }
1433 
1434             return false;
1435         }
1436 
1437         sal_Int32 DrawShape::getNumberOfTreeNodes( DocTreeNode::NodeType eNodeType ) const // throw ShapeLoadFailedException
1438         {
1439             ensureVerboseMtfComments();
1440 
1441             return maSubsetting.getNumberOfTreeNodes( eNodeType );
1442         }
1443 
1444         DocTreeNode DrawShape::getTreeNode( sal_Int32				nNodeIndex,
1445                                             DocTreeNode::NodeType	eNodeType ) const // throw ShapeLoadFailedException
1446         {
1447             ensureVerboseMtfComments();
1448 
1449             if ( hasHyperlinks())
1450             {
1451                 prepareHyperlinkIndices();
1452             }
1453 
1454             return maSubsetting.getTreeNode( nNodeIndex, eNodeType );
1455         }
1456 
1457         sal_Int32 DrawShape::getNumberOfSubsetTreeNodes	( const DocTreeNode& 	rParentNode,
1458                                                           DocTreeNode::NodeType eNodeType ) const // throw ShapeLoadFailedException
1459         {
1460             ensureVerboseMtfComments();
1461 
1462             return maSubsetting.getNumberOfSubsetTreeNodes( rParentNode, eNodeType );
1463         }
1464 
1465         DocTreeNode DrawShape::getSubsetTreeNode( const DocTreeNode& 	rParentNode,
1466                                                   sal_Int32				nNodeIndex,
1467                                                   DocTreeNode::NodeType	eNodeType ) const // throw ShapeLoadFailedException
1468         {
1469             ensureVerboseMtfComments();
1470 
1471             return maSubsetting.getSubsetTreeNode( rParentNode, nNodeIndex, eNodeType );
1472         }
1473     }
1474 }
1475