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