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 #include "precompiled_sd.hxx"
25 
26 #include "SlsLayeredDevice.hxx"
27 
28 #include <vcl/window.hxx>
29 #include <vcl/virdev.hxx>
30 
31 #include <boost/bind.hpp>
32 #include <boost/function.hpp>
33 
34 
35 namespace sd { namespace slidesorter { namespace view {
36 
37 namespace {
38 static const sal_Int32 gnMaximumLayerCount = 8;
39 
40 class LayerInvalidator : public ILayerInvalidator
41 {
42 public:
LayerInvalidator(const::boost::shared_ptr<LayeredDevice> & rpLayeredDevice,const SharedSdWindow & rpTargetWindow,const int nLayer)43     LayerInvalidator (
44         const ::boost::shared_ptr<LayeredDevice>& rpLayeredDevice,
45         const SharedSdWindow& rpTargetWindow,
46         const int nLayer)
47         : mpLayeredDevice(rpLayeredDevice),
48           mpTargetWindow(rpTargetWindow),
49           mnLayer(nLayer)
50     {
51     }
52 
Invalidate(const Rectangle & rInvalidationBox)53     virtual void Invalidate (const Rectangle& rInvalidationBox)
54     {
55         mpLayeredDevice->Invalidate(rInvalidationBox, mnLayer);
56         mpTargetWindow->Invalidate(rInvalidationBox);
57     }
58 
59 private:
60     const ::boost::shared_ptr<LayeredDevice> mpLayeredDevice;
61     SharedSdWindow mpTargetWindow;
62     const int mnLayer;
63 };
64 
DeviceCopy(OutputDevice & rTargetDevice,OutputDevice & rSourceDevice,const Rectangle & rBox)65 void DeviceCopy (
66     OutputDevice& rTargetDevice,
67     OutputDevice& rSourceDevice,
68     const Rectangle& rBox)
69 {
70     rTargetDevice.DrawOutDev(
71         rBox.TopLeft(),
72         rBox.GetSize(),
73         rBox.TopLeft(),
74         rBox.GetSize(),
75         rSourceDevice);
76 }
77 
78 
ForAllRectangles(const Region & rRegion,::boost::function<void (const Rectangle &)> aFunction)79 void ForAllRectangles (const Region& rRegion, ::boost::function<void(const Rectangle&)> aFunction)
80 {
81     OSL_ASSERT(aFunction);
82     RectangleVector aRectangles;
83     rRegion.GetRegionRectangles(aRectangles);
84 
85     if(0 == aRectangles.size())
86     {
87         aFunction(Rectangle());
88     }
89     else
90     {
91         for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); aRectIter++)
92         {
93             aFunction(*aRectIter);
94         }
95 
96         //Region aMutableRegionCopy (rRegion);
97         //RegionHandle aHandle(aMutableRegionCopy.BeginEnumRects());
98         //Rectangle aBox;
99         //while (aMutableRegionCopy.GetEnumRects(aHandle, aBox))
100         //    aFunction(aBox);
101         //aMutableRegionCopy.EndEnumRects(aHandle);
102     }
103 }
104 
105 class Layer : private ::boost::noncopyable
106 {
107 public:
108     Layer (void);
109     ~Layer (void);
110 
111     void Initialize (const SharedSdWindow& rpTargetWindow);
112     void InvalidateRectangle (const Rectangle& rInvalidationBox);
113     void InvalidateRegion (const Region& rInvalidationRegion);
114     void Validate (const MapMode& rMapMode);
115     void Repaint (
116         OutputDevice& rTargetDevice,
117         const Rectangle& rRepaintRectangle);
118     void Resize (const Size& rSize);
119     void AddPainter (const SharedILayerPainter& rpPainter);
120     void RemovePainter (const SharedILayerPainter& rpPainter);
121     bool HasPainter (void) const;
122     void Dispose (void);
123 
124 private:
125     ::boost::shared_ptr<VirtualDevice> mpLayerDevice;
126     ::std::vector<SharedILayerPainter> maPainters;
127     Region maInvalidationRegion;
128 
129     void ValidateRectangle (const Rectangle& rBox);
130 };
131 typedef ::boost::shared_ptr<Layer> SharedLayer;
132 
133 
134 } // end of anonymous namespace
135 
136 
137 class LayeredDevice::LayerContainer : public ::std::vector<SharedLayer>
138 {
139 public:
LayerContainer(void)140     LayerContainer (void) {}
~LayerContainer(void)141     ~LayerContainer (void) {}
142 };
143 
144 
145 
146 
147 //===== LayeredDevice =========================================================
148 
LayeredDevice(const SharedSdWindow & rpTargetWindow)149 LayeredDevice::LayeredDevice (const SharedSdWindow& rpTargetWindow)
150     : mpTargetWindow(rpTargetWindow),
151       mpLayers(new LayerContainer()),
152       mpBackBuffer(new VirtualDevice(*mpTargetWindow)),
153       maSavedMapMode(rpTargetWindow->GetMapMode())
154 {
155     mpBackBuffer->SetOutputSizePixel(mpTargetWindow->GetSizePixel());
156 }
157 
158 
159 
160 
~LayeredDevice(void)161 LayeredDevice::~LayeredDevice (void)
162 {
163 }
164 
165 
166 
167 
Invalidate(const Rectangle & rInvalidationArea,const sal_Int32 nLayer)168 void LayeredDevice::Invalidate (
169     const Rectangle& rInvalidationArea,
170     const sal_Int32 nLayer)
171 {
172     if (nLayer<0 || size_t(nLayer)>=mpLayers->size())
173     {
174         OSL_ASSERT(nLayer>=0 && size_t(nLayer)<mpLayers->size());
175         return;
176     }
177 
178     (*mpLayers)[nLayer]->InvalidateRectangle(rInvalidationArea);
179 }
180 
181 
182 
183 
InvalidateAllLayers(const Rectangle & rInvalidationArea)184 void LayeredDevice::InvalidateAllLayers (const Rectangle& rInvalidationArea)
185 {
186     for (sal_uInt32 nLayer=0; nLayer<mpLayers->size(); ++nLayer)
187         (*mpLayers)[nLayer]->InvalidateRectangle(rInvalidationArea);
188 }
189 
190 
191 
192 
InvalidateAllLayers(const Region & rInvalidationRegion)193 void LayeredDevice::InvalidateAllLayers (const Region& rInvalidationRegion)
194 {
195     for (sal_uInt32 nLayer=0; nLayer<mpLayers->size(); ++nLayer)
196         (*mpLayers)[nLayer]->InvalidateRegion(rInvalidationRegion);
197 }
198 
199 
200 
201 
RegisterPainter(const SharedILayerPainter & rpPainter,const sal_Int32 nLayer)202 void LayeredDevice::RegisterPainter (
203     const SharedILayerPainter& rpPainter,
204     const sal_Int32 nLayer)
205 {
206     OSL_ASSERT(mpLayers);
207     if ( ! rpPainter)
208     {
209         OSL_ASSERT(rpPainter);
210         return;
211     }
212     if (nLayer<0 || nLayer>=gnMaximumLayerCount)
213     {
214         OSL_ASSERT(nLayer>=0 && nLayer<gnMaximumLayerCount);
215         return;
216     }
217 
218     // Provide the layers.
219     if (sal_uInt32(nLayer) >= mpLayers->size())
220     {
221         const sal_Int32 nOldLayerCount (mpLayers->size());
222         mpLayers->resize(nLayer+1);
223 
224         for (size_t nIndex=nOldLayerCount; nIndex<mpLayers->size(); ++nIndex)
225             (*mpLayers)[nIndex].reset(new Layer());
226     }
227 
228     (*mpLayers)[nLayer]->AddPainter(rpPainter);
229     if (nLayer == 0)
230         (*mpLayers)[nLayer]->Initialize(mpTargetWindow);
231 
232     rpPainter->SetLayerInvalidator(
233         SharedILayerInvalidator(new LayerInvalidator(shared_from_this(),mpTargetWindow,nLayer)));
234 }
235 
236 
237 
238 
RemovePainter(const SharedILayerPainter & rpPainter,const sal_Int32 nLayer)239 void LayeredDevice::RemovePainter (
240     const SharedILayerPainter& rpPainter,
241     const sal_Int32 nLayer)
242 {
243     if ( ! rpPainter)
244     {
245         OSL_ASSERT(rpPainter);
246         return;
247     }
248     if (nLayer<0 || size_t(nLayer)>=mpLayers->size())
249     {
250         OSL_ASSERT(nLayer>=0 && size_t(nLayer)<mpLayers->size());
251         return;
252     }
253 
254     rpPainter->SetLayerInvalidator(SharedILayerInvalidator());
255 
256     (*mpLayers)[nLayer]->RemovePainter(rpPainter);
257 
258     // Remove top most layers that do not contain any painters.
259     while ( ! mpLayers->empty() && ! mpLayers->back()->HasPainter())
260         mpLayers->erase(mpLayers->end()-1);
261 }
262 
263 
264 
265 
HasPainter(const sal_Int32 nLayer)266 bool LayeredDevice::HasPainter (const sal_Int32 nLayer)
267 {
268     return nLayer>=0
269         && sal_uInt32(nLayer)<mpLayers->size()
270         && (*mpLayers)[nLayer]->HasPainter();
271 }
272 
273 
274 
275 
Repaint(const Region & rRepaintRegion)276 void LayeredDevice::Repaint (const Region& rRepaintRegion)
277 {
278     // Validate the contents of all layers (that have their own devices.)
279     ::std::for_each(
280         mpLayers->begin(),
281         mpLayers->end(),
282         ::boost::bind(&Layer::Validate, _1, mpTargetWindow->GetMapMode()));
283 
284     ForAllRectangles(rRepaintRegion, ::boost::bind(&LayeredDevice::RepaintRectangle, this, _1));
285 }
286 
287 
288 
289 
RepaintRectangle(const Rectangle & rRepaintRectangle)290 void LayeredDevice::RepaintRectangle (const Rectangle& rRepaintRectangle)
291 {
292     if (mpLayers->size() == 0)
293         return;
294     else if (mpLayers->size() == 1)
295     {
296         // Just copy the main layer into the target device.
297         (*mpLayers)[0]->Repaint(*mpTargetWindow, rRepaintRectangle);
298     }
299     else
300     {
301         // Paint all layers first into the back buffer (to avoid flickering
302         // due to synchronous paints) and then copy that into the target
303         // device.
304         mpBackBuffer->SetMapMode(mpTargetWindow->GetMapMode());
305         ::std::for_each(
306             mpLayers->begin(),
307             mpLayers->end(),
308             ::boost::bind(&Layer::Repaint, _1, ::boost::ref(*mpBackBuffer), rRepaintRectangle));
309 
310         DeviceCopy(*mpTargetWindow, *mpBackBuffer, rRepaintRectangle);
311     }
312 }
313 
314 
315 
316 
Resize(void)317 void LayeredDevice::Resize (void)
318 {
319     const Size aSize (mpTargetWindow->GetSizePixel());
320     mpBackBuffer->SetOutputSizePixel(aSize);
321     ::std::for_each(mpLayers->begin(), mpLayers->end(), ::boost::bind(&Layer::Resize, _1, aSize));
322 }
323 
324 
325 
326 
Dispose(void)327 void LayeredDevice::Dispose (void)
328 {
329     ::std::for_each(mpLayers->begin(), mpLayers->end(), ::boost::bind(&Layer::Dispose, _1));
330     mpLayers->clear();
331 }
332 
333 
334 
335 
HandleMapModeChange(void)336 bool LayeredDevice::HandleMapModeChange (void)
337 {
338     const MapMode& rMapMode (mpTargetWindow->GetMapMode());
339     if (maSavedMapMode == rMapMode)
340         return false;
341 
342     const Rectangle aLogicWindowBox (
343         mpTargetWindow->PixelToLogic(Rectangle(Point(0,0), mpTargetWindow->GetSizePixel())));
344     if (maSavedMapMode.GetScaleX() != rMapMode.GetScaleX()
345         || maSavedMapMode.GetScaleY() != rMapMode.GetScaleY()
346         || maSavedMapMode.GetMapUnit() != rMapMode.GetMapUnit())
347     {
348         // When the scale has changed then we have to paint everything.
349         InvalidateAllLayers(aLogicWindowBox);
350     }
351     else if (maSavedMapMode.GetOrigin() != rMapMode.GetOrigin())
352     {
353         // Window has been scrolled.  Adapt contents of backbuffers and
354         // layer devices.
355         const Point aDelta (rMapMode.GetOrigin() - maSavedMapMode.GetOrigin());
356         mpBackBuffer->CopyArea(
357             aLogicWindowBox.TopLeft(),
358             mpTargetWindow->PixelToLogic(Point(0,0), maSavedMapMode),
359             aLogicWindowBox.GetSize());
360 
361         // Invalidate the area(s) that have been exposed.
362         const Rectangle aWindowBox (Point(0,0), mpTargetWindow->GetSizePixel());
363         if (aDelta.Y() < 0)
364             InvalidateAllLayers(mpTargetWindow->PixelToLogic(Rectangle(
365                 aWindowBox.Left(),
366                 aWindowBox.Bottom()+aDelta.Y(),
367                 aWindowBox.Right(),
368                 aWindowBox.Bottom())));
369         else if (aDelta.Y() > 0)
370             InvalidateAllLayers(mpTargetWindow->PixelToLogic(Rectangle(
371                 aWindowBox.Left(),
372                 aWindowBox.Top(),
373                 aWindowBox.Right(),
374                 aWindowBox.Top()+aDelta.Y())));
375         if (aDelta.X() < 0)
376             InvalidateAllLayers(mpTargetWindow->PixelToLogic(Rectangle(
377                 aWindowBox.Right()+aDelta.X(),
378                 aWindowBox.Top(),
379                 aWindowBox.Right(),
380                 aWindowBox.Bottom())));
381         else if (aDelta.X() > 0)
382             InvalidateAllLayers(mpTargetWindow->PixelToLogic(Rectangle(
383                 aWindowBox.Left(),
384                 aWindowBox.Top(),
385                 aWindowBox.Left()+aDelta.X(),
386                 aWindowBox.Bottom())));
387     }
388     else
389     {
390         // Can this happen?  Lets trigger a warning when it does.
391         OSL_ASSERT(false);
392     }
393 
394     maSavedMapMode = rMapMode;
395 
396     return true;
397 }
398 
399 
400 
401 
402 //===== Layer =================================================================
403 
Layer(void)404 Layer::Layer (void)
405     : mpLayerDevice(),
406       maPainters(),
407       maInvalidationRegion()
408 {
409 }
410 
411 
412 
413 
~Layer(void)414 Layer::~Layer (void)
415 {
416 }
417 
418 
419 
420 
Initialize(const SharedSdWindow & rpTargetWindow)421 void Layer::Initialize (const SharedSdWindow& rpTargetWindow)
422 {
423 #if 0
424     (void)rpTargetWindow;
425 #else
426     if ( ! mpLayerDevice)
427     {
428         mpLayerDevice.reset(new VirtualDevice(*rpTargetWindow));
429         mpLayerDevice->SetOutputSizePixel(rpTargetWindow->GetSizePixel());
430     }
431 #endif
432 }
433 
434 
435 
436 
InvalidateRectangle(const Rectangle & rInvalidationBox)437 void Layer::InvalidateRectangle (const Rectangle& rInvalidationBox)
438 {
439     maInvalidationRegion.Union(rInvalidationBox);
440 }
441 
442 
443 
444 
InvalidateRegion(const Region & rInvalidationRegion)445 void Layer::InvalidateRegion (const Region& rInvalidationRegion)
446 {
447     maInvalidationRegion.Union(rInvalidationRegion);
448 }
449 
450 
451 
452 
Validate(const MapMode & rMapMode)453 void Layer::Validate (const MapMode& rMapMode)
454 {
455     if (mpLayerDevice && ! maInvalidationRegion.IsEmpty())
456     {
457         Region aRegion (maInvalidationRegion);
458         maInvalidationRegion.SetEmpty();
459 
460         mpLayerDevice->SetMapMode(rMapMode);
461         ForAllRectangles(
462             aRegion,
463             ::boost::bind(&Layer::ValidateRectangle, this, _1));
464     }
465 }
466 
467 
468 
469 
ValidateRectangle(const Rectangle & rBox)470 void Layer::ValidateRectangle (const Rectangle& rBox)
471 {
472     if ( ! mpLayerDevice)
473         return;
474     const Region aSavedClipRegion (mpLayerDevice->GetClipRegion());
475     mpLayerDevice->IntersectClipRegion(rBox);
476 
477     for (::std::vector<SharedILayerPainter>::const_iterator
478              iPainter(maPainters.begin()),
479              iEnd(maPainters.end());
480          iPainter!=iEnd;
481          ++iPainter)
482     {
483         (*iPainter)->Paint(*mpLayerDevice, rBox);
484     }
485 
486     mpLayerDevice->SetClipRegion(aSavedClipRegion);
487 }
488 
489 
490 
491 
Repaint(OutputDevice & rTargetDevice,const Rectangle & rRepaintRectangle)492 void Layer::Repaint (
493     OutputDevice& rTargetDevice,
494     const Rectangle& rRepaintRectangle)
495 {
496     if (mpLayerDevice)
497     {
498         DeviceCopy(rTargetDevice, *mpLayerDevice, rRepaintRectangle);
499     }
500     else
501     {
502         ::std::for_each(
503             maPainters.begin(),
504             maPainters.end(),
505             ::boost::bind(&ILayerPainter::Paint,
506                 _1,
507                 ::boost::ref(rTargetDevice),
508                 rRepaintRectangle));
509     }
510 }
511 
512 
513 
514 
Resize(const Size & rSize)515 void Layer::Resize (const Size& rSize)
516 {
517     if (mpLayerDevice)
518     {
519         mpLayerDevice->SetOutputSizePixel(rSize);
520         maInvalidationRegion = Rectangle(Point(0,0), rSize);
521     }
522 }
523 
524 
525 
526 
AddPainter(const SharedILayerPainter & rpPainter)527 void Layer::AddPainter (const SharedILayerPainter& rpPainter)
528 {
529     OSL_ASSERT(::std::find(maPainters.begin(), maPainters.end(), rpPainter) == maPainters.end());
530 
531     maPainters.push_back(rpPainter);
532 }
533 
534 
535 
536 
RemovePainter(const SharedILayerPainter & rpPainter)537 void Layer::RemovePainter (const SharedILayerPainter& rpPainter)
538 {
539     const ::std::vector<SharedILayerPainter>::iterator iPainter (
540         ::std::find(maPainters.begin(), maPainters.end(), rpPainter));
541     if (iPainter != maPainters.end())
542     {
543         maPainters.erase(iPainter);
544     }
545     else
546     {
547         DBG_ASSERT(false,"LayeredDevice::RemovePainter called for painter that is not registered");
548     }
549 }
550 
551 
552 
553 
HasPainter(void) const554 bool Layer::HasPainter (void) const
555 {
556     return !maPainters.empty();
557 }
558 
559 
560 
561 
Dispose(void)562 void Layer::Dispose (void)
563 {
564     maPainters.clear();
565 }
566 
567 
568 } } } // end of namespace ::sd::slidesorter::view
569