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