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