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