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