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