Version 5.4.3.2, tag libreoffice-5.4.3.2
[LibreOffice.git] / svx / source / sdr / contact / viewobjectcontact.cxx
blobff3c266bba01f0c1f64968dad8dac735919f4d71
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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;
44 namespace {
46 // animated extractor
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
54 // if necessary.
55 class AnimatedExtractingProcessor2D : public drawinglayer::processor2d::BaseProcessor2D
57 protected:
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;
71 public:
72 AnimatedExtractingProcessor2D(
73 const drawinglayer::geometry::ViewInformation2D& rViewInformation,
74 bool bTextAnimationAllowed,
75 bool bGraphicAnimationAllowed);
77 // data access
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);
112 break;
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 :
141 process(rCandidate);
142 break;
145 default :
147 // nothing to do for the rest
148 break;
153 } // end of anonymous namespace
155 namespace sdr { namespace contact {
157 ViewObjectContact::ViewObjectContact(ObjectContact& rObjectContact, ViewContact& rViewContact)
158 : mrObjectContact(rObjectContact),
159 mrViewContact(rViewContact),
160 maObjectRange(),
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;
209 else
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)
230 // set local flag
231 mbLazyInvalidate = true;
233 // force ObjectRange
234 getObjectRange();
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()
252 if(mbLazyInvalidate)
254 // reset flag
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);
263 #endif
265 // force ObjectRange
266 getObjectRange();
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()
290 // remove old one
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());
323 if(!xRetval.empty())
325 // handle GluePoint
326 if(!GetObjectContact().isOutputToPrinter() && GetObjectContact().AreGluePointsVisible())
328 const drawinglayer::primitive2d::Primitive2DContainer xGlue(GetViewContact().createGluePointPrimitive2DSequence());
330 if(!xGlue.empty())
332 xRetval.append(xGlue);
336 // handle ghosted
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(
342 aRGBWhite,
343 0.5));
344 const drawinglayer::primitive2d::Primitive2DReference xReference(
345 new drawinglayer::primitive2d::ModifiedColorPrimitive2D(
346 xRetval,
347 aBColorModifier));
349 xRetval = drawinglayer::primitive2d::Primitive2DContainer { xReference };
353 return xRetval;
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();
363 if(pRedirector)
365 xNewPrimitiveSequence = pRedirector->createRedirectedPrimitive2DSequence(*this, rDisplayInfo);
367 else
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
394 return true;
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);
412 if(!xRetval.empty())
414 // get ranges
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);
421 if(!bVisible)
423 // not visible, release
424 xRetval.clear();
429 return xRetval;
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));
444 return xSeqRetval;
449 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */