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