Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*
3 : : * This file is part of the LibreOffice project.
4 : : *
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/.
8 : : *
9 : : * This file incorporates work covered by the following license notice:
10 : : *
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 .
18 : : */
19 : :
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>
35 : :
36 : : //////////////////////////////////////////////////////////////////////////////
37 : :
38 : : using namespace com::sun::star;
39 : :
40 : : //////////////////////////////////////////////////////////////////////////////
41 : :
42 : : namespace
43 : : {
44 : : // animated extractor
45 : :
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
52 : : // if necessary.
53 : : class AnimatedExtractingProcessor2D : public drawinglayer::processor2d::BaseProcessor2D
54 : : {
55 : : protected:
56 : : // the found animated primitives
57 : : drawinglayer::primitive2d::Primitive2DSequence maPrimitive2DSequence;
58 : :
59 : : // bitfield
60 : : // text animation allowed?
61 : : unsigned mbTextAnimationAllowed : 1;
62 : :
63 : : // graphic animation allowed?
64 : : unsigned mbGraphicAnimationAllowed : 1;
65 : :
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);
69 : :
70 : : public:
71 : : AnimatedExtractingProcessor2D(
72 : : const drawinglayer::geometry::ViewInformation2D& rViewInformation,
73 : : bool bTextAnimationAllowed,
74 : : bool bGraphicAnimationAllowed);
75 : : virtual ~AnimatedExtractingProcessor2D();
76 : :
77 : : // data access
78 : 50605 : const drawinglayer::primitive2d::Primitive2DSequence& getPrimitive2DSequence() const { return maPrimitive2DSequence; }
79 : 0 : bool isTextAnimationAllowed() const { return mbTextAnimationAllowed; }
80 : 0 : bool isGraphicAnimationAllowed() const { return mbGraphicAnimationAllowed; }
81 : : };
82 : :
83 : 50605 : 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 [ + - ]: 50605 : mbGraphicAnimationAllowed(bGraphicAnimationAllowed)
91 : : {
92 : 50605 : }
93 : :
94 [ + - ]: 50605 : AnimatedExtractingProcessor2D::~AnimatedExtractingProcessor2D()
95 : : {
96 [ - + ]: 50605 : }
97 : :
98 : 136440 : void AnimatedExtractingProcessor2D::processBasePrimitive2D(const drawinglayer::primitive2d::BasePrimitive2D& rCandidate)
99 : : {
100 : : // known implementation, access directly
101 [ - + + ]: 136440 : switch(rCandidate.getPrimitive2DID())
102 : : {
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 :
107 : : {
108 : 0 : const drawinglayer::primitive2d::AnimatedSwitchPrimitive2D& rSwitchPrimitive = static_cast< const drawinglayer::primitive2d::AnimatedSwitchPrimitive2D& >(rCandidate);
109 : :
110 [ # # ][ # # : 0 : if((rSwitchPrimitive.isTextAnimation() && isTextAnimationAllowed())
# # # # ]
[ # # ]
111 : 0 : || (rSwitchPrimitive.isGraphicAnimation() && isGraphicAnimationAllowed()))
112 : : {
113 [ # # ]: 0 : const drawinglayer::primitive2d::Primitive2DReference xReference(const_cast< drawinglayer::primitive2d::BasePrimitive2D* >(&rCandidate));
114 [ # # ]: 0 : drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(maPrimitive2DSequence, xReference);
115 : : }
116 : 0 : break;
117 : : }
118 : :
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 :
123 : :
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 :
133 : :
134 : : // decompose evtl. animated text contained in MaskPrimitive2D
135 : : // or group rimitives
136 : : case PRIMITIVE2D_ID_MASKPRIMITIVE2D :
137 : : case PRIMITIVE2D_ID_GROUPPRIMITIVE2D :
138 : : {
139 [ + - ]: 39797 : process(rCandidate.get2DDecomposition(getViewInformation2D()));
140 : 39797 : break;
141 : : }
142 : :
143 : : default :
144 : : {
145 : : // nothing to do for the rest
146 : 96643 : break;
147 : : }
148 : : }
149 : 136440 : }
150 : : } // end of anonymous namespace
151 : :
152 : : //////////////////////////////////////////////////////////////////////////////
153 : :
154 : : namespace sdr
155 : : {
156 : : namespace contact
157 : : {
158 : 95044 : ViewObjectContact::ViewObjectContact(ObjectContact& rObjectContact, ViewContact& rViewContact)
159 : : : mrObjectContact(rObjectContact),
160 : : mrViewContact(rViewContact),
161 : : maObjectRange(),
162 : : mxPrimitive2DSequence(),
163 : : mpPrimitiveAnimation(0),
164 : 95044 : mbLazyInvalidate(false)
165 : : {
166 : : // make the ViewContact remember me
167 [ + - ]: 95044 : mrViewContact.AddViewObjectContact(*this);
168 : :
169 : : // make the ObjectContact remember me
170 [ + - ]: 95044 : mrObjectContact.AddViewObjectContact(*this);
171 : 95044 : }
172 : :
173 : 93904 : ViewObjectContact::~ViewObjectContact()
174 : : {
175 : : // invalidate in view
176 [ + - ][ + + ]: 93904 : if(!maObjectRange.isEmpty())
177 : : {
178 [ + - ]: 41907 : GetObjectContact().InvalidatePartOfView(maObjectRange);
179 : : }
180 : :
181 : : // delete PrimitiveAnimation
182 [ - + ]: 93904 : if(mpPrimitiveAnimation)
183 : : {
184 [ # # ][ # # ]: 0 : delete mpPrimitiveAnimation;
185 : 0 : mpPrimitiveAnimation = 0;
186 : : }
187 : :
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 [ + - ]: 93904 : GetObjectContact().RemoveViewObjectContact(*this);
195 : :
196 : : // take care of remebered ViewContact
197 [ + - ]: 93904 : GetViewContact().RemoveViewObjectContact(*this);
198 [ - + ]: 93904 : }
199 : :
200 : 22552 : const basegfx::B2DRange& ViewObjectContact::getObjectRange() const
201 : : {
202 [ + + ]: 22552 : if(maObjectRange.isEmpty())
203 : : {
204 : : // if range is not computed (new or LazyInvalidate objects), force it
205 [ + - ]: 14089 : const DisplayInfo aDisplayInfo;
206 [ + - ]: 14089 : const drawinglayer::primitive2d::Primitive2DSequence xSequence(getPrimitive2DSequence(aDisplayInfo));
207 : :
208 [ + + ]: 14089 : if(xSequence.hasElements())
209 : : {
210 : 12290 : const drawinglayer::geometry::ViewInformation2D& rViewInformation2D(GetObjectContact().getViewInformation2D());
211 : : const_cast< ViewObjectContact* >(this)->maObjectRange =
212 [ + - ]: 12290 : drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence(xSequence, rViewInformation2D);
213 [ + - ][ + - ]: 14089 : }
214 : : }
215 : :
216 : 22552 : return maObjectRange;
217 : : }
218 : :
219 : 22686 : void ViewObjectContact::ActionChanged()
220 : : {
221 [ + + ]: 22686 : if(!mbLazyInvalidate)
222 : : {
223 : : // set local flag
224 : 11307 : mbLazyInvalidate = true;
225 : :
226 : : // force ObjectRange
227 : 11307 : getObjectRange();
228 : :
229 [ + + ]: 11307 : if(!maObjectRange.isEmpty())
230 : : {
231 : : // invalidate current valid range
232 : 10398 : GetObjectContact().InvalidatePartOfView(maObjectRange);
233 : :
234 : : // reset ObjectRange, it needs to be recalculated
235 : 10398 : maObjectRange.reset();
236 : : }
237 : :
238 : : // register at OC for lazy invalidate
239 : 11307 : GetObjectContact().setLazyInvalidate(*this);
240 : : }
241 : 22686 : }
242 : :
243 : 203326 : void ViewObjectContact::triggerLazyInvalidate()
244 : : {
245 [ + + ]: 203326 : if(mbLazyInvalidate)
246 : : {
247 : : // reset flag
248 : 11243 : mbLazyInvalidate = false;
249 : :
250 : : // force ObjectRange
251 : 11243 : getObjectRange();
252 : :
253 [ + + ]: 11243 : if(!maObjectRange.isEmpty())
254 : : {
255 : : // invalidate current valid range
256 : 10323 : GetObjectContact().InvalidatePartOfView(maObjectRange);
257 : : }
258 : : }
259 : 203326 : }
260 : :
261 : : // Take some action when new objects are inserted
262 : 931 : void ViewObjectContact::ActionChildInserted(ViewContact& rChild)
263 : : {
264 : : // force creation of the new VOC and trigger it's refresh, so it
265 : : // will take part in LazyInvalidate immediately
266 : 931 : rChild.GetViewObjectContact(GetObjectContact()).ActionChanged();
267 : :
268 : : // forward action to ObjectContact
269 : : // const ViewObjectContact& rChildVOC = rChild.GetViewObjectContact(GetObjectContact());
270 : : // GetObjectContact().InvalidatePartOfView(rChildVOC.getObjectRange());
271 : 931 : }
272 : :
273 : 50626 : void ViewObjectContact::checkForPrimitive2DAnimations()
274 : : {
275 : : // remove old one
276 [ - + ]: 50626 : if(mpPrimitiveAnimation)
277 : : {
278 [ # # ]: 0 : delete mpPrimitiveAnimation;
279 : 0 : mpPrimitiveAnimation = 0;
280 : : }
281 : :
282 : : // check for animated primitives
283 [ + + ]: 50626 : if(mxPrimitive2DSequence.hasElements())
284 : : {
285 : 50605 : const bool bTextAnimationAllowed(GetObjectContact().IsTextAnimationAllowed());
286 : 50605 : const bool bGraphicAnimationAllowed(GetObjectContact().IsGraphicAnimationAllowed());
287 : :
288 [ # # ][ - + ]: 50605 : if(bTextAnimationAllowed || bGraphicAnimationAllowed)
289 : : {
290 : 50605 : AnimatedExtractingProcessor2D aAnimatedExtractor(GetObjectContact().getViewInformation2D(),
291 [ + - ]: 50605 : bTextAnimationAllowed, bGraphicAnimationAllowed);
292 [ + - ]: 50605 : aAnimatedExtractor.process(mxPrimitive2DSequence);
293 : :
294 [ - + ]: 50605 : if(aAnimatedExtractor.getPrimitive2DSequence().hasElements())
295 : : {
296 : : // dervied primitiveList is animated, setup new PrimitiveAnimation
297 [ # # ][ # # ]: 0 : mpPrimitiveAnimation = new sdr::animation::PrimitiveAnimation(*this, aAnimatedExtractor.getPrimitive2DSequence());
298 [ + - ]: 50605 : }
299 : : }
300 : : }
301 : 50626 : }
302 : :
303 : 54275 : drawinglayer::primitive2d::Primitive2DSequence ViewObjectContact::createPrimitive2DSequence(const DisplayInfo& rDisplayInfo) const
304 : : {
305 : : // get the view-independent Primitive from the viewContact
306 : 54275 : drawinglayer::primitive2d::Primitive2DSequence xRetval(GetViewContact().getViewIndependentPrimitive2DSequence());
307 : :
308 [ + + ]: 54275 : if(xRetval.hasElements())
309 : : {
310 : : // handle GluePoint
311 [ + - ][ + - ]: 52988 : if(!GetObjectContact().isOutputToPrinter() && GetObjectContact().AreGluePointsVisible())
[ + - ][ - + ]
[ - + ]
312 : : {
313 [ # # ]: 0 : const drawinglayer::primitive2d::Primitive2DSequence xGlue(GetViewContact().createGluePointPrimitive2DSequence());
314 : :
315 [ # # ]: 0 : if(xGlue.hasElements())
316 : : {
317 [ # # ]: 0 : drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(xRetval, xGlue);
318 [ # # ]: 0 : }
319 : : }
320 : :
321 : : // handle ghosted
322 [ + - ][ - + ]: 52988 : if(isPrimitiveGhosted(rDisplayInfo))
323 : : {
324 : 0 : const basegfx::BColor aRGBWhite(1.0, 1.0, 1.0);
325 : 0 : const basegfx::BColorModifier aBColorModifier(aRGBWhite, 0.5, basegfx::BCOLORMODIFYMODE_INTERPOLATE);
326 [ # # ][ # # ]: 0 : const drawinglayer::primitive2d::Primitive2DReference xReference(new drawinglayer::primitive2d::ModifiedColorPrimitive2D(xRetval, aBColorModifier));
[ # # ]
327 [ # # ][ # # ]: 0 : xRetval = drawinglayer::primitive2d::Primitive2DSequence(&xReference, 1);
[ # # ][ # # ]
328 : : }
329 : : }
330 : :
331 : 54275 : return xRetval;
332 : : }
333 : :
334 : 75046 : drawinglayer::primitive2d::Primitive2DSequence ViewObjectContact::getPrimitive2DSequence(const DisplayInfo& rDisplayInfo) const
335 : : {
336 [ + - ]: 75046 : drawinglayer::primitive2d::Primitive2DSequence xNewPrimitiveSequence;
337 : :
338 : : // take care of redirectors and create new list
339 [ + - ]: 75046 : ViewObjectContactRedirector* pRedirector = GetObjectContact().GetViewObjectContactRedirector();
340 : :
341 [ + + ]: 75046 : if(pRedirector)
342 : : {
343 [ + - ][ + - ]: 15555 : xNewPrimitiveSequence = pRedirector->createRedirectedPrimitive2DSequence(*this, rDisplayInfo);
[ + - ]
344 : : }
345 : : else
346 : : {
347 [ + - ][ + - ]: 59491 : xNewPrimitiveSequence = createPrimitive2DSequence(rDisplayInfo);
[ + - ]
348 : : }
349 : :
350 : : // local up-to-date checks. New list different from local one?
351 [ + - ][ + + ]: 75046 : if(!drawinglayer::primitive2d::arePrimitive2DSequencesEqual(mxPrimitive2DSequence, xNewPrimitiveSequence))
352 : : {
353 : : // has changed, copy content
354 [ + - ]: 50626 : const_cast< ViewObjectContact* >(this)->mxPrimitive2DSequence = xNewPrimitiveSequence;
355 : :
356 : : // check for animated stuff
357 [ + - ]: 50626 : const_cast< ViewObjectContact* >(this)->checkForPrimitive2DAnimations();
358 : :
359 : : // always update object range when PrimitiveSequence changes
360 : 50626 : const drawinglayer::geometry::ViewInformation2D& rViewInformation2D(GetObjectContact().getViewInformation2D());
361 : : const_cast< ViewObjectContact* >(this)->maObjectRange =
362 [ + - ]: 50626 : drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence(mxPrimitive2DSequence, rViewInformation2D);
363 : : }
364 : :
365 : : // return current Primitive2DSequence
366 [ + - ][ + - ]: 75046 : return mxPrimitive2DSequence;
367 : : }
368 : :
369 : 0 : bool ViewObjectContact::isPrimitiveVisible(const DisplayInfo& /*rDisplayInfo*/) const
370 : : {
371 : : // default: always visible
372 : 0 : return true;
373 : : }
374 : :
375 : 47829 : bool ViewObjectContact::isPrimitiveGhosted(const DisplayInfo& rDisplayInfo) const
376 : : {
377 : : // default: standard check
378 [ + + ][ + - ]: 47829 : return (GetObjectContact().DoVisualizeEnteredGroup() && !GetObjectContact().isOutputToPrinter() && rDisplayInfo.IsGhostedDrawModeActive());
[ - + ]
379 : : }
380 : :
381 : 538397 : drawinglayer::primitive2d::Primitive2DSequence ViewObjectContact::getPrimitive2DSequenceHierarchy(DisplayInfo& rDisplayInfo) const
382 : : {
383 : 538397 : drawinglayer::primitive2d::Primitive2DSequence xRetval;
384 : :
385 : : // check model-view visibility
386 [ + + ][ + - ]: 538397 : if(isPrimitiveVisible(rDisplayInfo))
387 : : {
388 [ + - ][ + - ]: 60955 : xRetval = getPrimitive2DSequence(rDisplayInfo);
[ + - ]
389 : :
390 [ + + ]: 60955 : if(xRetval.hasElements())
391 : : {
392 : : // get ranges
393 : 59651 : const drawinglayer::geometry::ViewInformation2D& rViewInformation2D(GetObjectContact().getViewInformation2D());
394 [ + - ]: 59651 : const basegfx::B2DRange aObjectRange(drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence(xRetval, rViewInformation2D));
395 [ + - ]: 59651 : const basegfx::B2DRange aViewRange(rViewInformation2D.getViewport());
396 : :
397 : : // check geometrical visibility
398 [ + - ][ + + ]: 59651 : if(!aViewRange.isEmpty() && !aViewRange.overlaps(aObjectRange))
[ + - ][ + + ]
[ + + ]
399 : : {
400 : : // not visible, release
401 [ + - ]: 59651 : xRetval.realloc(0);
402 : : }
403 : : }
404 : : }
405 : :
406 : 538397 : return xRetval;
407 : : }
408 : :
409 : 88605 : drawinglayer::primitive2d::Primitive2DSequence ViewObjectContact::getPrimitive2DSequenceSubHierarchy(DisplayInfo& rDisplayInfo) const
410 : : {
411 : 88605 : const sal_uInt32 nSubHierarchyCount(GetViewContact().GetObjectCount());
412 : 88605 : drawinglayer::primitive2d::Primitive2DSequence xSeqRetval;
413 : :
414 [ + + ]: 699449 : for(sal_uInt32 a(0); a < nSubHierarchyCount; a++)
415 : : {
416 [ + - ][ + - ]: 610844 : const ViewObjectContact& rCandidate(GetViewContact().GetViewContact(a).GetViewObjectContact(GetObjectContact()));
417 : :
418 [ + - ][ + - ]: 610844 : drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(xSeqRetval, rCandidate.getPrimitive2DSequenceHierarchy(rDisplayInfo));
[ + - ]
419 : : }
420 : :
421 : 88605 : return xSeqRetval;
422 : : }
423 : : } // end of namespace contact
424 : : } // end of namespace sdr
425 : :
426 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|