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