Update ooo320-m1
[ooovba.git] / slideshow / source / engine / shapes / drawshape.cxx
blobc94b73f3a6f8e5363f93b8d22f2a34c6d7e521f2
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: drawshape.cxx,v $
10 * $Revision: 1.7.12.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_slideshow.hxx"
34 // must be first
35 #include <canvas/debug.hxx>
36 #include <tools/diagnose_ex.h>
37 #include <canvas/verbosetrace.hxx>
39 #include <rtl/logfile.hxx>
40 #include <osl/diagnose.hxx>
41 #include <com/sun/star/awt/Rectangle.hpp>
42 #include <com/sun/star/beans/XPropertySet.hpp>
43 #include <com/sun/star/awt/FontWeight.hpp>
44 #include <comphelper/anytostring.hxx>
45 #include <cppuhelper/exc_hlp.hxx>
47 #include <vcl/metaact.hxx>
48 #include <vcl/gdimtf.hxx>
49 #include <vcl/wrkwin.hxx>
51 #include <basegfx/numeric/ftools.hxx>
52 #include <basegfx/range/rangeexpander.hxx>
54 #include <rtl/math.hxx>
56 #include <com/sun/star/drawing/TextAnimationKind.hpp>
58 #include <vcl/svapp.hxx>
59 #include <vcl/window.hxx>
60 #include <tools/stream.hxx>
61 #include <com/sun/star/frame/XModel.hpp>
62 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
63 #include <com/sun/star/datatransfer/XTransferable.hpp>
65 #include <comphelper/scopeguard.hxx>
66 #include <canvas/canvastools.hxx>
68 #include <cmath> // for trigonometry and fabs
69 #include <algorithm>
70 #include <functional>
71 #include <limits>
73 #include "drawshapesubsetting.hxx"
74 #include "drawshape.hxx"
75 #include "eventqueue.hxx"
76 #include "wakeupevent.hxx"
77 #include "subsettableshapemanager.hxx"
78 #include "intrinsicanimationactivity.hxx"
79 #include "slideshowexceptions.hxx"
80 #include "tools.hxx"
81 #include "gdimtftools.hxx"
82 #include "drawinglayeranimation.hxx"
84 #include <boost/bind.hpp>
85 #include <math.h>
87 using namespace ::com::sun::star;
90 namespace slideshow
92 namespace internal
94 //#i75867# poor quality of ole's alternative view with 3D scenes and zoomfactors besides 100%
95 //metafiles are resolution dependent when bitmaps are contained with is the case for 3D scenes for example
96 //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)
97 bool local_getMetafileForChart( const uno::Reference< lang::XComponent >& xSource,
98 const uno::Reference< drawing::XDrawPage >& xContainingPage,
99 GDIMetaFile& rMtf )
101 //get the chart model
102 uno::Reference< beans::XPropertySet > xPropSet( xSource, uno::UNO_QUERY );
103 uno::Reference< frame::XModel > xChartModel;
104 getPropertyValue( xChartModel, xPropSet, OUSTR("Model"));
105 uno::Reference< lang::XMultiServiceFactory > xFact( xChartModel, uno::UNO_QUERY );
106 OSL_ENSURE( xFact.is(), "Chart cannot be painted pretty!\n" );
107 if(!xFact.is())
108 return false;
110 //get the chart view
111 uno::Reference< datatransfer::XTransferable > xChartViewTransferable(
112 xFact->createInstance( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.chart2.ChartView" ) ) ), uno::UNO_QUERY );
113 uno::Reference< beans::XPropertySet > xChartViewProp( xChartViewTransferable, uno::UNO_QUERY );
114 OSL_ENSURE( xChartViewProp.is(), "Chart cannot be painted pretty!\n" );
115 if( !xChartViewProp.is() )
116 return false;
118 //estimate zoom and resolution (this is only a workaround, correct would be to know and use the exact zoom and resoltion during slideshow display)
119 sal_Int32 nScaleXNumerator = 100;//zoom factor -> exact values are important for the quality of the created bitmap especially for 3D charts
120 sal_Int32 nScaleYNumerator = 100;
121 sal_Int32 nScaleXDenominator = 100;
122 sal_Int32 nScaleYDenominator = 100;
123 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
125 Window* pActiveTopWindow( Application::GetActiveTopWindow() );
126 WorkWindow* pWorkWindow( dynamic_cast<WorkWindow*>(pActiveTopWindow));
127 if( pWorkWindow && pWorkWindow->IsPresentationMode() )
129 Size aPixScreenSize( pActiveTopWindow->GetOutputSizePixel() );
130 aPixelPerChart = awt::Size( aPixScreenSize.getWidth(), aPixScreenSize.getHeight() );//this is still to much (but costs only seldom performance), correct would be pixel per chart object
132 uno::Reference< beans::XPropertySet > xPageProp( xContainingPage, uno::UNO_QUERY );
133 sal_Int32 nLogicPageWidth=1;
134 sal_Int32 nLogicPageHeight=1;
135 if( getPropertyValue( nLogicPageWidth, xPageProp, OUSTR("Width")) &&
136 getPropertyValue( nLogicPageHeight, xPageProp, OUSTR("Height")) )
138 Size aLogicScreenSize( pActiveTopWindow->PixelToLogic( aPixScreenSize, MAP_100TH_MM ) );
139 nScaleXNumerator = aLogicScreenSize.getWidth();
140 nScaleYNumerator = aLogicScreenSize.getHeight();
141 nScaleXDenominator = nLogicPageWidth;
142 nScaleYDenominator = nLogicPageHeight;
145 else
147 long nMaxPixWidth = 0;
148 long nMaxPixHeight = 0;
149 unsigned int nScreenCount( Application::GetScreenCount() );
150 for( unsigned int nScreen=0; nScreen<nScreenCount; nScreen++ )
152 Rectangle aCurScreenRect( Application::GetScreenPosSizePixel( nScreen ) );
153 if( aCurScreenRect.GetWidth() > nMaxPixWidth )
154 nMaxPixWidth = aCurScreenRect.GetWidth();
155 if( aCurScreenRect.GetHeight() > nMaxPixHeight )
156 nMaxPixHeight = aCurScreenRect.GetHeight();
158 if(nMaxPixWidth>1 && nMaxPixHeight>1)
159 aPixelPerChart = awt::Size( nMaxPixWidth, nMaxPixHeight );//this is still to much (but costs only seldom performance), correct would be pixel per chart object
164 uno::Sequence< beans::PropertyValue > aZoomFactors(4);
165 aZoomFactors[0].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ScaleXNumerator") );
166 aZoomFactors[0].Value = uno::makeAny( nScaleXNumerator );
167 aZoomFactors[1].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ScaleXDenominator") );
168 aZoomFactors[1].Value = uno::makeAny( nScaleXDenominator );
169 aZoomFactors[2].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ScaleYNumerator") );
170 aZoomFactors[2].Value = uno::makeAny( nScaleYNumerator );
171 aZoomFactors[3].Name = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ScaleYDenominator") );
172 aZoomFactors[3].Value = uno::makeAny( nScaleYDenominator );
174 xChartViewProp->setPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("ZoomFactors") ), uno::makeAny( aZoomFactors ));
175 xChartViewProp->setPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("Resolution") ), uno::makeAny( aPixelPerChart ));
177 catch (uno::Exception &)
179 OSL_ENSURE( false, rtl::OUStringToOString(
180 comphelper::anyToString(
181 cppu::getCaughtException() ),
182 RTL_TEXTENCODING_UTF8 ).getStr() );
185 //get a metafile from the prepared chart view
186 datatransfer::DataFlavor aDataFlavor(
187 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("application/x-openoffice-gdimetafile;windows_formatname=\"GDIMetaFile\"") ),
188 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "GDIMetaFile" ) ),
189 ::getCppuType( (const uno::Sequence< sal_Int8 >*) 0 ) );
190 uno::Any aData( xChartViewTransferable->getTransferData( aDataFlavor ) );
191 uno::Sequence< sal_Int8 > aSeq;
192 if( aData >>= aSeq )
194 ::std::auto_ptr< SvMemoryStream > pSrcStm( new SvMemoryStream( (char*) aSeq.getConstArray(), aSeq.getLength(), STREAM_WRITE | STREAM_TRUNC ) );
195 *(pSrcStm.get() ) >> rMtf;
196 return true;
198 return false;
201 //same as getMetafile with an exception for charts
202 //for charts a metafile with a higher resolution is created, because charts have resolution dependent content
203 bool local_getMetaFile_WithSpecialChartHandling( const uno::Reference< lang::XComponent >& xSource,
204 const uno::Reference< drawing::XDrawPage >& xContainingPage,
205 GDIMetaFile& rMtf,
206 int mtfLoadFlags,
207 const uno::Reference< uno::XComponentContext >& rxContext )
209 uno::Reference<beans::XPropertySet> xProp( xSource, uno::UNO_QUERY );
210 rtl::OUString sCLSID;
211 getPropertyValue( sCLSID, xProp, OUSTR("CLSID"));
212 if( sCLSID.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("12DCAE26-281F-416F-a234-c3086127382e")) && local_getMetafileForChart( xSource, xContainingPage, rMtf ) )
213 return true;
214 return getMetaFile( xSource, xContainingPage, rMtf, mtfLoadFlags, rxContext );
218 //////////////////////////////////////////////////////////////////////
220 // Private methods
222 //////////////////////////////////////////////////////////////////////
224 GDIMetaFileSharedPtr DrawShape::forceScrollTextMetaFile()
226 if ((mnCurrMtfLoadFlags & MTF_LOAD_SCROLL_TEXT_MTF) != MTF_LOAD_SCROLL_TEXT_MTF)
228 // reload with added flags:
229 mpCurrMtf.reset( new GDIMetaFile );
230 mnCurrMtfLoadFlags |= MTF_LOAD_SCROLL_TEXT_MTF;
231 local_getMetaFile_WithSpecialChartHandling(
232 uno::Reference<lang::XComponent>(mxShape, uno::UNO_QUERY),
233 mxPage, *mpCurrMtf, mnCurrMtfLoadFlags,
234 mxComponentContext );
236 // TODO(F1): Currently, the scroll metafile will
237 // never contain any verbose text comments. Thus,
238 // can only display the full mtf content, no
239 // subsets.
240 maSubsetting.reset( mpCurrMtf );
242 // adapt maBounds. the requested scroll text metafile
243 // will typically have dimension different from the
244 // actual shape
245 ::basegfx::B2DRectangle aScrollRect, aPaintRect;
246 ENSURE_OR_THROW( getRectanglesFromScrollMtf( aScrollRect,
247 aPaintRect,
248 mpCurrMtf ),
249 "DrawShape::forceScrollTextMetaFile(): Could "
250 "not extract scroll anim rectangles from mtf" );
252 // take the larger one of the two rectangles (that
253 // should be the bound rect of the retrieved
254 // metafile)
255 if( aScrollRect.isInside( aPaintRect ) )
256 maBounds = aScrollRect;
257 else
258 maBounds = aPaintRect;
260 return mpCurrMtf;
263 void DrawShape::updateStateIds() const
265 // Update the states, we've just redrawn or created a new
266 // attribute layer.
267 if( mpAttributeLayer )
269 mnAttributeTransformationState = mpAttributeLayer->getTransformationState();
270 mnAttributeClipState = mpAttributeLayer->getClipState();
271 mnAttributeAlphaState = mpAttributeLayer->getAlphaState();
272 mnAttributePositionState = mpAttributeLayer->getPositionState();
273 mnAttributeContentState = mpAttributeLayer->getContentState();
274 mnAttributeVisibilityState = mpAttributeLayer->getVisibilityState();
278 void DrawShape::ensureVerboseMtfComments() const
280 // TODO(F1): Text effects don't currently work for drawing
281 // layer animations.
283 // only touch mpCurrMtf, if we're not a DrawingLayer
284 // animation.
285 if( (mnCurrMtfLoadFlags & MTF_LOAD_VERBOSE_COMMENTS) == 0 &&
286 maAnimationFrames.empty() )
288 ENSURE_OR_THROW( !maSubsetting.hasSubsetShapes(),
289 "DrawShape::ensureVerboseMtfComments(): reloading the metafile "
290 "with active child subsets will wreak havoc on the view!" );
291 ENSURE_OR_THROW( maSubsetting.getSubsetNode().isEmpty(),
292 "DrawShape::ensureVerboseMtfComments(): reloading the metafile "
293 "for an ALREADY SUBSETTED shape is not possible!" );
295 // re-fetch metafile with comments
296 // note that, in case of shapes without text, the new
297 // metafile might still not provide any useful
298 // subsetting information!
299 mpCurrMtf.reset( new GDIMetaFile );
300 mnCurrMtfLoadFlags |= MTF_LOAD_VERBOSE_COMMENTS;
301 local_getMetaFile_WithSpecialChartHandling(
302 uno::Reference<lang::XComponent>(mxShape, uno::UNO_QUERY),
303 mxPage, *mpCurrMtf, mnCurrMtfLoadFlags,
304 mxComponentContext );
306 maSubsetting.reset( maSubsetting.getSubsetNode(),
307 mpCurrMtf );
311 ViewShape::RenderArgs DrawShape::getViewRenderArgs() const
313 return ViewShape::RenderArgs(
314 maBounds,
315 getUpdateArea(),
316 getBounds(),
317 getActualUnitShapeBounds(),
318 mpAttributeLayer,
319 maSubsetting.getActiveSubsets(),
320 mnPriority);
323 bool DrawShape::implRender( int nUpdateFlags ) const
325 RTL_LOGFILE_CONTEXT( aLog, "::presentation::internal::DrawShape::implRender()" );
326 RTL_LOGFILE_CONTEXT_TRACE1( aLog, "::presentation::internal::DrawShape: 0x%X", this );
328 // will perform the update now, clear update-enforcing
329 // flags
330 mbForceUpdate = false;
331 mbAttributeLayerRevoked = false;
333 ENSURE_OR_RETURN( !maViewShapes.empty(),
334 "DrawShape::implRender(): render called on DrawShape without views" );
336 if( maBounds.isEmpty() )
338 // zero-sized shapes are effectively invisible,
339 // thus, we save us the rendering...
340 return true;
343 // redraw all view shapes, by calling their update() method
344 if( ::std::count_if( maViewShapes.begin(),
345 maViewShapes.end(),
346 ::boost::bind<bool>(
347 ::boost::mem_fn( &ViewShape::update ), // though _theoretically_,
348 // bind should eat this even
349 // with _1 being a shared_ptr,
350 // it does _not_ for MSVC without
351 // the extra mem_fn. WTF.
353 ::boost::cref( mpCurrMtf ),
354 ::boost::cref(
355 getViewRenderArgs() ),
356 nUpdateFlags,
357 isVisible() ) )
358 != static_cast<ViewShapeVector::difference_type>(maViewShapes.size()) )
360 // at least one of the ViewShape::update() calls did return
361 // false - update failed on at least one ViewLayer
362 return false;
365 // successfully redrawn - update state IDs to detect next changes
366 updateStateIds();
368 return true;
371 int DrawShape::getUpdateFlags() const
373 // default: update nothing, unless ShapeAttributeStack
374 // tells us below, or if the attribute layer was revoked
375 int nUpdateFlags(ViewShape::NONE);
377 // possibly the whole shape content changed
378 if( mbAttributeLayerRevoked )
379 nUpdateFlags = ViewShape::CONTENT;
382 // determine what has to be updated
383 // --------------------------------
385 // do we have an attribute layer?
386 if( mpAttributeLayer )
388 // Prevent nUpdateFlags to be modified when the shape is not
389 // visible, except when it just was hidden.
390 if (mpAttributeLayer->getVisibility()
391 || mpAttributeLayer->getVisibilityState() != mnAttributeVisibilityState )
393 if (mpAttributeLayer->getVisibilityState() != mnAttributeVisibilityState )
395 // Change of the visibility state is mapped to
396 // content change because when the visibility
397 // changes then usually a sprite is shown or hidden
398 // and the background under has to be painted once.
399 nUpdateFlags |= ViewShape::CONTENT;
402 // TODO(P1): This can be done without conditional branching.
403 // See HAKMEM.
404 if( mpAttributeLayer->getPositionState() != mnAttributePositionState )
406 nUpdateFlags |= ViewShape::POSITION;
408 if( mpAttributeLayer->getAlphaState() != mnAttributeAlphaState )
410 nUpdateFlags |= ViewShape::ALPHA;
412 if( mpAttributeLayer->getClipState() != mnAttributeClipState )
414 nUpdateFlags |= ViewShape::CLIP;
416 if( mpAttributeLayer->getTransformationState() != mnAttributeTransformationState )
418 nUpdateFlags |= ViewShape::TRANSFORMATION;
420 if( mpAttributeLayer->getContentState() != mnAttributeContentState )
422 nUpdateFlags |= ViewShape::CONTENT;
427 return nUpdateFlags;
430 ::basegfx::B2DRectangle DrawShape::getActualUnitShapeBounds() const
432 ENSURE_OR_THROW( !maViewShapes.empty(),
433 "DrawShape::getActualUnitShapeBounds(): called on DrawShape without views" );
435 const VectorOfDocTreeNodes& rSubsets(
436 maSubsetting.getActiveSubsets() );
438 const ::basegfx::B2DRectangle aDefaultBounds( 0.0,0.0,1.0,1.0 );
440 // perform the cheapest check first
441 if( rSubsets.empty() )
443 // if subset contains the whole shape, no need to call
444 // the somewhat expensive bound calculation, since as
445 // long as the subset is empty, this branch will be
446 // taken.
447 return aDefaultBounds;
449 else
451 OSL_ENSURE( rSubsets.size() != 1 ||
452 !rSubsets.front().isEmpty(),
453 "DrawShape::getActualUnitShapeBounds() expects a "
454 "_non-empty_ subset vector for a subsetted shape!" );
456 // are the cached bounds still valid?
457 if( !maCurrentShapeUnitBounds )
459 // no, (re)generate them
460 // =====================
462 // setup cached values to defaults (might fail to
463 // retrieve true bounds below)
464 maCurrentShapeUnitBounds.reset( aDefaultBounds );
466 // TODO(P2): the subset of the master shape (that from
467 // which the subsets are subtracted) changes
468 // relatively often (every time a subset shape is
469 // added or removed). Maybe we should exclude it here,
470 // always assuming full bounds?
472 ::cppcanvas::CanvasSharedPtr pDestinationCanvas(
473 maViewShapes.front()->getViewLayer()->getCanvas() );
475 // TODO(Q2): Although this _is_ currently
476 // view-agnostic, it might not stay like
477 // that. Maybe this method should again be moved
478 // to the ViewShape
479 ::cppcanvas::RendererSharedPtr pRenderer(
480 maViewShapes.front()->getRenderer(
481 pDestinationCanvas, mpCurrMtf, mpAttributeLayer ) );
483 // If we cannot not prefetch, be defensive and assume
484 // full shape size
485 if( pRenderer )
487 // temporarily, switch total transformation to identity
488 // (need the bounds in the [0,1]x[0,1] unit coordinate
489 // system.
490 ::basegfx::B2DHomMatrix aEmptyTransformation;
492 ::basegfx::B2DHomMatrix aOldTransform( pDestinationCanvas->getTransformation() );
493 pDestinationCanvas->setTransformation( aEmptyTransformation );
494 pRenderer->setTransformation( aEmptyTransformation );
496 // restore old transformation when leaving the scope
497 const ::comphelper::ScopeGuard aGuard(
498 boost::bind( &::cppcanvas::Canvas::setTransformation,
499 pDestinationCanvas, aOldTransform ) );
502 // retrieve bounds for subset of whole metafile
503 // --------------------------------------------
505 ::basegfx::B2DRange aTotalBounds;
507 // cannot use ::boost::bind, ::basegfx::B2DRange::expand()
508 // is overloaded.
509 VectorOfDocTreeNodes::const_iterator aCurr( rSubsets.begin() );
510 const VectorOfDocTreeNodes::const_iterator aEnd( rSubsets.end() );
511 while( aCurr != aEnd )
513 aTotalBounds.expand( pRenderer->getSubsetArea(
514 aCurr->getStartIndex(),
515 aCurr->getEndIndex() ) );
516 ++aCurr;
519 OSL_ENSURE( aTotalBounds.getMinX() >= -0.1 &&
520 aTotalBounds.getMinY() >= -0.1 &&
521 aTotalBounds.getMaxX() <= 1.1 &&
522 aTotalBounds.getMaxY() <= 1.1,
523 "DrawShape::getActualUnitShapeBounds(): bounds noticeably larger than original shape - clipping!" );
525 // really make sure no shape appears larger than its
526 // original bounds (there _are_ some pathologic cases,
527 // especially when imported from PPT, that have
528 // e.g. obscenely large polygon bounds)
529 aTotalBounds.intersect(
530 ::basegfx::B2DRange( 0.0, 0.0,
531 1.0, 1.0 ));
533 maCurrentShapeUnitBounds.reset( aTotalBounds );
537 return *maCurrentShapeUnitBounds;
541 DrawShape::DrawShape( const uno::Reference< drawing::XShape >& xShape,
542 const uno::Reference< drawing::XDrawPage >& xContainingPage,
543 double nPrio,
544 bool bForeignSource,
545 const SlideShowContext& rContext ) :
546 mxShape( xShape ),
547 mxPage( xContainingPage ),
548 maAnimationFrames(), // empty, we don't have no intrinsic animation
549 mnCurrFrame(0),
550 mpCurrMtf(),
551 mnCurrMtfLoadFlags( bForeignSource
552 ? MTF_LOAD_FOREIGN_SOURCE : MTF_LOAD_NONE ),
553 maCurrentShapeUnitBounds(),
554 mnPriority( nPrio ), // TODO(F1): When ZOrder someday becomes usable: make this ( getAPIShapePrio( xShape ) ),
555 maBounds( getAPIShapeBounds( xShape ) ),
556 mpAttributeLayer(),
557 mpIntrinsicAnimationActivity(),
558 mnAttributeTransformationState(0),
559 mnAttributeClipState(0),
560 mnAttributeAlphaState(0),
561 mnAttributePositionState(0),
562 mnAttributeContentState(0),
563 mnAttributeVisibilityState(0),
564 maViewShapes(),
565 mxComponentContext( rContext.mxComponentContext ),
566 maHyperlinkIndices(),
567 maHyperlinkRegions(),
568 maSubsetting(),
569 mnIsAnimatedCount(0),
570 mnAnimationLoopCount(0),
571 meCycleMode(CYCLE_LOOP),
572 mbIsVisible( true ),
573 mbForceUpdate( false ),
574 mbAttributeLayerRevoked( false ),
575 mbDrawingLayerAnim( false )
577 ENSURE_OR_THROW( mxShape.is(), "DrawShape::DrawShape(): Invalid XShape" );
578 ENSURE_OR_THROW( mxPage.is(), "DrawShape::DrawShape(): Invalid containing page" );
580 // check for drawing layer animations:
581 drawing::TextAnimationKind eKind = drawing::TextAnimationKind_NONE;
582 uno::Reference<beans::XPropertySet> xPropSet( mxShape,
583 uno::UNO_QUERY );
584 if( xPropSet.is() )
585 getPropertyValue( eKind, xPropSet,
586 OUSTR("TextAnimationKind") );
587 mbDrawingLayerAnim = (eKind != drawing::TextAnimationKind_NONE);
589 // must NOT be called from within initializer list, uses
590 // state from mnCurrMtfLoadFlags!
591 mpCurrMtf.reset( new GDIMetaFile );
592 local_getMetaFile_WithSpecialChartHandling(
593 uno::Reference<lang::XComponent>(xShape, uno::UNO_QUERY),
594 xContainingPage, *mpCurrMtf, mnCurrMtfLoadFlags,
595 mxComponentContext );
596 ENSURE_OR_THROW( mpCurrMtf,
597 "DrawShape::DrawShape(): Invalid metafile" );
598 maSubsetting.reset( mpCurrMtf );
600 prepareHyperlinkIndices();
603 DrawShape::DrawShape( const uno::Reference< drawing::XShape >& xShape,
604 const uno::Reference< drawing::XDrawPage >& xContainingPage,
605 double nPrio,
606 const Graphic& rGraphic,
607 const SlideShowContext& rContext ) :
608 mxShape( xShape ),
609 mxPage( xContainingPage ),
610 maAnimationFrames(),
611 mnCurrFrame(0),
612 mpCurrMtf(),
613 mnCurrMtfLoadFlags( MTF_LOAD_NONE ),
614 maCurrentShapeUnitBounds(),
615 mnPriority( nPrio ), // TODO(F1): When ZOrder someday becomes usable: make this ( getAPIShapePrio( xShape ) ),
616 maBounds( getAPIShapeBounds( xShape ) ),
617 mpAttributeLayer(),
618 mpIntrinsicAnimationActivity(),
619 mnAttributeTransformationState(0),
620 mnAttributeClipState(0),
621 mnAttributeAlphaState(0),
622 mnAttributePositionState(0),
623 mnAttributeContentState(0),
624 mnAttributeVisibilityState(0),
625 maViewShapes(),
626 mxComponentContext( rContext.mxComponentContext ),
627 maHyperlinkIndices(),
628 maHyperlinkRegions(),
629 maSubsetting(),
630 mnIsAnimatedCount(0),
631 mnAnimationLoopCount(0),
632 meCycleMode(CYCLE_LOOP),
633 mbIsVisible( true ),
634 mbForceUpdate( false ),
635 mbAttributeLayerRevoked( false ),
636 mbDrawingLayerAnim( false )
638 ENSURE_OR_THROW( rGraphic.IsAnimated(),
639 "DrawShape::DrawShape(): Graphic is no animation" );
641 getAnimationFromGraphic( maAnimationFrames,
642 mnAnimationLoopCount,
643 meCycleMode,
644 rGraphic );
646 ENSURE_OR_THROW( !maAnimationFrames.empty() &&
647 maAnimationFrames.front().mpMtf,
648 "DrawShape::DrawShape(): " );
649 mpCurrMtf = maAnimationFrames.front().mpMtf;
651 ENSURE_OR_THROW( mxShape.is(), "DrawShape::DrawShape(): Invalid XShape" );
652 ENSURE_OR_THROW( mxPage.is(), "DrawShape::DrawShape(): Invalid containing page" );
653 ENSURE_OR_THROW( mpCurrMtf, "DrawShape::DrawShape(): Invalid metafile" );
656 DrawShape::DrawShape( const DrawShape& rSrc,
657 const DocTreeNode& rTreeNode,
658 double nPrio ) :
659 mxShape( rSrc.mxShape ),
660 mxPage( rSrc.mxPage ),
661 maAnimationFrames(), // don't copy animations for subsets,
662 // only the current frame!
663 mnCurrFrame(0),
664 mpCurrMtf( rSrc.mpCurrMtf ),
665 mnCurrMtfLoadFlags( rSrc.mnCurrMtfLoadFlags ),
666 maCurrentShapeUnitBounds(),
667 mnPriority( nPrio ),
668 maBounds( rSrc.maBounds ),
669 mpAttributeLayer(),
670 mpIntrinsicAnimationActivity(),
671 mnAttributeTransformationState(0),
672 mnAttributeClipState(0),
673 mnAttributeAlphaState(0),
674 mnAttributePositionState(0),
675 mnAttributeContentState(0),
676 mnAttributeVisibilityState(0),
677 maViewShapes(),
678 mxComponentContext( rSrc.mxComponentContext ),
679 maHyperlinkIndices(),
680 maHyperlinkRegions(),
681 maSubsetting( rTreeNode, mpCurrMtf ),
682 mnIsAnimatedCount(0),
683 mnAnimationLoopCount(0),
684 meCycleMode(CYCLE_LOOP),
685 mbIsVisible( rSrc.mbIsVisible ),
686 mbForceUpdate( false ),
687 mbAttributeLayerRevoked( false ),
688 mbDrawingLayerAnim( false )
690 ENSURE_OR_THROW( mxShape.is(), "DrawShape::DrawShape(): Invalid XShape" );
691 ENSURE_OR_THROW( mpCurrMtf, "DrawShape::DrawShape(): Invalid metafile" );
693 // xxx todo: currently not implemented for subsetted shapes;
694 // would mean modifying set of hyperlink regions when
695 // subsetting text portions. N.B.: there's already an
696 // issue for this #i72828#
699 //////////////////////////////////////////////////////////////////////
701 // Public methods
703 //////////////////////////////////////////////////////////////////////
705 DrawShapeSharedPtr DrawShape::create(
706 const uno::Reference< drawing::XShape >& xShape,
707 const uno::Reference< drawing::XDrawPage >& xContainingPage,
708 double nPrio,
709 bool bForeignSource,
710 const SlideShowContext& rContext )
712 DrawShapeSharedPtr pShape( new DrawShape(xShape,
713 xContainingPage,
714 nPrio,
715 bForeignSource,
716 rContext) );
718 if( pShape->hasIntrinsicAnimation() )
720 OSL_ASSERT( pShape->maAnimationFrames.empty() );
721 if( pShape->getNumberOfTreeNodes(
722 DocTreeNode::NODETYPE_LOGICAL_PARAGRAPH) > 0 )
724 pShape->mpIntrinsicAnimationActivity =
725 createDrawingLayerAnimActivity(
726 rContext,
727 pShape);
731 if( pShape->hasHyperlinks() )
732 rContext.mpSubsettableShapeManager->addHyperlinkArea( pShape );
734 return pShape;
737 DrawShapeSharedPtr DrawShape::create(
738 const uno::Reference< drawing::XShape >& xShape,
739 const uno::Reference< drawing::XDrawPage >& xContainingPage,
740 double nPrio,
741 const Graphic& rGraphic,
742 const SlideShowContext& rContext )
744 DrawShapeSharedPtr pShape( new DrawShape(xShape,
745 xContainingPage,
746 nPrio,
747 rGraphic,
748 rContext) );
750 if( pShape->hasIntrinsicAnimation() )
752 OSL_ASSERT( !pShape->maAnimationFrames.empty() );
754 std::vector<double> aTimeout;
755 std::transform(
756 pShape->maAnimationFrames.begin(),
757 pShape->maAnimationFrames.end(),
758 std::back_insert_iterator< std::vector<double> >( aTimeout ),
759 boost::mem_fn(&MtfAnimationFrame::getDuration) );
761 WakeupEventSharedPtr pWakeupEvent(
762 new WakeupEvent( rContext.mrEventQueue.getTimer(),
763 rContext.mrActivitiesQueue ) );
765 ActivitySharedPtr pActivity =
766 createIntrinsicAnimationActivity(
767 rContext,
768 pShape,
769 pWakeupEvent,
770 aTimeout,
771 pShape->mnAnimationLoopCount,
772 pShape->meCycleMode);
774 pWakeupEvent->setActivity( pActivity );
775 pShape->mpIntrinsicAnimationActivity = pActivity;
778 OSL_ENSURE( !pShape->hasHyperlinks(),
779 "DrawShape::create(): graphic-only shapes must not have hyperlinks!" );
781 return pShape;
784 DrawShape::~DrawShape()
788 // dispose intrinsic animation activity, else, it will
789 // linger forever
790 ActivitySharedPtr pActivity( mpIntrinsicAnimationActivity.lock() );
791 if( pActivity )
792 pActivity->dispose();
794 catch (uno::Exception &)
796 OSL_ENSURE( false, rtl::OUStringToOString(
797 comphelper::anyToString(
798 cppu::getCaughtException() ),
799 RTL_TEXTENCODING_UTF8 ).getStr() );
803 uno::Reference< drawing::XShape > DrawShape::getXShape() const
805 return mxShape;
808 void DrawShape::addViewLayer( const ViewLayerSharedPtr& rNewLayer,
809 bool bRedrawLayer )
811 ViewShapeVector::iterator aEnd( maViewShapes.end() );
813 // already added?
814 if( ::std::find_if( maViewShapes.begin(),
815 aEnd,
816 ::boost::bind<bool>(
817 ::std::equal_to< ViewLayerSharedPtr >(),
818 ::boost::bind( &ViewShape::getViewLayer,
819 _1 ),
820 ::boost::cref( rNewLayer ) ) ) != aEnd )
822 // yes, nothing to do
823 return;
826 ViewShapeSharedPtr pNewShape( new ViewShape( rNewLayer ) );
828 maViewShapes.push_back( pNewShape );
830 // pass on animation state
831 if( mnIsAnimatedCount )
833 for( int i=0; i<mnIsAnimatedCount; ++i )
834 pNewShape->enterAnimationMode();
837 // render the Shape on the newly added ViewLayer
838 if( bRedrawLayer )
840 pNewShape->update( mpCurrMtf,
841 getViewRenderArgs(),
842 ViewShape::FORCE,
843 isVisible() );
847 bool DrawShape::removeViewLayer( const ViewLayerSharedPtr& rLayer )
849 const ViewShapeVector::iterator aEnd( maViewShapes.end() );
851 OSL_ENSURE( ::std::count_if(maViewShapes.begin(),
852 aEnd,
853 ::boost::bind<bool>(
854 ::std::equal_to< ViewLayerSharedPtr >(),
855 ::boost::bind( &ViewShape::getViewLayer,
856 _1 ),
857 ::boost::cref( rLayer ) ) ) < 2,
858 "DrawShape::removeViewLayer(): Duplicate ViewLayer entries!" );
860 ViewShapeVector::iterator aIter;
862 if( (aIter=::std::remove_if( maViewShapes.begin(),
863 aEnd,
864 ::boost::bind<bool>(
865 ::std::equal_to< ViewLayerSharedPtr >(),
866 ::boost::bind( &ViewShape::getViewLayer,
867 _1 ),
868 ::boost::cref( rLayer ) ) )) == aEnd )
870 // view layer seemingly was not added, failed
871 return false;
874 // actually erase from container
875 maViewShapes.erase( aIter, aEnd );
877 return true;
880 bool DrawShape::clearAllViewLayers()
882 maViewShapes.clear();
883 return true;
886 bool DrawShape::update() const
888 if( mbForceUpdate )
890 return render();
892 else
894 return implRender( getUpdateFlags() );
898 bool DrawShape::render() const
900 // force redraw. Have to also pass on the update flags,
901 // because e.g. content update (regeneration of the
902 // metafile renderer) is normally not performed. A simple
903 // ViewShape::FORCE would only paint the metafile in its
904 // old state.
905 return implRender( ViewShape::FORCE | getUpdateFlags() );
908 bool DrawShape::isContentChanged() const
910 return mbForceUpdate ?
911 true :
912 getUpdateFlags() != ViewShape::NONE;
916 ::basegfx::B2DRectangle DrawShape::getBounds() const
918 // little optimization: for non-modified shapes, we don't
919 // create an ShapeAttributeStack, and therefore also don't
920 // have to check it.
921 return getShapePosSize( maBounds,
922 mpAttributeLayer );
925 ::basegfx::B2DRectangle DrawShape::getDomBounds() const
927 return maBounds;
930 namespace
932 /** Functor expanding AA border for each passed ViewShape
934 Could not use ::boost::bind here, since
935 B2DRange::expand is overloaded (which yields one or
936 the other template type deduction ambiguous)
938 class Expander
940 public:
941 Expander( ::basegfx::B2DSize& rBounds ) :
942 mrBounds( rBounds )
946 void operator()( const ViewShapeSharedPtr& rShape ) const
948 const ::basegfx::B2DSize& rShapeBorder( rShape->getAntialiasingBorder() );
950 mrBounds.setX(
951 ::std::max(
952 rShapeBorder.getX(),
953 mrBounds.getX() ) );
954 mrBounds.setY(
955 ::std::max(
956 rShapeBorder.getY(),
957 mrBounds.getY() ) );
960 private:
961 ::basegfx::B2DSize& mrBounds;
965 ::basegfx::B2DRectangle DrawShape::getUpdateArea() const
967 ::basegfx::B2DRectangle aBounds;
969 // an already empty shape bound need no further
970 // treatment. In fact, any changes applied below would
971 // actually remove the special empty state, thus, don't
972 // change!
973 if( !maBounds.isEmpty() )
975 basegfx::B2DRectangle aUnitBounds(0.0,0.0,1.0,1.0);
977 if( !maViewShapes.empty() )
978 aUnitBounds = getActualUnitShapeBounds();
980 if( !aUnitBounds.isEmpty() )
982 if( mpAttributeLayer )
984 // calc actual shape area (in user coordinate
985 // space) from the transformation as given by the
986 // shape attribute layer
987 aBounds = getShapeUpdateArea( aUnitBounds,
988 getShapeTransformation( getBounds(),
989 mpAttributeLayer ),
990 mpAttributeLayer );
992 else
994 // no attribute layer, thus, the true shape bounds
995 // can be directly derived from the XShape bound
996 // attribute
997 aBounds = getShapeUpdateArea( aUnitBounds,
998 maBounds );
1001 if( !maViewShapes.empty() )
1003 // determine border needed for antialiasing the shape
1004 ::basegfx::B2DSize aAABorder(0.0,0.0);
1006 // for every view, get AA border and 'expand' aAABorder
1007 // appropriately.
1008 ::std::for_each( maViewShapes.begin(),
1009 maViewShapes.end(),
1010 Expander( aAABorder ) );
1012 // add calculated AA border to aBounds
1013 aBounds = ::basegfx::B2DRectangle( aBounds.getMinX() - aAABorder.getX(),
1014 aBounds.getMinY() - aAABorder.getY(),
1015 aBounds.getMaxX() + aAABorder.getX(),
1016 aBounds.getMaxY() + aAABorder.getY() );
1021 return aBounds;
1024 bool DrawShape::isVisible() const
1026 bool bIsVisible( mbIsVisible );
1028 if( mpAttributeLayer )
1030 // check whether visibility and alpha are not default
1031 // (mpAttributeLayer->isVisibilityValid() returns true
1032 // then): bVisible becomes true, if shape visibility
1033 // is on and alpha is not 0.0 (fully transparent)
1034 if( mpAttributeLayer->isVisibilityValid() )
1035 bIsVisible = mpAttributeLayer->getVisibility();
1037 // only touch bIsVisible, if the shape is still
1038 // visible - if getVisibility already made us
1039 // invisible, no alpha value will make us appear
1040 // again.
1041 if( bIsVisible && mpAttributeLayer->isAlphaValid() )
1042 bIsVisible = !::basegfx::fTools::equalZero( mpAttributeLayer->getAlpha() );
1045 return bIsVisible;
1048 double DrawShape::getPriority() const
1050 return mnPriority;
1053 bool DrawShape::isBackgroundDetached() const
1055 return mnIsAnimatedCount > 0;
1058 bool DrawShape::hasIntrinsicAnimation() const
1060 return (!maAnimationFrames.empty() || mbDrawingLayerAnim);
1063 bool DrawShape::setIntrinsicAnimationFrame( ::std::size_t nCurrFrame )
1065 ENSURE_OR_RETURN( nCurrFrame < maAnimationFrames.size(),
1066 "DrawShape::setIntrinsicAnimationFrame(): frame index out of bounds" );
1068 if( mnCurrFrame != nCurrFrame )
1070 mnCurrFrame = nCurrFrame;
1071 mpCurrMtf = maAnimationFrames[ mnCurrFrame ].mpMtf;
1072 mbForceUpdate = true;
1075 return true;
1078 // hyperlink support
1079 void DrawShape::prepareHyperlinkIndices() const
1081 if ( !maHyperlinkIndices.empty())
1083 maHyperlinkIndices.clear();
1084 maHyperlinkRegions.clear();
1087 sal_Int32 nIndex = 0;
1088 for ( MetaAction * pCurrAct = mpCurrMtf->FirstAction();
1089 pCurrAct != 0; pCurrAct = mpCurrMtf->NextAction() )
1091 if (pCurrAct->GetType() == META_COMMENT_ACTION) {
1092 MetaCommentAction * pAct =
1093 static_cast<MetaCommentAction *>(pCurrAct);
1094 // skip comment if not a special XTEXT comment
1095 if (pAct->GetComment().CompareIgnoreCaseToAscii(
1096 RTL_CONSTASCII_STRINGPARAM("FIELD_SEQ_BEGIN") ) ==
1097 COMPARE_EQUAL &&
1098 // e.g. date field doesn't have data!
1099 // currently assuming that only url field, this is
1100 // somehow fragile! xxx todo if possible
1101 pAct->GetData() != 0 &&
1102 pAct->GetDataSize() > 0)
1104 if (!maHyperlinkIndices.empty() &&
1105 maHyperlinkIndices.back().second == -1) {
1106 OSL_ENSURE( false, "### pending FIELD_SEQ_END!" );
1107 maHyperlinkIndices.pop_back();
1108 maHyperlinkRegions.pop_back();
1110 maHyperlinkIndices.push_back(
1111 HyperlinkIndexPair( nIndex + 1,
1112 -1 /* to be filled below */ ) );
1113 maHyperlinkRegions.push_back(
1114 HyperlinkRegion(
1115 basegfx::B2DRectangle(),
1116 rtl::OUString(
1117 reinterpret_cast<sal_Unicode const*>(
1118 pAct->GetData()),
1119 pAct->GetDataSize() / sizeof(sal_Unicode) )
1120 ) );
1122 else if (pAct->GetComment().CompareIgnoreCaseToAscii(
1123 RTL_CONSTASCII_STRINGPARAM("FIELD_SEQ_END")) ==
1124 COMPARE_EQUAL &&
1125 // pending end is expected:
1126 !maHyperlinkIndices.empty() &&
1127 maHyperlinkIndices.back().second == -1)
1129 maHyperlinkIndices.back().second = nIndex;
1131 ++nIndex;
1133 else
1134 nIndex += getNextActionOffset(pCurrAct);
1136 if (!maHyperlinkIndices.empty() &&
1137 maHyperlinkIndices.back().second == -1) {
1138 OSL_ENSURE( false, "### pending FIELD_SEQ_END!" );
1139 maHyperlinkIndices.pop_back();
1140 maHyperlinkRegions.pop_back();
1142 OSL_ASSERT( maHyperlinkIndices.size() == maHyperlinkRegions.size());
1145 bool DrawShape::hasHyperlinks() const
1147 return ! maHyperlinkRegions.empty();
1150 HyperlinkArea::HyperlinkRegions DrawShape::getHyperlinkRegions() const
1152 OSL_ASSERT( !maViewShapes.empty() );
1154 if( !isVisible() )
1155 return HyperlinkArea::HyperlinkRegions();
1157 // late init, determine regions:
1158 if( !maHyperlinkRegions.empty() &&
1159 !maViewShapes.empty() &&
1160 // region already inited?
1161 maHyperlinkRegions.front().first.getWidth() == 0 &&
1162 maHyperlinkRegions.front().first.getHeight() == 0 &&
1163 maHyperlinkRegions.size() == maHyperlinkIndices.size() )
1165 // TODO(Q2): Although this _is_ currently
1166 // view-agnostic, it might not stay like that.
1167 ViewShapeSharedPtr const& pViewShape = maViewShapes.front();
1168 cppcanvas::CanvasSharedPtr const pCanvas(
1169 pViewShape->getViewLayer()->getCanvas() );
1171 // reuse Renderer of first view shape:
1172 cppcanvas::RendererSharedPtr const pRenderer(
1173 pViewShape->getRenderer(
1174 pCanvas, mpCurrMtf, mpAttributeLayer ) );
1176 OSL_ASSERT( pRenderer );
1178 if (pRenderer)
1180 basegfx::B2DHomMatrix const aOldTransform(
1181 pCanvas->getTransformation() );
1182 basegfx::B2DHomMatrix aTransform;
1183 pCanvas->setTransformation( aTransform /* empty */ );
1185 comphelper::ScopeGuard const resetOldTransformation(
1186 boost::bind( &cppcanvas::Canvas::setTransformation,
1187 pCanvas.get(),
1188 boost::cref(aOldTransform) ));
1190 aTransform.scale( maBounds.getWidth(),
1191 maBounds.getHeight() );
1192 pRenderer->setTransformation( aTransform );
1193 pRenderer->setClip();
1195 for( std::size_t pos = maHyperlinkRegions.size(); pos--; )
1197 // get region:
1198 HyperlinkIndexPair const& rIndices = maHyperlinkIndices[pos];
1199 basegfx::B2DRectangle const region(
1200 pRenderer->getSubsetArea( rIndices.first,
1201 rIndices.second ));
1202 maHyperlinkRegions[pos].first = region;
1207 // shift shape-relative hyperlink regions to
1208 // slide-absolute position
1210 HyperlinkRegions aTranslatedRegions;
1211 const basegfx::B2DPoint& rOffset(getBounds().getMinimum());
1212 HyperlinkRegions::const_iterator aIter( maHyperlinkRegions.begin() );
1213 HyperlinkRegions::const_iterator const aEnd ( maHyperlinkRegions.end() );
1214 while( aIter != aEnd )
1216 basegfx::B2DRange const& relRegion( aIter->first );
1217 aTranslatedRegions.push_back(
1218 std::make_pair(
1219 basegfx::B2DRange(
1220 relRegion.getMinimum() + rOffset,
1221 relRegion.getMaximum() + rOffset),
1222 aIter->second) );
1223 ++aIter;
1226 return aTranslatedRegions;
1229 double DrawShape::getHyperlinkPriority() const
1231 return getPriority();
1235 // AnimatableShape methods
1236 // ======================================================
1238 void DrawShape::enterAnimationMode()
1240 OSL_ENSURE( !maViewShapes.empty(),
1241 "DrawShape::enterAnimationMode(): called on DrawShape without views" );
1243 if( mnIsAnimatedCount == 0 )
1245 // notify all ViewShapes, by calling their enterAnimationMode method.
1246 // We're now entering animation mode
1247 ::std::for_each( maViewShapes.begin(),
1248 maViewShapes.end(),
1249 ::boost::mem_fn( &ViewShape::enterAnimationMode ) );
1252 ++mnIsAnimatedCount;
1255 void DrawShape::leaveAnimationMode()
1257 OSL_ENSURE( !maViewShapes.empty(),
1258 "DrawShape::leaveAnimationMode(): called on DrawShape without views" );
1260 --mnIsAnimatedCount;
1262 if( mnIsAnimatedCount == 0 )
1264 // notify all ViewShapes, by calling their leaveAnimationMode method.
1265 // we're now leaving animation mode
1266 ::std::for_each( maViewShapes.begin(),
1267 maViewShapes.end(),
1268 ::boost::mem_fn( &ViewShape::leaveAnimationMode ) );
1273 // AttributableShape methods
1274 // ======================================================
1276 ShapeAttributeLayerSharedPtr DrawShape::createAttributeLayer()
1278 // create new layer, with last as its new child
1279 mpAttributeLayer.reset( new ShapeAttributeLayer( mpAttributeLayer ) );
1281 // Update the local state ids to reflect those of the new layer.
1282 updateStateIds();
1284 return mpAttributeLayer;
1287 bool DrawShape::revokeAttributeLayer( const ShapeAttributeLayerSharedPtr& rLayer )
1289 if( !mpAttributeLayer )
1290 return false; // no layers
1292 if( mpAttributeLayer == rLayer )
1294 // it's the toplevel layer
1295 mpAttributeLayer = mpAttributeLayer->getChildLayer();
1297 // force content redraw, all state variables have
1298 // possibly changed
1299 mbAttributeLayerRevoked = true;
1301 return true;
1303 else
1305 // pass on to the layer, to try its children
1306 return mpAttributeLayer->revokeChildLayer( rLayer );
1310 ShapeAttributeLayerSharedPtr DrawShape::getTopmostAttributeLayer() const
1312 return mpAttributeLayer;
1315 void DrawShape::setVisibility( bool bVisible )
1317 if( mbIsVisible != bVisible )
1319 mbIsVisible = bVisible;
1320 mbForceUpdate = true;
1324 const DocTreeNodeSupplier& DrawShape::getTreeNodeSupplier() const
1326 return *this;
1329 DocTreeNodeSupplier& DrawShape::getTreeNodeSupplier()
1331 return *this;
1334 DocTreeNode DrawShape::getSubsetNode() const
1336 ensureVerboseMtfComments();
1338 // forward to delegate
1339 return maSubsetting.getSubsetNode();
1342 AttributableShapeSharedPtr DrawShape::getSubset( const DocTreeNode& rTreeNode ) const
1344 ENSURE_OR_THROW( (mnCurrMtfLoadFlags & MTF_LOAD_VERBOSE_COMMENTS) != 0,
1345 "DrawShape::getSubset(): subset query on shape with apparently no subsets" );
1347 // forward to delegate
1348 return maSubsetting.getSubsetShape( rTreeNode );
1351 bool DrawShape::createSubset( AttributableShapeSharedPtr& o_rSubset,
1352 const DocTreeNode& rTreeNode )
1354 ENSURE_OR_THROW( (mnCurrMtfLoadFlags & MTF_LOAD_VERBOSE_COMMENTS) != 0,
1355 "DrawShape::createSubset(): subset query on shape with apparently no subsets" );
1357 // subset shape already created for this DocTreeNode?
1358 AttributableShapeSharedPtr pSubset( maSubsetting.getSubsetShape( rTreeNode ) );
1360 // when true, this method has created a new subset
1361 // DrawShape
1362 bool bNewlyCreated( false );
1364 if( pSubset )
1366 o_rSubset = pSubset;
1368 // reusing existing subset
1370 else
1372 // not yet created, init entry
1373 o_rSubset.reset( new DrawShape( *this,
1374 rTreeNode,
1375 // TODO(Q3): That's a
1376 // hack. We assume
1377 // that start and end
1378 // index will always
1379 // be less than 65535
1380 mnPriority +
1381 rTreeNode.getStartIndex()/double(SAL_MAX_INT16) ));
1383 bNewlyCreated = true; // subset newly created
1386 // always register shape at DrawShapeSubsetting, to keep
1387 // refcount up-to-date
1388 maSubsetting.addSubsetShape( o_rSubset );
1390 // flush bounds cache
1391 maCurrentShapeUnitBounds.reset();
1393 return bNewlyCreated;
1396 bool DrawShape::revokeSubset( const AttributableShapeSharedPtr& rShape )
1398 ENSURE_OR_THROW( (mnCurrMtfLoadFlags & MTF_LOAD_VERBOSE_COMMENTS) != 0,
1399 "DrawShape::createSubset(): subset query on shape with apparently no subsets" );
1401 // flush bounds cache
1402 maCurrentShapeUnitBounds.reset();
1404 // forward to delegate
1405 if( maSubsetting.revokeSubsetShape( rShape ) )
1407 // force redraw, our content has possibly changed (as
1408 // one of the subsets now display within our shape
1409 // again).
1410 mbForceUpdate = true;
1412 // #i47428# TEMP FIX: synchronize visibility of subset
1413 // with parent.
1415 // TODO(F3): Remove here, and implement
1416 // TEXT_ONLY/BACKGROUND_ONLY with the proverbial
1417 // additional level of indirection: create a
1418 // persistent subset, containing all text/only the
1419 // background respectively. From _that_ object,
1420 // generate the temporary character subset shapes.
1421 const ShapeAttributeLayerSharedPtr& rAttrLayer(
1422 rShape->getTopmostAttributeLayer() );
1423 if( rAttrLayer &&
1424 rAttrLayer->isVisibilityValid() &&
1425 rAttrLayer->getVisibility() != isVisible() )
1427 const bool bVisibility( rAttrLayer->getVisibility() );
1429 // visibilities differ - adjust ours, then
1430 if( mpAttributeLayer )
1431 mpAttributeLayer->setVisibility( bVisibility );
1432 else
1433 mbIsVisible = bVisibility;
1436 // END TEMP FIX
1438 return true;
1441 return false;
1444 sal_Int32 DrawShape::getNumberOfTreeNodes( DocTreeNode::NodeType eNodeType ) const // throw ShapeLoadFailedException
1446 ensureVerboseMtfComments();
1448 return maSubsetting.getNumberOfTreeNodes( eNodeType );
1451 DocTreeNode DrawShape::getTreeNode( sal_Int32 nNodeIndex,
1452 DocTreeNode::NodeType eNodeType ) const // throw ShapeLoadFailedException
1454 ensureVerboseMtfComments();
1456 if ( hasHyperlinks())
1458 prepareHyperlinkIndices();
1461 return maSubsetting.getTreeNode( nNodeIndex, eNodeType );
1464 sal_Int32 DrawShape::getNumberOfSubsetTreeNodes ( const DocTreeNode& rParentNode,
1465 DocTreeNode::NodeType eNodeType ) const // throw ShapeLoadFailedException
1467 ensureVerboseMtfComments();
1469 return maSubsetting.getNumberOfSubsetTreeNodes( rParentNode, eNodeType );
1472 DocTreeNode DrawShape::getSubsetTreeNode( const DocTreeNode& rParentNode,
1473 sal_Int32 nNodeIndex,
1474 DocTreeNode::NodeType eNodeType ) const // throw ShapeLoadFailedException
1476 ensureVerboseMtfComments();
1478 return maSubsetting.getSubsetTreeNode( rParentNode, nNodeIndex, eNodeType );