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