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_svx.hxx" 26 #include <svx/sdr/contact/viewobjectcontact.hxx> 27 #include <svx/sdr/contact/viewcontact.hxx> 28 #include <svx/sdr/contact/objectcontact.hxx> 29 #include <svx/sdr/contact/displayinfo.hxx> 30 #include <vcl/region.hxx> 31 #include <svx/sdr/animation/objectanimator.hxx> 32 #include <svx/sdr/animation/animationstate.hxx> 33 #include <svx/sdr/contact/viewobjectcontactredirector.hxx> 34 #include <basegfx/numeric/ftools.hxx> 35 #include <basegfx/color/bcolor.hxx> 36 #include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx> 37 #include <basegfx/tools/canvastools.hxx> 38 #include <drawinglayer/primitive2d/animatedprimitive2d.hxx> 39 #include <drawinglayer/processor2d/baseprocessor2d.hxx> 40 #include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx> 41 #include <svx/sdr/contact/viewobjectcontactredirector.hxx> 42 43 ////////////////////////////////////////////////////////////////////////////// 44 45 using namespace com::sun::star; 46 47 ////////////////////////////////////////////////////////////////////////////// 48 49 namespace 50 { 51 // animated extractor 52 53 // Necessary to filter a sequence of animated primitives from 54 // a sequence of primitives to find out if animated or not. The decision for 55 // what to decompose is hard-coded and only done for knowingly animated primitives 56 // to not decompose too deeply and unnecessarily. This implies that the list 57 // which is view-specific needs to be expanded by hand when new animated objects 58 // are added. This may eventually be changed to a dynamically configurable approach 59 // if necessary. 60 class AnimatedExtractingProcessor2D : public drawinglayer::processor2d::BaseProcessor2D 61 { 62 protected: 63 // the found animated primitives 64 drawinglayer::primitive2d::Primitive2DSequence maPrimitive2DSequence; 65 66 // bitfield 67 // text animation allowed? 68 unsigned mbTextAnimationAllowed : 1; 69 70 // graphic animation allowed? 71 unsigned mbGraphicAnimationAllowed : 1; 72 73 // as tooling, the process() implementation takes over API handling and calls this 74 // virtual render method when the primitive implementation is BasePrimitive2D-based. 75 virtual void processBasePrimitive2D(const drawinglayer::primitive2d::BasePrimitive2D& rCandidate); 76 77 public: 78 AnimatedExtractingProcessor2D( 79 const drawinglayer::geometry::ViewInformation2D& rViewInformation, 80 bool bTextAnimationAllowed, 81 bool bGraphicAnimationAllowed); 82 virtual ~AnimatedExtractingProcessor2D(); 83 84 // data access getPrimitive2DSequence() const85 const drawinglayer::primitive2d::Primitive2DSequence& getPrimitive2DSequence() const { return maPrimitive2DSequence; } isTextAnimationAllowed() const86 bool isTextAnimationAllowed() const { return mbTextAnimationAllowed; } isGraphicAnimationAllowed() const87 bool isGraphicAnimationAllowed() const { return mbGraphicAnimationAllowed; } 88 }; 89 AnimatedExtractingProcessor2D(const drawinglayer::geometry::ViewInformation2D & rViewInformation,bool bTextAnimationAllowed,bool bGraphicAnimationAllowed)90 AnimatedExtractingProcessor2D::AnimatedExtractingProcessor2D( 91 const drawinglayer::geometry::ViewInformation2D& rViewInformation, 92 bool bTextAnimationAllowed, 93 bool bGraphicAnimationAllowed) 94 : drawinglayer::processor2d::BaseProcessor2D(rViewInformation), 95 maPrimitive2DSequence(), 96 mbTextAnimationAllowed(bTextAnimationAllowed), 97 mbGraphicAnimationAllowed(bGraphicAnimationAllowed) 98 { 99 } 100 ~AnimatedExtractingProcessor2D()101 AnimatedExtractingProcessor2D::~AnimatedExtractingProcessor2D() 102 { 103 } 104 processBasePrimitive2D(const drawinglayer::primitive2d::BasePrimitive2D & rCandidate)105 void AnimatedExtractingProcessor2D::processBasePrimitive2D(const drawinglayer::primitive2d::BasePrimitive2D& rCandidate) 106 { 107 // known implementation, access directly 108 switch(rCandidate.getPrimitive2DID()) 109 { 110 // add and accept animated primitives directly, no need to decompose 111 case PRIMITIVE2D_ID_ANIMATEDSWITCHPRIMITIVE2D : 112 case PRIMITIVE2D_ID_ANIMATEDBLINKPRIMITIVE2D : 113 case PRIMITIVE2D_ID_ANIMATEDINTERPOLATEPRIMITIVE2D : 114 { 115 const drawinglayer::primitive2d::AnimatedSwitchPrimitive2D& rSwitchPrimitive = static_cast< const drawinglayer::primitive2d::AnimatedSwitchPrimitive2D& >(rCandidate); 116 117 if((rSwitchPrimitive.isTextAnimation() && isTextAnimationAllowed()) 118 || (rSwitchPrimitive.isGraphicAnimation() && isGraphicAnimationAllowed())) 119 { 120 const drawinglayer::primitive2d::Primitive2DReference xReference(const_cast< drawinglayer::primitive2d::BasePrimitive2D* >(&rCandidate)); 121 drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(maPrimitive2DSequence, xReference); 122 } 123 break; 124 } 125 126 // decompose animated gifs where SdrGrafPrimitive2D produces a GraphicPrimitive2D 127 // which then produces the animation infos (all when used/needed) 128 case PRIMITIVE2D_ID_SDRGRAFPRIMITIVE2D : 129 case PRIMITIVE2D_ID_GRAPHICPRIMITIVE2D : 130 131 // decompose SdrObjects with evtl. animated text 132 case PRIMITIVE2D_ID_SDRCAPTIONPRIMITIVE2D : 133 case PRIMITIVE2D_ID_SDRCONNECTORPRIMITIVE2D : 134 case PRIMITIVE2D_ID_SDRCUSTOMSHAPEPRIMITIVE2D : 135 case PRIMITIVE2D_ID_SDRELLIPSEPRIMITIVE2D : 136 case PRIMITIVE2D_ID_SDRELLIPSESEGMENTPRIMITIVE2D : 137 case PRIMITIVE2D_ID_SDRMEASUREPRIMITIVE2D : 138 case PRIMITIVE2D_ID_SDRPATHPRIMITIVE2D : 139 case PRIMITIVE2D_ID_SDRRECTANGLEPRIMITIVE2D : 140 141 // #121194# With Graphic as Bitmap FillStyle, also check 142 // for primitives filled with animated graphics 143 case PRIMITIVE2D_ID_POLYPOLYGONGRAPHICPRIMITIVE2D: 144 case PRIMITIVE2D_ID_FILLGRAPHICPRIMITIVE2D: 145 case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D: 146 147 // decompose evtl. animated text contained in MaskPrimitive2D 148 // or group rimitives 149 case PRIMITIVE2D_ID_MASKPRIMITIVE2D : 150 case PRIMITIVE2D_ID_GROUPPRIMITIVE2D : 151 { 152 process(rCandidate.get2DDecomposition(getViewInformation2D())); 153 break; 154 } 155 156 default : 157 { 158 // nothing to do for the rest 159 break; 160 } 161 } 162 } 163 } // end of anonymous namespace 164 165 ////////////////////////////////////////////////////////////////////////////// 166 167 namespace sdr 168 { 169 namespace contact 170 { ViewObjectContact(ObjectContact & rObjectContact,ViewContact & rViewContact)171 ViewObjectContact::ViewObjectContact(ObjectContact& rObjectContact, ViewContact& rViewContact) 172 : mrObjectContact(rObjectContact), 173 mrViewContact(rViewContact), 174 maObjectRange(), 175 mxPrimitive2DSequence(), 176 mpPrimitiveAnimation(0), 177 mbLazyInvalidate(false) 178 { 179 // make the ViewContact remember me 180 mrViewContact.AddViewObjectContact(*this); 181 182 // make the ObjectContact remember me 183 mrObjectContact.AddViewObjectContact(*this); 184 } 185 ~ViewObjectContact()186 ViewObjectContact::~ViewObjectContact() 187 { 188 // invalidate in view 189 if(!maObjectRange.isEmpty()) 190 { 191 GetObjectContact().InvalidatePartOfView(maObjectRange); 192 } 193 194 // delete PrimitiveAnimation 195 if(mpPrimitiveAnimation) 196 { 197 delete mpPrimitiveAnimation; 198 mpPrimitiveAnimation = 0; 199 } 200 201 // take care of remebered ObjectContact. Remove from 202 // OC first. The VC removal (below) CAN trigger a StopGettingViewed() 203 // which (depending of it's implementation) may destroy other OCs. This 204 // can trigger the deletion of the helper OC of a page visualising object 205 // which IS the OC of this object. Eventually StopGettingViewed() needs 206 // to get asynchron later 207 GetObjectContact().RemoveViewObjectContact(*this); 208 209 // take care of remebered ViewContact 210 GetViewContact().RemoveViewObjectContact(*this); 211 } 212 getObjectRange() const213 const basegfx::B2DRange& ViewObjectContact::getObjectRange() const 214 { 215 if(maObjectRange.isEmpty()) 216 { 217 // if range is not computed (new or LazyInvalidate objects), force it 218 const DisplayInfo aDisplayInfo; 219 const drawinglayer::primitive2d::Primitive2DSequence xSequence(getPrimitive2DSequence(aDisplayInfo)); 220 221 if(xSequence.hasElements()) 222 { 223 const drawinglayer::geometry::ViewInformation2D& rViewInformation2D(GetObjectContact().getViewInformation2D()); 224 const_cast< ViewObjectContact* >(this)->maObjectRange = 225 drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence(xSequence, rViewInformation2D); 226 } 227 } 228 229 return maObjectRange; 230 } 231 ActionChanged()232 void ViewObjectContact::ActionChanged() 233 { 234 if(!mbLazyInvalidate) 235 { 236 // set local flag 237 mbLazyInvalidate = true; 238 239 // force ObjectRange 240 getObjectRange(); 241 242 if(!maObjectRange.isEmpty()) 243 { 244 // invalidate current valid range 245 GetObjectContact().InvalidatePartOfView(maObjectRange); 246 247 // reset ObjectRange, it needs to be recalculated 248 maObjectRange.reset(); 249 } 250 251 // register at OC for lazy invalidate 252 GetObjectContact().setLazyInvalidate(*this); 253 } 254 } 255 triggerLazyInvalidate()256 void ViewObjectContact::triggerLazyInvalidate() 257 { 258 if(mbLazyInvalidate) 259 { 260 // reset flag 261 mbLazyInvalidate = false; 262 263 // force ObjectRange 264 getObjectRange(); 265 266 if(!maObjectRange.isEmpty()) 267 { 268 // invalidate current valid range 269 GetObjectContact().InvalidatePartOfView(maObjectRange); 270 } 271 } 272 } 273 274 // Take some action when new objects are inserted ActionChildInserted(ViewContact & rChild)275 void ViewObjectContact::ActionChildInserted(ViewContact& rChild) 276 { 277 // force creation of the new VOC and trigger it's refresh, so it 278 // will take part in LazyInvalidate immediately 279 rChild.GetViewObjectContact(GetObjectContact()).ActionChanged(); 280 281 // forward action to ObjectContact 282 // const ViewObjectContact& rChildVOC = rChild.GetViewObjectContact(GetObjectContact()); 283 // GetObjectContact().InvalidatePartOfView(rChildVOC.getObjectRange()); 284 } 285 checkForPrimitive2DAnimations()286 void ViewObjectContact::checkForPrimitive2DAnimations() 287 { 288 // remove old one 289 if(mpPrimitiveAnimation) 290 { 291 delete mpPrimitiveAnimation; 292 mpPrimitiveAnimation = 0; 293 } 294 295 // check for animated primitives 296 if(mxPrimitive2DSequence.hasElements()) 297 { 298 const bool bTextAnimationAllowed(GetObjectContact().IsTextAnimationAllowed()); 299 const bool bGraphicAnimationAllowed(GetObjectContact().IsGraphicAnimationAllowed()); 300 301 if(bTextAnimationAllowed || bGraphicAnimationAllowed) 302 { 303 AnimatedExtractingProcessor2D aAnimatedExtractor(GetObjectContact().getViewInformation2D(), 304 bTextAnimationAllowed, bGraphicAnimationAllowed); 305 aAnimatedExtractor.process(mxPrimitive2DSequence); 306 307 if(aAnimatedExtractor.getPrimitive2DSequence().hasElements()) 308 { 309 // dervied primitiveList is animated, setup new PrimitiveAnimation 310 mpPrimitiveAnimation = new sdr::animation::PrimitiveAnimation(*this, aAnimatedExtractor.getPrimitive2DSequence()); 311 } 312 } 313 } 314 } 315 createPrimitive2DSequence(const DisplayInfo & rDisplayInfo) const316 drawinglayer::primitive2d::Primitive2DSequence ViewObjectContact::createPrimitive2DSequence(const DisplayInfo& rDisplayInfo) const 317 { 318 // get the view-independent Primitive from the viewContact 319 drawinglayer::primitive2d::Primitive2DSequence xRetval(GetViewContact().getViewIndependentPrimitive2DSequence()); 320 321 if(xRetval.hasElements()) 322 { 323 // handle GluePoint 324 if(!GetObjectContact().isOutputToPrinter() && GetObjectContact().AreGluePointsVisible()) 325 { 326 const drawinglayer::primitive2d::Primitive2DSequence xGlue(GetViewContact().createGluePointPrimitive2DSequence()); 327 328 if(xGlue.hasElements()) 329 { 330 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(xRetval, xGlue); 331 } 332 } 333 334 // handle ghosted 335 if(isPrimitiveGhosted(rDisplayInfo)) 336 { 337 const basegfx::BColor aRGBWhite(1.0, 1.0, 1.0); 338 const basegfx::BColorModifierSharedPtr aBColorModifier( 339 new basegfx::BColorModifier_interpolate( 340 aRGBWhite, 341 0.5)); 342 const drawinglayer::primitive2d::Primitive2DReference xReference( 343 new drawinglayer::primitive2d::ModifiedColorPrimitive2D( 344 xRetval, 345 aBColorModifier)); 346 347 xRetval = drawinglayer::primitive2d::Primitive2DSequence(&xReference, 1); 348 } 349 } 350 351 return xRetval; 352 } 353 getPrimitive2DSequence(const DisplayInfo & rDisplayInfo) const354 drawinglayer::primitive2d::Primitive2DSequence ViewObjectContact::getPrimitive2DSequence(const DisplayInfo& rDisplayInfo) const 355 { 356 drawinglayer::primitive2d::Primitive2DSequence xNewPrimitiveSequence; 357 358 // take care of redirectors and create new list 359 ViewObjectContactRedirector* pRedirector = GetObjectContact().GetViewObjectContactRedirector(); 360 361 if(pRedirector) 362 { 363 xNewPrimitiveSequence = pRedirector->createRedirectedPrimitive2DSequence(*this, rDisplayInfo); 364 } 365 else 366 { 367 xNewPrimitiveSequence = createPrimitive2DSequence(rDisplayInfo); 368 } 369 370 // local up-to-date checks. New list different from local one? 371 if(!drawinglayer::primitive2d::arePrimitive2DSequencesEqual(mxPrimitive2DSequence, xNewPrimitiveSequence)) 372 { 373 // has changed, copy content 374 const_cast< ViewObjectContact* >(this)->mxPrimitive2DSequence = xNewPrimitiveSequence; 375 376 // check for animated stuff 377 const_cast< ViewObjectContact* >(this)->checkForPrimitive2DAnimations(); 378 379 // always update object range when PrimitiveSequence changes 380 const drawinglayer::geometry::ViewInformation2D& rViewInformation2D(GetObjectContact().getViewInformation2D()); 381 const_cast< ViewObjectContact* >(this)->maObjectRange = 382 drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence(mxPrimitive2DSequence, rViewInformation2D); 383 } 384 385 // return current Primitive2DSequence 386 return mxPrimitive2DSequence; 387 } 388 isPrimitiveVisible(const DisplayInfo &) const389 bool ViewObjectContact::isPrimitiveVisible(const DisplayInfo& /*rDisplayInfo*/) const 390 { 391 // default: always visible 392 return true; 393 } 394 isPrimitiveGhosted(const DisplayInfo & rDisplayInfo) const395 bool ViewObjectContact::isPrimitiveGhosted(const DisplayInfo& rDisplayInfo) const 396 { 397 // default: standard check 398 return (GetObjectContact().DoVisualizeEnteredGroup() && !GetObjectContact().isOutputToPrinter() && rDisplayInfo.IsGhostedDrawModeActive()); 399 } 400 getPrimitive2DSequenceHierarchy(DisplayInfo & rDisplayInfo) const401 drawinglayer::primitive2d::Primitive2DSequence ViewObjectContact::getPrimitive2DSequenceHierarchy(DisplayInfo& rDisplayInfo) const 402 { 403 drawinglayer::primitive2d::Primitive2DSequence xRetval; 404 405 // check model-view visibility 406 if(isPrimitiveVisible(rDisplayInfo)) 407 { 408 xRetval = getPrimitive2DSequence(rDisplayInfo); 409 410 if(xRetval.hasElements()) 411 { 412 // get ranges 413 const drawinglayer::geometry::ViewInformation2D& rViewInformation2D(GetObjectContact().getViewInformation2D()); 414 const basegfx::B2DRange aObjectRange(drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence(xRetval, rViewInformation2D)); 415 const basegfx::B2DRange aViewRange(rViewInformation2D.getViewport()); 416 417 // check geometrical visibility 418 if(!aViewRange.isEmpty() && !aViewRange.overlaps(aObjectRange)) 419 { 420 // not visible, release 421 xRetval.realloc(0); 422 } 423 } 424 } 425 426 return xRetval; 427 } 428 getPrimitive2DSequenceSubHierarchy(DisplayInfo & rDisplayInfo) const429 drawinglayer::primitive2d::Primitive2DSequence ViewObjectContact::getPrimitive2DSequenceSubHierarchy(DisplayInfo& rDisplayInfo) const 430 { 431 const sal_uInt32 nSubHierarchyCount(GetViewContact().GetObjectCount()); 432 drawinglayer::primitive2d::Primitive2DSequence xSeqRetval; 433 434 for(sal_uInt32 a(0); a < nSubHierarchyCount; a++) 435 { 436 const ViewObjectContact& rCandidate(GetViewContact().GetViewContact(a).GetViewObjectContact(GetObjectContact())); 437 438 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(xSeqRetval, rCandidate.getPrimitive2DSequenceHierarchy(rDisplayInfo)); 439 } 440 441 return xSeqRetval; 442 } 443 } // end of namespace contact 444 } // end of namespace sdr 445 446 ////////////////////////////////////////////////////////////////////////////// 447 // eof 448