1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <svx/sdr/contact/viewobjectcontact.hxx>
21 #include <svx/sdr/contact/viewcontact.hxx>
22 #include <svx/sdr/contact/objectcontact.hxx>
23 #include <svx/sdr/contact/displayinfo.hxx>
24 #include <vcl/region.hxx>
25 #include <svx/sdr/animation/objectanimator.hxx>
26 #include <svx/sdr/animation/animationstate.hxx>
27 #include <svx/sdr/contact/viewobjectcontactredirector.hxx>
28 #include <basegfx/numeric/ftools.hxx>
29 #include <basegfx/color/bcolor.hxx>
30 #include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx>
31 #include <basegfx/tools/canvastools.hxx>
32 #include <drawinglayer/primitive2d/animatedprimitive2d.hxx>
33 #include <drawinglayer/processor2d/baseprocessor2d.hxx>
34 #include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
36 //////////////////////////////////////////////////////////////////////////////
38 using namespace com::sun::star
;
40 //////////////////////////////////////////////////////////////////////////////
46 // Necessary to filter a sequence of animated primitives from
47 // a sequence of primitives to find out if animated or not. The decision for
48 // what to decompose is hard-coded and only done for knowingly animated primitives
49 // to not decompose too deeply and unnecessarily. This implies that the list
50 // which is view-specific needs to be expanded by hand when new animated objects
51 // are added. This may eventually be changed to a dynamically configurable approach
53 class AnimatedExtractingProcessor2D
: public drawinglayer::processor2d::BaseProcessor2D
56 // the found animated primitives
57 drawinglayer::primitive2d::Primitive2DSequence maPrimitive2DSequence
;
60 // text animation allowed?
61 unsigned mbTextAnimationAllowed
: 1;
63 // graphic animation allowed?
64 unsigned mbGraphicAnimationAllowed
: 1;
66 // as tooling, the process() implementation takes over API handling and calls this
67 // virtual render method when the primitive implementation is BasePrimitive2D-based.
68 virtual void processBasePrimitive2D(const drawinglayer::primitive2d::BasePrimitive2D
& rCandidate
);
71 AnimatedExtractingProcessor2D(
72 const drawinglayer::geometry::ViewInformation2D
& rViewInformation
,
73 bool bTextAnimationAllowed
,
74 bool bGraphicAnimationAllowed
);
75 virtual ~AnimatedExtractingProcessor2D();
78 const drawinglayer::primitive2d::Primitive2DSequence
& getPrimitive2DSequence() const { return maPrimitive2DSequence
; }
79 bool isTextAnimationAllowed() const { return mbTextAnimationAllowed
; }
80 bool isGraphicAnimationAllowed() const { return mbGraphicAnimationAllowed
; }
83 AnimatedExtractingProcessor2D::AnimatedExtractingProcessor2D(
84 const drawinglayer::geometry::ViewInformation2D
& rViewInformation
,
85 bool bTextAnimationAllowed
,
86 bool bGraphicAnimationAllowed
)
87 : drawinglayer::processor2d::BaseProcessor2D(rViewInformation
),
88 maPrimitive2DSequence(),
89 mbTextAnimationAllowed(bTextAnimationAllowed
),
90 mbGraphicAnimationAllowed(bGraphicAnimationAllowed
)
94 AnimatedExtractingProcessor2D::~AnimatedExtractingProcessor2D()
98 void AnimatedExtractingProcessor2D::processBasePrimitive2D(const drawinglayer::primitive2d::BasePrimitive2D
& rCandidate
)
100 // known implementation, access directly
101 switch(rCandidate
.getPrimitive2DID())
103 // add and accept animated primitives directly, no need to decompose
104 case PRIMITIVE2D_ID_ANIMATEDSWITCHPRIMITIVE2D
:
105 case PRIMITIVE2D_ID_ANIMATEDBLINKPRIMITIVE2D
:
106 case PRIMITIVE2D_ID_ANIMATEDINTERPOLATEPRIMITIVE2D
:
108 const drawinglayer::primitive2d::AnimatedSwitchPrimitive2D
& rSwitchPrimitive
= static_cast< const drawinglayer::primitive2d::AnimatedSwitchPrimitive2D
& >(rCandidate
);
110 if((rSwitchPrimitive
.isTextAnimation() && isTextAnimationAllowed())
111 || (rSwitchPrimitive
.isGraphicAnimation() && isGraphicAnimationAllowed()))
113 const drawinglayer::primitive2d::Primitive2DReference
xReference(const_cast< drawinglayer::primitive2d::BasePrimitive2D
* >(&rCandidate
));
114 drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(maPrimitive2DSequence
, xReference
);
119 // decompose animated gifs where SdrGrafPrimitive2D produces a GraphicPrimitive2D
120 // which then produces the animation infos (all when used/needed)
121 case PRIMITIVE2D_ID_SDRGRAFPRIMITIVE2D
:
122 case PRIMITIVE2D_ID_GRAPHICPRIMITIVE2D
:
124 // decompose SdrObjects with evtl. animated text
125 case PRIMITIVE2D_ID_SDRCAPTIONPRIMITIVE2D
:
126 case PRIMITIVE2D_ID_SDRCONNECTORPRIMITIVE2D
:
127 case PRIMITIVE2D_ID_SDRCUSTOMSHAPEPRIMITIVE2D
:
128 case PRIMITIVE2D_ID_SDRELLIPSEPRIMITIVE2D
:
129 case PRIMITIVE2D_ID_SDRELLIPSESEGMENTPRIMITIVE2D
:
130 case PRIMITIVE2D_ID_SDRMEASUREPRIMITIVE2D
:
131 case PRIMITIVE2D_ID_SDRPATHPRIMITIVE2D
:
132 case PRIMITIVE2D_ID_SDRRECTANGLEPRIMITIVE2D
:
134 // decompose evtl. animated text contained in MaskPrimitive2D
135 // or group rimitives
136 case PRIMITIVE2D_ID_MASKPRIMITIVE2D
:
137 case PRIMITIVE2D_ID_GROUPPRIMITIVE2D
:
139 process(rCandidate
.get2DDecomposition(getViewInformation2D()));
145 // nothing to do for the rest
150 } // end of anonymous namespace
152 //////////////////////////////////////////////////////////////////////////////
158 ViewObjectContact::ViewObjectContact(ObjectContact
& rObjectContact
, ViewContact
& rViewContact
)
159 : mrObjectContact(rObjectContact
),
160 mrViewContact(rViewContact
),
162 mxPrimitive2DSequence(),
163 mpPrimitiveAnimation(0),
164 mbLazyInvalidate(false)
166 // make the ViewContact remember me
167 mrViewContact
.AddViewObjectContact(*this);
169 // make the ObjectContact remember me
170 mrObjectContact
.AddViewObjectContact(*this);
173 ViewObjectContact::~ViewObjectContact()
175 // invalidate in view
176 if(!maObjectRange
.isEmpty())
178 GetObjectContact().InvalidatePartOfView(maObjectRange
);
181 // delete PrimitiveAnimation
182 if(mpPrimitiveAnimation
)
184 delete mpPrimitiveAnimation
;
185 mpPrimitiveAnimation
= 0;
188 // take care of remebered ObjectContact. Remove from
189 // OC first. The VC removal (below) CAN trigger a StopGettingViewed()
190 // which (depending of it's implementation) may destroy other OCs. This
191 // can trigger the deletion of the helper OC of a page visualising object
192 // which IS the OC of this object. Eventually StopGettingViewed() needs
193 // to get asynchron later
194 GetObjectContact().RemoveViewObjectContact(*this);
196 // take care of remebered ViewContact
197 GetViewContact().RemoveViewObjectContact(*this);
200 const basegfx::B2DRange
& ViewObjectContact::getObjectRange() const
202 if(maObjectRange
.isEmpty())
204 // if range is not computed (new or LazyInvalidate objects), force it
205 const DisplayInfo aDisplayInfo
;
206 const drawinglayer::primitive2d::Primitive2DSequence
xSequence(getPrimitive2DSequence(aDisplayInfo
));
208 if(xSequence
.hasElements())
210 const drawinglayer::geometry::ViewInformation2D
& rViewInformation2D(GetObjectContact().getViewInformation2D());
211 const_cast< ViewObjectContact
* >(this)->maObjectRange
=
212 drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence(xSequence
, rViewInformation2D
);
216 return maObjectRange
;
219 void ViewObjectContact::ActionChanged()
221 if(!mbLazyInvalidate
)
224 mbLazyInvalidate
= true;
229 if(!maObjectRange
.isEmpty())
231 // invalidate current valid range
232 GetObjectContact().InvalidatePartOfView(maObjectRange
);
234 // reset ObjectRange, it needs to be recalculated
235 maObjectRange
.reset();
238 // register at OC for lazy invalidate
239 GetObjectContact().setLazyInvalidate(*this);
243 void ViewObjectContact::triggerLazyInvalidate()
248 mbLazyInvalidate
= false;
253 if(!maObjectRange
.isEmpty())
255 // invalidate current valid range
256 GetObjectContact().InvalidatePartOfView(maObjectRange
);
261 // Take some action when new objects are inserted
262 void ViewObjectContact::ActionChildInserted(ViewContact
& rChild
)
264 // force creation of the new VOC and trigger it's refresh, so it
265 // will take part in LazyInvalidate immediately
266 rChild
.GetViewObjectContact(GetObjectContact()).ActionChanged();
268 // forward action to ObjectContact
269 // const ViewObjectContact& rChildVOC = rChild.GetViewObjectContact(GetObjectContact());
270 // GetObjectContact().InvalidatePartOfView(rChildVOC.getObjectRange());
273 void ViewObjectContact::checkForPrimitive2DAnimations()
276 if(mpPrimitiveAnimation
)
278 delete mpPrimitiveAnimation
;
279 mpPrimitiveAnimation
= 0;
282 // check for animated primitives
283 if(mxPrimitive2DSequence
.hasElements())
285 const bool bTextAnimationAllowed(GetObjectContact().IsTextAnimationAllowed());
286 const bool bGraphicAnimationAllowed(GetObjectContact().IsGraphicAnimationAllowed());
288 if(bTextAnimationAllowed
|| bGraphicAnimationAllowed
)
290 AnimatedExtractingProcessor2D
aAnimatedExtractor(GetObjectContact().getViewInformation2D(),
291 bTextAnimationAllowed
, bGraphicAnimationAllowed
);
292 aAnimatedExtractor
.process(mxPrimitive2DSequence
);
294 if(aAnimatedExtractor
.getPrimitive2DSequence().hasElements())
296 // dervied primitiveList is animated, setup new PrimitiveAnimation
297 mpPrimitiveAnimation
= new sdr::animation::PrimitiveAnimation(*this, aAnimatedExtractor
.getPrimitive2DSequence());
303 drawinglayer::primitive2d::Primitive2DSequence
ViewObjectContact::createPrimitive2DSequence(const DisplayInfo
& rDisplayInfo
) const
305 // get the view-independent Primitive from the viewContact
306 drawinglayer::primitive2d::Primitive2DSequence
xRetval(GetViewContact().getViewIndependentPrimitive2DSequence());
308 if(xRetval
.hasElements())
311 if(!GetObjectContact().isOutputToPrinter() && GetObjectContact().AreGluePointsVisible())
313 const drawinglayer::primitive2d::Primitive2DSequence
xGlue(GetViewContact().createGluePointPrimitive2DSequence());
315 if(xGlue
.hasElements())
317 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(xRetval
, xGlue
);
322 if(isPrimitiveGhosted(rDisplayInfo
))
324 const basegfx::BColor
aRGBWhite(1.0, 1.0, 1.0);
325 const basegfx::BColorModifier
aBColorModifier(aRGBWhite
, 0.5, basegfx::BCOLORMODIFYMODE_INTERPOLATE
);
326 const drawinglayer::primitive2d::Primitive2DReference
xReference(new drawinglayer::primitive2d::ModifiedColorPrimitive2D(xRetval
, aBColorModifier
));
327 xRetval
= drawinglayer::primitive2d::Primitive2DSequence(&xReference
, 1);
334 drawinglayer::primitive2d::Primitive2DSequence
ViewObjectContact::getPrimitive2DSequence(const DisplayInfo
& rDisplayInfo
) const
336 drawinglayer::primitive2d::Primitive2DSequence xNewPrimitiveSequence
;
338 // take care of redirectors and create new list
339 ViewObjectContactRedirector
* pRedirector
= GetObjectContact().GetViewObjectContactRedirector();
343 xNewPrimitiveSequence
= pRedirector
->createRedirectedPrimitive2DSequence(*this, rDisplayInfo
);
347 xNewPrimitiveSequence
= createPrimitive2DSequence(rDisplayInfo
);
350 // local up-to-date checks. New list different from local one?
351 if(!drawinglayer::primitive2d::arePrimitive2DSequencesEqual(mxPrimitive2DSequence
, xNewPrimitiveSequence
))
353 // has changed, copy content
354 const_cast< ViewObjectContact
* >(this)->mxPrimitive2DSequence
= xNewPrimitiveSequence
;
356 // check for animated stuff
357 const_cast< ViewObjectContact
* >(this)->checkForPrimitive2DAnimations();
359 // always update object range when PrimitiveSequence changes
360 const drawinglayer::geometry::ViewInformation2D
& rViewInformation2D(GetObjectContact().getViewInformation2D());
361 const_cast< ViewObjectContact
* >(this)->maObjectRange
=
362 drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence(mxPrimitive2DSequence
, rViewInformation2D
);
365 // return current Primitive2DSequence
366 return mxPrimitive2DSequence
;
369 bool ViewObjectContact::isPrimitiveVisible(const DisplayInfo
& /*rDisplayInfo*/) const
371 // default: always visible
375 bool ViewObjectContact::isPrimitiveGhosted(const DisplayInfo
& rDisplayInfo
) const
377 // default: standard check
378 return (GetObjectContact().DoVisualizeEnteredGroup() && !GetObjectContact().isOutputToPrinter() && rDisplayInfo
.IsGhostedDrawModeActive());
381 drawinglayer::primitive2d::Primitive2DSequence
ViewObjectContact::getPrimitive2DSequenceHierarchy(DisplayInfo
& rDisplayInfo
) const
383 drawinglayer::primitive2d::Primitive2DSequence xRetval
;
385 // check model-view visibility
386 if(isPrimitiveVisible(rDisplayInfo
))
388 xRetval
= getPrimitive2DSequence(rDisplayInfo
);
390 if(xRetval
.hasElements())
393 const drawinglayer::geometry::ViewInformation2D
& rViewInformation2D(GetObjectContact().getViewInformation2D());
394 const basegfx::B2DRange
aObjectRange(drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence(xRetval
, rViewInformation2D
));
395 const basegfx::B2DRange
aViewRange(rViewInformation2D
.getViewport());
397 // check geometrical visibility
398 if(!aViewRange
.isEmpty() && !aViewRange
.overlaps(aObjectRange
))
400 // not visible, release
409 drawinglayer::primitive2d::Primitive2DSequence
ViewObjectContact::getPrimitive2DSequenceSubHierarchy(DisplayInfo
& rDisplayInfo
) const
411 const sal_uInt32
nSubHierarchyCount(GetViewContact().GetObjectCount());
412 drawinglayer::primitive2d::Primitive2DSequence xSeqRetval
;
414 for(sal_uInt32
a(0); a
< nSubHierarchyCount
; a
++)
416 const ViewObjectContact
& rCandidate(GetViewContact().GetViewContact(a
).GetViewObjectContact(GetObjectContact()));
418 drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(xSeqRetval
, rCandidate
.getPrimitive2DSequenceHierarchy(rDisplayInfo
));
423 } // end of namespace contact
424 } // end of namespace sdr
426 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */