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? Let's 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