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 85 const drawinglayer::primitive2d::Primitive2DSequence& getPrimitive2DSequence() const { return maPrimitive2DSequence; } 86 bool isTextAnimationAllowed() const { return mbTextAnimationAllowed; } 87 bool isGraphicAnimationAllowed() const { return mbGraphicAnimationAllowed; } 88 }; 89 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 101 AnimatedExtractingProcessor2D::~AnimatedExtractingProcessor2D() 102 { 103 } 104 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 { 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 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 213 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 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 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 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 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 316 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::BColorModifier aBColorModifier(aRGBWhite, 0.5, basegfx::BCOLORMODIFYMODE_INTERPOLATE); 339 const drawinglayer::primitive2d::Primitive2DReference xReference(new drawinglayer::primitive2d::ModifiedColorPrimitive2D(xRetval, aBColorModifier)); 340 xRetval = drawinglayer::primitive2d::Primitive2DSequence(&xReference, 1); 341 } 342 } 343 344 return xRetval; 345 } 346 347 drawinglayer::primitive2d::Primitive2DSequence ViewObjectContact::getPrimitive2DSequence(const DisplayInfo& rDisplayInfo) const 348 { 349 drawinglayer::primitive2d::Primitive2DSequence xNewPrimitiveSequence; 350 351 // take care of redirectors and create new list 352 ViewObjectContactRedirector* pRedirector = GetObjectContact().GetViewObjectContactRedirector(); 353 354 if(pRedirector) 355 { 356 xNewPrimitiveSequence = pRedirector->createRedirectedPrimitive2DSequence(*this, rDisplayInfo); 357 } 358 else 359 { 360 xNewPrimitiveSequence = createPrimitive2DSequence(rDisplayInfo); 361 } 362 363 // local up-to-date checks. New list different from local one? 364 if(!drawinglayer::primitive2d::arePrimitive2DSequencesEqual(mxPrimitive2DSequence, xNewPrimitiveSequence)) 365 { 366 // has changed, copy content 367 const_cast< ViewObjectContact* >(this)->mxPrimitive2DSequence = xNewPrimitiveSequence; 368 369 // check for animated stuff 370 const_cast< ViewObjectContact* >(this)->checkForPrimitive2DAnimations(); 371 372 // always update object range when PrimitiveSequence changes 373 const drawinglayer::geometry::ViewInformation2D& rViewInformation2D(GetObjectContact().getViewInformation2D()); 374 const_cast< ViewObjectContact* >(this)->maObjectRange = 375 drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence(mxPrimitive2DSequence, rViewInformation2D); 376 } 377 378 // return current Primitive2DSequence 379 return mxPrimitive2DSequence; 380 } 381 382 bool ViewObjectContact::isPrimitiveVisible(const DisplayInfo& /*rDisplayInfo*/) const 383 { 384 // default: always visible 385 return true; 386 } 387 388 bool ViewObjectContact::isPrimitiveGhosted(const DisplayInfo& rDisplayInfo) const 389 { 390 // default: standard check 391 return (GetObjectContact().DoVisualizeEnteredGroup() && !GetObjectContact().isOutputToPrinter() && rDisplayInfo.IsGhostedDrawModeActive()); 392 } 393 394 drawinglayer::primitive2d::Primitive2DSequence ViewObjectContact::getPrimitive2DSequenceHierarchy(DisplayInfo& rDisplayInfo) const 395 { 396 drawinglayer::primitive2d::Primitive2DSequence xRetval; 397 398 // check model-view visibility 399 if(isPrimitiveVisible(rDisplayInfo)) 400 { 401 xRetval = getPrimitive2DSequence(rDisplayInfo); 402 403 if(xRetval.hasElements()) 404 { 405 // get ranges 406 const drawinglayer::geometry::ViewInformation2D& rViewInformation2D(GetObjectContact().getViewInformation2D()); 407 const basegfx::B2DRange aObjectRange(drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence(xRetval, rViewInformation2D)); 408 const basegfx::B2DRange aViewRange(rViewInformation2D.getViewport()); 409 410 // check geometrical visibility 411 if(!aViewRange.isEmpty() && !aViewRange.overlaps(aObjectRange)) 412 { 413 // not visible, release 414 xRetval.realloc(0); 415 } 416 } 417 } 418 419 return xRetval; 420 } 421 422 drawinglayer::primitive2d::Primitive2DSequence ViewObjectContact::getPrimitive2DSequenceSubHierarchy(DisplayInfo& rDisplayInfo) const 423 { 424 const sal_uInt32 nSubHierarchyCount(GetViewContact().GetObjectCount()); 425 drawinglayer::primitive2d::Primitive2DSequence xSeqRetval; 426 427 for(sal_uInt32 a(0); a < nSubHierarchyCount; a++) 428 { 429 const ViewObjectContact& rCandidate(GetViewContact().GetViewContact(a).GetViewObjectContact(GetObjectContact())); 430 431 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(xSeqRetval, rCandidate.getPrimitive2DSequenceHierarchy(rDisplayInfo)); 432 } 433 434 return xSeqRetval; 435 } 436 } // end of namespace contact 437 } // end of namespace sdr 438 439 ////////////////////////////////////////////////////////////////////////////// 440 // eof 441