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