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