xref: /AOO41X/main/svx/source/sdr/overlay/overlaymanager.cxx (revision 7b6b9ddb4b63a97ea0214b9472b5270bbf674949)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_svx.hxx"
26 #include <svx/sdr/overlay/overlaymanager.hxx>
27 #include <basegfx/point/b2dpoint.hxx>
28 #include <basegfx/range/b2drange.hxx>
29 #include <tools/gen.hxx>
30 #include <vcl/salbtype.hxx>
31 #include <vcl/outdev.hxx>
32 #include <vcl/window.hxx>
33 #include <svx/sdr/overlay/overlayobject.hxx>
34 #include <basegfx/matrix/b2dhommatrix.hxx>
35 #include <drawinglayer/processor2d/baseprocessor2d.hxx>
36 #include <svx/sdr/contact/objectcontacttools.hxx>
37 
38 //////////////////////////////////////////////////////////////////////////////
39 
40 using namespace com::sun::star;
41 
42 //////////////////////////////////////////////////////////////////////////////
43 
44 namespace sdr
45 {
46     namespace overlay
47     {
48         void OverlayManager::ImpDrawMembers(const basegfx::B2DRange& rRange, OutputDevice& rDestinationDevice) const
49         {
50             const sal_uInt32 nSize(maOverlayObjects.size());
51 
52             if(nSize)
53             {
54                 const sal_uInt16 nOriginalAA(rDestinationDevice.GetAntialiasing());
55                 const bool bIsAntiAliasing(getDrawinglayerOpt().IsAntiAliasing());
56 
57                 // create processor
58                 drawinglayer::processor2d::BaseProcessor2D* pProcessor = ::sdr::contact::createBaseProcessor2DFromOutputDevice(
59                     rDestinationDevice,
60                     getCurrentViewInformation2D());
61 
62                 if(pProcessor)
63                 {
64                     for(OverlayObjectVector::const_iterator aIter(maOverlayObjects.begin()); aIter != maOverlayObjects.end(); aIter++)
65                     {
66                         OSL_ENSURE(*aIter, "Corrupted OverlayObject List (!)");
67                         const OverlayObject& rCandidate = **aIter;
68 
69                         if(rCandidate.isVisible())
70                         {
71                             const drawinglayer::primitive2d::Primitive2DSequence& rSequence = rCandidate.getOverlayObjectPrimitive2DSequence();
72 
73                             if(rSequence.hasElements())
74                             {
75                                 if(rRange.overlaps(rCandidate.getBaseRange()))
76                                 {
77                                     if(bIsAntiAliasing && rCandidate.allowsAntiAliase())
78                                     {
79                                         rDestinationDevice.SetAntialiasing(nOriginalAA | ANTIALIASING_ENABLE_B2DDRAW);
80                                     }
81                                     else
82                                     {
83                                         rDestinationDevice.SetAntialiasing(nOriginalAA & ~ANTIALIASING_ENABLE_B2DDRAW);
84                                     }
85 
86                                     pProcessor->process(rSequence);
87                                 }
88                             }
89                         }
90                     }
91 
92                     delete pProcessor;
93                 }
94 
95                 // restore AA settings
96                 rDestinationDevice.SetAntialiasing(nOriginalAA);
97             }
98         }
99 
100         void OverlayManager::ImpStripeDefinitionChanged()
101         {
102             const sal_uInt32 nSize(maOverlayObjects.size());
103 
104             if(nSize)
105             {
106                 for(OverlayObjectVector::iterator aIter(maOverlayObjects.begin()); aIter != maOverlayObjects.end(); aIter++)
107                 {
108                     OSL_ENSURE(*aIter, "Corrupted OverlayObject List (!)");
109                     OverlayObject& rCandidate = **aIter;
110                     rCandidate.stripeDefinitionHasChanged();
111                 }
112             }
113         }
114 
115         double OverlayManager::getDiscreteOne() const
116         {
117             if(basegfx::fTools::equalZero(mfDiscreteOne))
118             {
119                 const basegfx::B2DVector aDiscreteInLogic(getOutputDevice().GetInverseViewTransformation() * basegfx::B2DVector(1.0, 0.0));
120                 const_cast< OverlayManager* >(this)->mfDiscreteOne = aDiscreteInLogic.getLength();
121             }
122 
123             return mfDiscreteOne;
124         }
125 
126         OverlayManager::OverlayManager(OutputDevice& rOutputDevice)
127         :   Scheduler(),
128             rmOutputDevice(rOutputDevice),
129             maOverlayObjects(),
130             maStripeColorA(Color(COL_BLACK)),
131             maStripeColorB(Color(COL_WHITE)),
132             mnStripeLengthPixel(5),
133             maDrawinglayerOpt(),
134             maViewTransformation(),
135             maViewInformation2D(),
136             mfDiscreteOne(0.0)
137         {
138             // set Property 'ReducedDisplayQuality' to true to allow simpler interaction
139             // visualisations
140             static bool bUseReducedDisplayQualityForDrag(true);
141 
142             if(bUseReducedDisplayQualityForDrag)
143             {
144                 uno::Sequence< beans::PropertyValue > xProperties(1);
145                 xProperties[0].Name = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ReducedDisplayQuality"));
146                 xProperties[0].Value <<= true;
147                 maViewInformation2D = drawinglayer::geometry::ViewInformation2D(xProperties);
148             }
149         }
150 
151         const drawinglayer::geometry::ViewInformation2D OverlayManager::getCurrentViewInformation2D() const
152         {
153             if(getOutputDevice().GetViewTransformation() != maViewTransformation)
154             {
155                 basegfx::B2DRange aViewRange(maViewInformation2D.getViewport());
156 
157                 if(OUTDEV_WINDOW == getOutputDevice().GetOutDevType())
158                 {
159                     const Size aOutputSizePixel(getOutputDevice().GetOutputSizePixel());
160                     aViewRange = basegfx::B2DRange(0.0, 0.0, aOutputSizePixel.getWidth(), aOutputSizePixel.getHeight());
161                     aViewRange.transform(getOutputDevice().GetInverseViewTransformation());
162                 }
163 
164                 OverlayManager* pThis = const_cast< OverlayManager* >(this);
165 
166                 pThis->maViewTransformation = getOutputDevice().GetViewTransformation();
167                 pThis->maViewInformation2D = drawinglayer::geometry::ViewInformation2D(
168                     maViewInformation2D.getObjectTransformation(),
169                     maViewTransformation,
170                     aViewRange,
171                     maViewInformation2D.getVisualizedPage(),
172                     maViewInformation2D.getViewTime(),
173                     maViewInformation2D.getExtendedInformationSequence());
174                 pThis->mfDiscreteOne = 0.0;
175             }
176 
177             return maViewInformation2D;
178         }
179 
180         void OverlayManager::impApplyRemoveActions(OverlayObject& rTarget)
181         {
182             // handle evtl. animation
183             if(rTarget.allowsAnimation())
184             {
185                 // remove from event chain
186                 RemoveEvent(&rTarget);
187             }
188 
189             // make invisible
190             invalidateRange(rTarget.getBaseRange());
191 
192             // clear manager
193             rTarget.mpOverlayManager = 0;
194         }
195 
196         void OverlayManager::impApplyAddActions(OverlayObject& rTarget)
197         {
198             // set manager
199             rTarget.mpOverlayManager = this;
200 
201             // make visible
202             invalidateRange(rTarget.getBaseRange());
203 
204             // handle evtl. animation
205             if(rTarget.allowsAnimation())
206             {
207                 // Trigger at current time to get alive. This will do the
208                 // object-specific next time calculation and hand over adding
209                 // again to the scheduler to the animated object, too. This works for
210                 // a paused or non-paused animator.
211                 rTarget.Trigger(GetTime());
212             }
213         }
214 
215         OverlayManager::~OverlayManager()
216         {
217             // The OverlayManager is not the owner of the OverlayObjects
218             // and thus will not delete them, but remove them. Profit here
219             // from knowing that all will be removed
220             const sal_uInt32 nSize(maOverlayObjects.size());
221 
222             if(nSize)
223             {
224                 for(OverlayObjectVector::iterator aIter(maOverlayObjects.begin()); aIter != maOverlayObjects.end(); aIter++)
225                 {
226                     OSL_ENSURE(*aIter, "Corrupted OverlayObject List (!)");
227                     OverlayObject& rCandidate = **aIter;
228                     impApplyRemoveActions(rCandidate);
229                 }
230 
231                 // erase vector
232                 maOverlayObjects.clear();
233             }
234         }
235 
236         void OverlayManager::completeRedraw(const Region& rRegion, OutputDevice* pPreRenderDevice) const
237         {
238             if(!rRegion.IsEmpty() && maOverlayObjects.size())
239             {
240                 // check for changed MapModes. That may influence the
241                 // logical size of pixel based OverlayObjects (like BitmapHandles)
242                 //ImpCheckMapModeChange();
243 
244                 // paint members
245                 const Rectangle aRegionBoundRect(rRegion.GetBoundRect());
246                 const basegfx::B2DRange aRegionRange(
247                     aRegionBoundRect.Left(), aRegionBoundRect.Top(),
248                     aRegionBoundRect.Right(), aRegionBoundRect.Bottom());
249 
250                 OutputDevice& rTarget = (pPreRenderDevice) ? *pPreRenderDevice : getOutputDevice();
251                 ImpDrawMembers(aRegionRange, rTarget);
252             }
253         }
254 
255         void OverlayManager::flush()
256         {
257             // default has nothing to do
258         }
259 
260         // #i68597# part of content gets copied, react on it
261         void OverlayManager::copyArea(const Point& /*rDestPt*/, const Point& /*rSrcPt*/, const Size& /*rSrcSize*/)
262         {
263             // unbuffered versions do nothing here
264         }
265 
266         void OverlayManager::restoreBackground(const Region& /*rRegion*/) const
267         {
268             // unbuffered versions do nothing here
269         }
270 
271         void OverlayManager::add(OverlayObject& rOverlayObject)
272         {
273             OSL_ENSURE(0 == rOverlayObject.mpOverlayManager, "OverlayObject is added twice to an OverlayManager (!)");
274 
275             // add to the end of chain to preserve display order in paint
276             maOverlayObjects.push_back(&rOverlayObject);
277 
278             // execute add actions
279             impApplyAddActions(rOverlayObject);
280         }
281 
282         void OverlayManager::remove(OverlayObject& rOverlayObject)
283         {
284             OSL_ENSURE(rOverlayObject.mpOverlayManager == this, "OverlayObject is removed from wrong OverlayManager (!)");
285 
286             // execute remove actions
287             impApplyRemoveActions(rOverlayObject);
288 
289             // remove from vector
290             const OverlayObjectVector::iterator aFindResult = ::std::find(maOverlayObjects.begin(), maOverlayObjects.end(), &rOverlayObject);
291             const bool bFound(aFindResult != maOverlayObjects.end());
292             OSL_ENSURE(bFound, "OverlayObject NOT found at OverlayManager (!)");
293 
294             if(bFound)
295             {
296                 maOverlayObjects.erase(aFindResult);
297             }
298         }
299 
300         void OverlayManager::invalidateRange(const basegfx::B2DRange& rRange)
301         {
302             if(OUTDEV_WINDOW == getOutputDevice().GetOutDevType())
303             {
304                 if(getDrawinglayerOpt().IsAntiAliasing())
305                 {
306                     // assume AA needs one pixel more and invalidate one pixel more
307                     const double fDiscreteOne(getDiscreteOne());
308                     const Rectangle aInvalidateRectangle(
309                         (sal_Int32)floor(rRange.getMinX() - fDiscreteOne),
310                         (sal_Int32)floor(rRange.getMinY() - fDiscreteOne),
311                         (sal_Int32)ceil(rRange.getMaxX() + fDiscreteOne),
312                         (sal_Int32)ceil(rRange.getMaxY() + fDiscreteOne));
313 
314                     // simply invalidate
315                     ((Window&)getOutputDevice()).Invalidate(aInvalidateRectangle, INVALIDATE_NOERASE);
316                 }
317                 else
318                 {
319                     // #i77674# transform to rectangle. Use floor/ceil to get all covered
320                     // discrete pixels, see #i75163# and OverlayManagerBuffered::invalidateRange
321                     const Rectangle aInvalidateRectangle(
322                         (sal_Int32)floor(rRange.getMinX()), (sal_Int32)floor(rRange.getMinY()),
323                         (sal_Int32)ceil(rRange.getMaxX()), (sal_Int32)ceil(rRange.getMaxY()));
324 
325                     // simply invalidate
326                     ((Window&)getOutputDevice()).Invalidate(aInvalidateRectangle, INVALIDATE_NOERASE);
327                 }
328             }
329         }
330 
331         // stripe support ColA
332         void OverlayManager::setStripeColorA(Color aNew)
333         {
334             if(aNew != maStripeColorA)
335             {
336                 maStripeColorA = aNew;
337                 ImpStripeDefinitionChanged();
338             }
339         }
340 
341         // stripe support ColB
342         void OverlayManager::setStripeColorB(Color aNew)
343         {
344             if(aNew != maStripeColorB)
345             {
346                 maStripeColorB = aNew;
347                 ImpStripeDefinitionChanged();
348             }
349         }
350 
351         // stripe support StripeLengthPixel
352         void OverlayManager::setStripeLengthPixel(sal_uInt32 nNew)
353         {
354             if(nNew != mnStripeLengthPixel)
355             {
356                 mnStripeLengthPixel = nNew;
357                 ImpStripeDefinitionChanged();
358             }
359         }
360     } // end of namespace overlay
361 } // end of namespace sdr
362 
363 //////////////////////////////////////////////////////////////////////////////
364 // eof
365