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 <config_features.h>
22 #include <svx/charthelper.hxx>
23 #include <svx/sdr/contact/viewobjectcontact.hxx>
24 #include <svx/sdr/contact/viewcontact.hxx>
25 #include <svx/sdr/contact/objectcontact.hxx>
26 #include <svx/sdr/contact/displayinfo.hxx>
27 #include <vcl/region.hxx>
28 #include <svx/sdr/animation/objectanimator.hxx>
29 #include <svx/sdr/animation/animationstate.hxx>
30 #include <svx/sdr/contact/viewobjectcontactredirector.hxx>
31 #include <basegfx/numeric/ftools.hxx>
32 #include <basegfx/color/bcolor.hxx>
33 #include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx>
34 #include <basegfx/tools/canvastools.hxx>
35 #include <drawinglayer/primitive2d/animatedprimitive2d.hxx>
36 #include <drawinglayer/processor2d/baseprocessor2d.hxx>
37 #include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx>
38 #include <svx/svdoole2.hxx>
40 #include <sdr/contact/viewcontactofsdrole2obj.hxx>
42 using namespace com::sun::star
;
48 // Necessary to filter a sequence of animated primitives from
49 // a sequence of primitives to find out if animated or not. The decision for
50 // what to decompose is hard-coded and only done for knowingly animated primitives
51 // to not decompose too deeply and unnecessarily. This implies that the list
52 // which is view-specific needs to be expanded by hand when new animated objects
53 // are added. This may eventually be changed to a dynamically configurable approach
55 class AnimatedExtractingProcessor2D
: public drawinglayer::processor2d::BaseProcessor2D
58 // the found animated primitives
59 drawinglayer::primitive2d::Primitive2DContainer maPrimitive2DSequence
;
61 // text animation allowed?
62 bool mbTextAnimationAllowed
: 1;
64 // graphic animation allowed?
65 bool mbGraphicAnimationAllowed
: 1;
67 // as tooling, the process() implementation takes over API handling and calls this
68 // virtual render method when the primitive implementation is BasePrimitive2D-based.
69 virtual void processBasePrimitive2D(const drawinglayer::primitive2d::BasePrimitive2D
& rCandidate
) override
;
72 AnimatedExtractingProcessor2D(
73 const drawinglayer::geometry::ViewInformation2D
& rViewInformation
,
74 bool bTextAnimationAllowed
,
75 bool bGraphicAnimationAllowed
);
78 const drawinglayer::primitive2d::Primitive2DContainer
& 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 void AnimatedExtractingProcessor2D::processBasePrimitive2D(const drawinglayer::primitive2d::BasePrimitive2D
& rCandidate
)
96 // known implementation, access directly
97 switch(rCandidate
.getPrimitive2DID())
99 // add and accept animated primitives directly, no need to decompose
100 case PRIMITIVE2D_ID_ANIMATEDSWITCHPRIMITIVE2D
:
101 case PRIMITIVE2D_ID_ANIMATEDBLINKPRIMITIVE2D
:
102 case PRIMITIVE2D_ID_ANIMATEDINTERPOLATEPRIMITIVE2D
:
104 const drawinglayer::primitive2d::AnimatedSwitchPrimitive2D
& rSwitchPrimitive
= static_cast< const drawinglayer::primitive2d::AnimatedSwitchPrimitive2D
& >(rCandidate
);
106 if((rSwitchPrimitive
.isTextAnimation() && isTextAnimationAllowed())
107 || (rSwitchPrimitive
.isGraphicAnimation() && isGraphicAnimationAllowed()))
109 const drawinglayer::primitive2d::Primitive2DReference
xReference(const_cast< drawinglayer::primitive2d::BasePrimitive2D
* >(&rCandidate
));
110 maPrimitive2DSequence
.push_back(xReference
);
115 // decompose animated gifs where SdrGrafPrimitive2D produces a GraphicPrimitive2D
116 // which then produces the animation infos (all when used/needed)
117 case PRIMITIVE2D_ID_SDRGRAFPRIMITIVE2D
:
118 case PRIMITIVE2D_ID_GRAPHICPRIMITIVE2D
:
120 // decompose SdrObjects with evtl. animated text
121 case PRIMITIVE2D_ID_SDRCAPTIONPRIMITIVE2D
:
122 case PRIMITIVE2D_ID_SDRCONNECTORPRIMITIVE2D
:
123 case PRIMITIVE2D_ID_SDRCUSTOMSHAPEPRIMITIVE2D
:
124 case PRIMITIVE2D_ID_SDRELLIPSEPRIMITIVE2D
:
125 case PRIMITIVE2D_ID_SDRELLIPSESEGMENTPRIMITIVE2D
:
126 case PRIMITIVE2D_ID_SDRMEASUREPRIMITIVE2D
:
127 case PRIMITIVE2D_ID_SDRPATHPRIMITIVE2D
:
128 case PRIMITIVE2D_ID_SDRRECTANGLEPRIMITIVE2D
:
130 // #121194# With Graphic as Bitmap FillStyle, also check
131 // for primitives filled with animated graphics
132 case PRIMITIVE2D_ID_POLYPOLYGONGRAPHICPRIMITIVE2D
:
133 case PRIMITIVE2D_ID_FILLGRAPHICPRIMITIVE2D
:
134 case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D
:
136 // decompose evtl. animated text contained in MaskPrimitive2D
137 // or group primitives
138 case PRIMITIVE2D_ID_MASKPRIMITIVE2D
:
139 case PRIMITIVE2D_ID_GROUPPRIMITIVE2D
:
147 // nothing to do for the rest
153 } // end of anonymous namespace
155 namespace sdr
{ namespace contact
{
157 ViewObjectContact::ViewObjectContact(ObjectContact
& rObjectContact
, ViewContact
& rViewContact
)
158 : mrObjectContact(rObjectContact
),
159 mrViewContact(rViewContact
),
161 mxPrimitive2DSequence(),
162 mpPrimitiveAnimation(nullptr),
163 mbLazyInvalidate(false)
165 // make the ViewContact remember me
166 mrViewContact
.AddViewObjectContact(*this);
168 // make the ObjectContact remember me
169 mrObjectContact
.AddViewObjectContact(*this);
172 ViewObjectContact::~ViewObjectContact()
174 // invalidate in view
175 if(!maObjectRange
.isEmpty())
177 GetObjectContact().InvalidatePartOfView(maObjectRange
);
180 // delete PrimitiveAnimation
181 if(mpPrimitiveAnimation
)
183 delete mpPrimitiveAnimation
;
184 mpPrimitiveAnimation
= nullptr;
187 // take care of remembered ObjectContact. Remove from
188 // OC first. The VC removal (below) CAN trigger a StopGettingViewed()
189 // which (depending of its implementation) may destroy other OCs. This
190 // can trigger the deletion of the helper OC of a page visualising object
191 // which IS the OC of this object. Eventually StopGettingViewed() needs
192 // to get asynchron later
193 GetObjectContact().RemoveViewObjectContact(*this);
195 // take care of remembered ViewContact
196 GetViewContact().RemoveViewObjectContact(*this);
199 const basegfx::B2DRange
& ViewObjectContact::getObjectRange() const
201 if(maObjectRange
.isEmpty())
203 const drawinglayer::geometry::ViewInformation2D
& rViewInfo2D
= GetObjectContact().getViewInformation2D();
204 basegfx::B2DRange aTempRange
= GetViewContact().getRange(rViewInfo2D
);
205 if (!aTempRange
.isEmpty())
207 const_cast< ViewObjectContact
* >(this)->maObjectRange
= aTempRange
;
211 // if range is not computed (new or LazyInvalidate objects), force it
212 const DisplayInfo aDisplayInfo
;
213 const drawinglayer::primitive2d::Primitive2DContainer
xSequence(getPrimitive2DSequence(aDisplayInfo
));
215 if(!xSequence
.empty())
217 const_cast< ViewObjectContact
* >(this)->maObjectRange
=
218 xSequence
.getB2DRange(rViewInfo2D
);
223 return maObjectRange
;
226 void ViewObjectContact::ActionChanged()
228 if(!mbLazyInvalidate
)
231 mbLazyInvalidate
= true;
236 if(!maObjectRange
.isEmpty())
238 // invalidate current valid range
239 GetObjectContact().InvalidatePartOfView(maObjectRange
);
241 // reset ObjectRange, it needs to be recalculated
242 maObjectRange
.reset();
245 // register at OC for lazy invalidate
246 GetObjectContact().setLazyInvalidate(*this);
250 void ViewObjectContact::triggerLazyInvalidate()
255 mbLazyInvalidate
= false;
257 #if HAVE_FEATURE_DESKTOP
258 // 3D charts need to be notified separately, they are not to be
259 // drawn by the drawinglayer
260 ViewContactOfSdrOle2Obj
* pViewContact
= dynamic_cast<ViewContactOfSdrOle2Obj
*>(&GetViewContact());
261 if (pViewContact
&& pViewContact
->GetOle2Obj().IsReal3DChart())
262 ChartHelper::updateChart(pViewContact
->GetOle2Obj().getXModel(), false);
268 if(!maObjectRange
.isEmpty())
270 // invalidate current valid range
271 GetObjectContact().InvalidatePartOfView(maObjectRange
);
276 // Take some action when new objects are inserted
277 void ViewObjectContact::ActionChildInserted(ViewContact
& rChild
)
279 // force creation of the new VOC and trigger it's refresh, so it
280 // will take part in LazyInvalidate immediately
281 rChild
.GetViewObjectContact(GetObjectContact()).ActionChanged();
283 // forward action to ObjectContact
284 // const ViewObjectContact& rChildVOC = rChild.GetViewObjectContact(GetObjectContact());
285 // GetObjectContact().InvalidatePartOfView(rChildVOC.getObjectRange());
288 void ViewObjectContact::checkForPrimitive2DAnimations()
291 if(mpPrimitiveAnimation
)
293 delete mpPrimitiveAnimation
;
294 mpPrimitiveAnimation
= nullptr;
297 // check for animated primitives
298 if(!mxPrimitive2DSequence
.empty())
300 const bool bTextAnimationAllowed(GetObjectContact().IsTextAnimationAllowed());
301 const bool bGraphicAnimationAllowed(GetObjectContact().IsGraphicAnimationAllowed());
303 if(bTextAnimationAllowed
|| bGraphicAnimationAllowed
)
305 AnimatedExtractingProcessor2D
aAnimatedExtractor(GetObjectContact().getViewInformation2D(),
306 bTextAnimationAllowed
, bGraphicAnimationAllowed
);
307 aAnimatedExtractor
.process(mxPrimitive2DSequence
);
309 if(!aAnimatedExtractor
.getPrimitive2DSequence().empty())
311 // derived primitiveList is animated, setup new PrimitiveAnimation
312 mpPrimitiveAnimation
= new sdr::animation::PrimitiveAnimation(*this, aAnimatedExtractor
.getPrimitive2DSequence());
318 drawinglayer::primitive2d::Primitive2DContainer
ViewObjectContact::createPrimitive2DSequence(const DisplayInfo
& rDisplayInfo
) const
320 // get the view-independent Primitive from the viewContact
321 drawinglayer::primitive2d::Primitive2DContainer
xRetval(GetViewContact().getViewIndependentPrimitive2DContainer());
326 if(!GetObjectContact().isOutputToPrinter() && GetObjectContact().AreGluePointsVisible())
328 const drawinglayer::primitive2d::Primitive2DContainer
xGlue(GetViewContact().createGluePointPrimitive2DSequence());
332 xRetval
.append(xGlue
);
337 if(isPrimitiveGhosted(rDisplayInfo
))
339 const basegfx::BColor
aRGBWhite(1.0, 1.0, 1.0);
340 const basegfx::BColorModifierSharedPtr
aBColorModifier(
341 new basegfx::BColorModifier_interpolate(
344 const drawinglayer::primitive2d::Primitive2DReference
xReference(
345 new drawinglayer::primitive2d::ModifiedColorPrimitive2D(
349 xRetval
= drawinglayer::primitive2d::Primitive2DContainer
{ xReference
};
356 drawinglayer::primitive2d::Primitive2DContainer
const & ViewObjectContact::getPrimitive2DSequence(const DisplayInfo
& rDisplayInfo
) const
358 drawinglayer::primitive2d::Primitive2DContainer xNewPrimitiveSequence
;
360 // take care of redirectors and create new list
361 ViewObjectContactRedirector
* pRedirector
= GetObjectContact().GetViewObjectContactRedirector();
365 xNewPrimitiveSequence
= pRedirector
->createRedirectedPrimitive2DSequence(*this, rDisplayInfo
);
369 xNewPrimitiveSequence
= createPrimitive2DSequence(rDisplayInfo
);
372 // local up-to-date checks. New list different from local one?
373 if(mxPrimitive2DSequence
!= xNewPrimitiveSequence
)
375 // has changed, copy content
376 const_cast< ViewObjectContact
* >(this)->mxPrimitive2DSequence
= xNewPrimitiveSequence
;
378 // check for animated stuff
379 const_cast< ViewObjectContact
* >(this)->checkForPrimitive2DAnimations();
381 // always update object range when PrimitiveSequence changes
382 const drawinglayer::geometry::ViewInformation2D
& rViewInformation2D(GetObjectContact().getViewInformation2D());
383 const_cast< ViewObjectContact
* >(this)->maObjectRange
=
384 mxPrimitive2DSequence
.getB2DRange(rViewInformation2D
);
387 // return current Primitive2DContainer
388 return mxPrimitive2DSequence
;
391 bool ViewObjectContact::isPrimitiveVisible(const DisplayInfo
& /*rDisplayInfo*/) const
393 // default: always visible
397 bool ViewObjectContact::isPrimitiveGhosted(const DisplayInfo
& rDisplayInfo
) const
399 // default: standard check
400 return (GetObjectContact().DoVisualizeEnteredGroup() && !GetObjectContact().isOutputToPrinter() && rDisplayInfo
.IsGhostedDrawModeActive());
403 drawinglayer::primitive2d::Primitive2DContainer
ViewObjectContact::getPrimitive2DSequenceHierarchy(DisplayInfo
& rDisplayInfo
) const
405 drawinglayer::primitive2d::Primitive2DContainer xRetval
;
407 // check model-view visibility
408 if(isPrimitiveVisible(rDisplayInfo
))
410 xRetval
= getPrimitive2DSequence(rDisplayInfo
);
415 const drawinglayer::geometry::ViewInformation2D
& rViewInformation2D(GetObjectContact().getViewInformation2D());
416 const basegfx::B2DRange
aObjectRange(xRetval
.getB2DRange(rViewInformation2D
));
417 const basegfx::B2DRange
aViewRange(rViewInformation2D
.getViewport());
419 // check geometrical visibility
420 bool bVisible
= aViewRange
.isEmpty() || aViewRange
.overlaps(aObjectRange
);
423 // not visible, release
432 drawinglayer::primitive2d::Primitive2DContainer
ViewObjectContact::getPrimitive2DSequenceSubHierarchy(DisplayInfo
& rDisplayInfo
) const
434 const sal_uInt32
nSubHierarchyCount(GetViewContact().GetObjectCount());
435 drawinglayer::primitive2d::Primitive2DContainer xSeqRetval
;
437 for(sal_uInt32
a(0); a
< nSubHierarchyCount
; a
++)
439 const ViewObjectContact
& rCandidate(GetViewContact().GetViewContact(a
).GetViewObjectContact(GetObjectContact()));
441 xSeqRetval
.append(rCandidate
.getPrimitive2DSequenceHierarchy(rDisplayInfo
));
449 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */