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 // MARKER(update_precomp.py): autogen include statement, do not remove
23 #include "precompiled_svx.hxx"
24 #include <svx/sdr/overlay/overlaymanagerbuffered.hxx>
25 #include <vcl/outdev.hxx>
26 #include <basegfx/point/b2dpoint.hxx>
27 #include <basegfx/range/b2drange.hxx>
28 #include <vcl/salbtype.hxx>
29 #include <vcl/window.hxx>
30 #include <vcl/bitmap.hxx>
31 #include <tools/stream.hxx>
32 #include <basegfx/matrix/b2dhommatrix.hxx>
33 #include <vcl/cursor.hxx>
34 #include <vcl/dibtools.hxx>
35 
36 //////////////////////////////////////////////////////////////////////////////
37 
38 namespace sdr
39 {
40 	namespace overlay
41 	{
ImpPrepareBufferDevice()42 		void OverlayManagerBuffered::ImpPrepareBufferDevice()
43 		{
44 			// compare size of maBufferDevice with size of visible area
45 			if(maBufferDevice.GetOutputSizePixel() != getOutputDevice().GetOutputSizePixel())
46 			{
47 				// set new buffer size, copy as much content as possible (use bool parameter for vcl).
48 				// Newly uncovered regions will be repainted.
49 				maBufferDevice.SetOutputSizePixel(getOutputDevice().GetOutputSizePixel(), false);
50 			}
51 
52 			// compare the MapModes for zoom/scroll changes
53 			if(maBufferDevice.GetMapMode() != getOutputDevice().GetMapMode())
54 			{
55 				const bool bZoomed(
56 					maBufferDevice.GetMapMode().GetScaleX() != getOutputDevice().GetMapMode().GetScaleX()
57 					|| maBufferDevice.GetMapMode().GetScaleY() != getOutputDevice().GetMapMode().GetScaleY());
58 
59 				if(!bZoomed)
60 				{
61 					const Point& rOriginOld = maBufferDevice.GetMapMode().GetOrigin();
62 					const Point& rOriginNew = getOutputDevice().GetMapMode().GetOrigin();
63 					const bool bScrolled(rOriginOld != rOriginNew);
64 
65 					if(bScrolled)
66 					{
67 						// get pixel bounds
68 						const Point aOriginOldPixel(maBufferDevice.LogicToPixel(rOriginOld));
69 						const Point aOriginNewPixel(maBufferDevice.LogicToPixel(rOriginNew));
70 						const Size aOutputSizePixel(maBufferDevice.GetOutputSizePixel());
71 
72 						// remember and switch off MapMode
73 						const bool bMapModeWasEnabled(maBufferDevice.IsMapModeEnabled());
74 						maBufferDevice.EnableMapMode(false);
75 
76 						// scroll internally buffered stuff
77 						const Point aDestinationOffsetPixel(aOriginNewPixel - aOriginOldPixel);
78 						maBufferDevice.DrawOutDev(
79 							aDestinationOffsetPixel, aOutputSizePixel, // destination
80 							Point(), aOutputSizePixel); // source
81 
82 						// restore MapMode
83 						maBufferDevice.EnableMapMode(bMapModeWasEnabled);
84 
85 						// scroll remembered region, too.
86 						if(!maBufferRememberedRangePixel.isEmpty())
87 						{
88 							const basegfx::B2IPoint aIPointDestinationOffsetPixel(aDestinationOffsetPixel.X(), aDestinationOffsetPixel.Y());
89 							const basegfx::B2IPoint aNewMinimum(maBufferRememberedRangePixel.getMinimum() + aIPointDestinationOffsetPixel);
90 							const basegfx::B2IPoint aNewMaximum(maBufferRememberedRangePixel.getMaximum() + aIPointDestinationOffsetPixel);
91 							maBufferRememberedRangePixel = basegfx::B2IRange(aNewMinimum, aNewMaximum);
92 						}
93 					}
94 				}
95 
96 				// copy new MapMode
97 				maBufferDevice.SetMapMode(getOutputDevice().GetMapMode());
98 			}
99 
100 			// #i29186#
101 			maBufferDevice.SetDrawMode(getOutputDevice().GetDrawMode());
102 			maBufferDevice.SetSettings(getOutputDevice().GetSettings());
103 			maBufferDevice.SetAntialiasing(getOutputDevice().GetAntialiasing());
104 		}
105 
ImpRestoreBackground() const106 		void OverlayManagerBuffered::ImpRestoreBackground() const
107 		{
108 			const Rectangle aRegionRectanglePixel(
109 				maBufferRememberedRangePixel.getMinX(), maBufferRememberedRangePixel.getMinY(),
110 				maBufferRememberedRangePixel.getMaxX(), maBufferRememberedRangePixel.getMaxY());
111 			const Region aRegionPixel(aRegionRectanglePixel);
112 
113 			ImpRestoreBackground(aRegionPixel);
114 		}
115 
ImpRestoreBackground(const Region & rRegionPixel) const116 		void OverlayManagerBuffered::ImpRestoreBackground(const Region& rRegionPixel) const
117 		{
118 			// MapModes off
119 			const bool bMapModeWasEnabledDest(getOutputDevice().IsMapModeEnabled());
120 			const bool bMapModeWasEnabledSource(maBufferDevice.IsMapModeEnabled());
121 			getOutputDevice().EnableMapMode(false);
122 			((OverlayManagerBuffered*)this)->maBufferDevice.EnableMapMode(false);
123 
124 			// local region
125             RectangleVector aRectangles;
126             rRegionPixel.GetRegionRectangles(aRectangles);
127 
128             for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); aRectIter++)
129             {
130 #ifdef DBG_UTIL
131                 // #i72754# possible graphical region test only with non-pro
132                 static bool bDoPaintForVisualControl(false);
133 
134                 if(bDoPaintForVisualControl)
135                 {
136                     getOutputDevice().SetLineColor(COL_LIGHTGREEN);
137                     getOutputDevice().SetFillColor();
138                     getOutputDevice().DrawRect(*aRectIter);
139                 }
140 #endif
141 
142                 // restore the area
143                 const Point aTopLeft(aRectIter->TopLeft());
144                 const Size aSize(aRectIter->GetSize());
145 
146                 getOutputDevice().DrawOutDev(
147                     aTopLeft, aSize, // destination
148                     aTopLeft, aSize, // source
149                     maBufferDevice);
150             }
151 
152 			//Region aRegionPixel(rRegionPixel);
153 			//RegionHandle aRegionHandle(aRegionPixel.BeginEnumRects());
154 			//Rectangle aRegionRectanglePixel;
155 			//
156 			//while(aRegionPixel.GetEnumRects(aRegionHandle, aRegionRectanglePixel))
157 			//{
158 #ifdef DBG_U//TIL
159 			//	// #i72754# possible graphical region test only with non-pro
160 			//	static bool bDoPaintForVisualControl(false);
161 			//	if(bDoPaintForVisualControl)
162 			//	{
163 			//		getOutputDevice().SetLineColor(COL_LIGHTGREEN);
164 			//		getOutputDevice().SetFillColor();
165 			//		getOutputDevice().DrawRect(aRegionRectanglePixel);
166 			//	}
167 #endif      //
168 			//	// restore the area
169 			//	const Point aTopLeft(aRegionRectanglePixel.TopLeft());
170 			//	const Size aSize(aRegionRectanglePixel.GetSize());
171             //
172 			//	getOutputDevice().DrawOutDev(
173 			//		aTopLeft, aSize, // destination
174 			//		aTopLeft, aSize, // source
175 			//		maBufferDevice);
176 			//}
177             //
178 			//aRegionPixel.EndEnumRects(aRegionHandle);
179 
180 			// restore MapModes
181 			getOutputDevice().EnableMapMode(bMapModeWasEnabledDest);
182 			((OverlayManagerBuffered*)this)->maBufferDevice.EnableMapMode(bMapModeWasEnabledSource);
183 		}
184 
ImpSaveBackground(const Region & rRegion,OutputDevice * pPreRenderDevice)185 		void OverlayManagerBuffered::ImpSaveBackground(const Region& rRegion, OutputDevice* pPreRenderDevice)
186 		{
187 			// prepare source
188 			OutputDevice& rSource = (pPreRenderDevice) ? *pPreRenderDevice : getOutputDevice();
189 
190 			// Ensure buffer is valid
191 			ImpPrepareBufferDevice();
192 
193 			// build region which needs to be copied
194 			Region aRegion(rSource.LogicToPixel(rRegion));
195 
196 			// limit to PaintRegion if it's a window. This will be evtl. the expanded one,
197 			// but always the exact redraw area
198 			if(OUTDEV_WINDOW == rSource.GetOutDevType())
199 			{
200 				Window& rWindow = (Window&)rSource;
201 				Region aPaintRegionPixel = rWindow.LogicToPixel(rWindow.GetPaintRegion());
202 				aRegion.Intersect(aPaintRegionPixel);
203 
204 				// #i72754# Make sure content is completetly rendered, the window
205 				// will be used as source of a DrawOutDev soon
206 				rWindow.Flush();
207 			}
208 
209 			// also limit to buffer size
210 			const Rectangle aBufferDeviceRectanglePixel(Point(), maBufferDevice.GetOutputSizePixel());
211 			aRegion.Intersect(aBufferDeviceRectanglePixel);
212 
213 			// MapModes off
214 			const bool bMapModeWasEnabledDest(rSource.IsMapModeEnabled());
215 			const bool bMapModeWasEnabledSource(maBufferDevice.IsMapModeEnabled());
216 			rSource.EnableMapMode(false);
217 			maBufferDevice.EnableMapMode(false);
218 
219 			// prepare to iterate over the rectangles from the region in pixels
220             RectangleVector aRectangles;
221             aRegion.GetRegionRectangles(aRectangles);
222 
223             for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); aRectIter++)
224             {
225                 // for each rectangle, save the area
226                 const Point aTopLeft(aRectIter->TopLeft());
227                 const Size aSize(aRectIter->GetSize());
228 
229                 maBufferDevice.DrawOutDev(
230                     aTopLeft, aSize, // destination
231                     aTopLeft, aSize, // source
232                     rSource);
233 
234 #ifdef DBG_UTIL
235                 // #i72754# possible graphical region test only with non-pro
236                 static bool bDoPaintForVisualControl(false);
237 
238                 if(bDoPaintForVisualControl)
239                 {
240                     const bool bMapModeWasEnabledTest(getOutputDevice().IsMapModeEnabled());
241 
242                     getOutputDevice().EnableMapMode(false);
243                     getOutputDevice().SetLineColor(COL_LIGHTRED);
244                     getOutputDevice().SetFillColor();
245                     getOutputDevice().DrawRect(*aRectIter);
246                     getOutputDevice().EnableMapMode(bMapModeWasEnabledTest);
247                 }
248 
249                 static bool bDoSaveForVisualControl(false);
250 
251                 if(bDoSaveForVisualControl)
252                 {
253                     const Bitmap aBitmap(maBufferDevice.GetBitmap(aTopLeft, aSize));
254                     SvFileStream aNew((const String&)String(ByteString( "c:\\test.bmp" ), RTL_TEXTENCODING_UTF8), STREAM_WRITE|STREAM_TRUNC);
255                     WriteDIB(aBitmap, aNew, false, true);
256                 }
257 #endif
258             }
259 
260 			//RegionHandle aRegionHandle(aRegion.BeginEnumRects());
261 			//Rectangle aRegionRectanglePixel;
262             //
263 			//while(aRegion.GetEnumRects(aRegionHandle, aRegionRectanglePixel))
264 			//{
265 			//	// for each rectangle, save the area
266 			//	Point aTopLeft(aRegionRectanglePixel.TopLeft());
267 			//	Size aSize(aRegionRectanglePixel.GetSize());
268             //
269 			//	maBufferDevice.DrawOutDev(
270 			//		aTopLeft, aSize, // destination
271 			//		aTopLeft, aSize, // source
272 			//		rSource);
273             //
274 #ifdef DBG_U//TIL
275 			//	// #i72754# possible graphical region test only with non-pro
276 			//	static bool bDoPaintForVisualControl(false);
277 			//	if(bDoPaintForVisualControl)
278 			//	{
279 			//		const bool bMapModeWasEnabledTest(getOutputDevice().IsMapModeEnabled());
280 			//		getOutputDevice().EnableMapMode(false);
281 			//		getOutputDevice().SetLineColor(COL_LIGHTRED);
282 			//		getOutputDevice().SetFillColor();
283 			//		getOutputDevice().DrawRect(aRegionRectanglePixel);
284 			//		getOutputDevice().EnableMapMode(bMapModeWasEnabledTest);
285 			//	}
286             //
287 			//	static bool bDoSaveForVisualControl(false);
288 			//	if(bDoSaveForVisualControl)
289 			//	{
290 			//		const Bitmap aBitmap(maBufferDevice.GetBitmap(aTopLeft, aSize));
291 			//		SvFileStream aNew((const String&)String(ByteString( "c:\\test.bmp" ), RTL_TEXTENCODING_UTF8), STREAM_WRITE|STREAM_TRUNC);
292 			//		aNew << aBitmap;
293 			//	}
294 #endif      //
295 			//}
296             //
297 			//aRegion.EndEnumRects(aRegionHandle);
298 
299 			// restore MapModes
300 			rSource.EnableMapMode(bMapModeWasEnabledDest);
301 			maBufferDevice.EnableMapMode(bMapModeWasEnabledSource);
302 		}
303 
304 		IMPL_LINK(OverlayManagerBuffered, ImpBufferTimerHandler, AutoTimer*, /*pTimer*/)
305 		{
306 			// stop timer
307 			maBufferTimer.Stop();
308 
309 			if(!maBufferRememberedRangePixel.isEmpty())
310 			{
311 				// logic size for impDrawMember call
312                 basegfx::B2DRange aBufferRememberedRangeLogic(
313                     maBufferRememberedRangePixel.getMinX(), maBufferRememberedRangePixel.getMinY(),
314 					maBufferRememberedRangePixel.getMaxX(), maBufferRememberedRangePixel.getMaxY());
315                 aBufferRememberedRangeLogic.transform(getOutputDevice().GetInverseViewTransformation());
316 
317                 // prepare cursor handling
318                 const bool bTargetIsWindow(OUTDEV_WINDOW == rmOutputDevice.GetOutDevType());
319                 bool bCursorWasEnabled(false);
320 
321                 // #i80730# switch off VCL cursor during overlay refresh
322 				if(bTargetIsWindow)
323 				{
324 					Window& rWindow = static_cast< Window& >(rmOutputDevice);
325 					Cursor* pCursor = rWindow.GetCursor();
326 
327                     if(pCursor && pCursor->IsVisible())
328                     {
329                         pCursor->Hide();
330                         bCursorWasEnabled = true;
331                     }
332 				}
333 
334 				if(DoRefreshWithPreRendering())
335 				{
336 					// #i73602# ensure valid and sized maOutputBufferDevice
337 					const Size aDestinationSizePixel(maBufferDevice.GetOutputSizePixel());
338 					const Size aOutputBufferSizePixel(maOutputBufferDevice.GetOutputSizePixel());
339 
340 					if(aDestinationSizePixel != aOutputBufferSizePixel)
341 					{
342 						maOutputBufferDevice.SetOutputSizePixel(aDestinationSizePixel);
343 					}
344 
345 					maOutputBufferDevice.SetMapMode(getOutputDevice().GetMapMode());
346 					maOutputBufferDevice.EnableMapMode(false);
347 					maOutputBufferDevice.SetDrawMode(maBufferDevice.GetDrawMode());
348 					maOutputBufferDevice.SetSettings(maBufferDevice.GetSettings());
349 					maOutputBufferDevice.SetAntialiasing(maBufferDevice.GetAntialiasing());
350 
351 					// calculate sizes
352 					Rectangle aRegionRectanglePixel(
353 						maBufferRememberedRangePixel.getMinX(), maBufferRememberedRangePixel.getMinY(),
354 						maBufferRememberedRangePixel.getMaxX(), maBufferRememberedRangePixel.getMaxY());
355 
356 					// truncate aRegionRectanglePixel to destination pixel size, more does
357 					// not need to be prepared since destination is a buffer for a window. So,
358 					// maximum size indirectly shall be limited to getOutputDevice().GetOutputSizePixel()
359 					if(aRegionRectanglePixel.Left() < 0L)
360 					{
361 						aRegionRectanglePixel.Left() = 0L;
362 					}
363 
364 					if(aRegionRectanglePixel.Top() < 0L)
365 					{
366 						aRegionRectanglePixel.Top() = 0L;
367 					}
368 
369 					if(aRegionRectanglePixel.Right() > aDestinationSizePixel.getWidth())
370 					{
371 						aRegionRectanglePixel.Right() = aDestinationSizePixel.getWidth();
372 					}
373 
374 					if(aRegionRectanglePixel.Bottom() > aDestinationSizePixel.getHeight())
375 					{
376 						aRegionRectanglePixel.Bottom() = aDestinationSizePixel.getHeight();
377 					}
378 
379 					// get sizes
380 					const Point aTopLeft(aRegionRectanglePixel.TopLeft());
381 					const Size aSize(aRegionRectanglePixel.GetSize());
382 
383 					{
384 						const bool bMapModeWasEnabledDest(maBufferDevice.IsMapModeEnabled());
385 						maBufferDevice.EnableMapMode(false);
386 
387 						maOutputBufferDevice.DrawOutDev(
388 							aTopLeft, aSize, // destination
389 							aTopLeft, aSize, // source
390 							maBufferDevice);
391 
392 						// restore MapModes
393 						maBufferDevice.EnableMapMode(bMapModeWasEnabledDest);
394 					}
395 
396 					// paint overlay content for remembered region, use
397 					// method from base class directly
398 					maOutputBufferDevice.EnableMapMode(true);
399 					OverlayManager::ImpDrawMembers(aBufferRememberedRangeLogic, maOutputBufferDevice);
400 					maOutputBufferDevice.EnableMapMode(false);
401 
402 					// copy to output
403 					{
404 						const bool bMapModeWasEnabledDest(getOutputDevice().IsMapModeEnabled());
405 						getOutputDevice().EnableMapMode(false);
406 
407 						getOutputDevice().DrawOutDev(
408 							aTopLeft, aSize, // destination
409 							aTopLeft, aSize, // source
410 							maOutputBufferDevice);
411 
412 						// debug
413 						/*getOutputDevice().SetLineColor(COL_RED);
414 						getOutputDevice().SetFillColor();
415 						getOutputDevice().DrawRect(Rectangle(aTopLeft, aSize));*/
416 
417 						// restore MapModes
418 						getOutputDevice().EnableMapMode(bMapModeWasEnabledDest);
419 					}
420 				}
421 				else
422 				{
423 					// Restore all rectangles for remembered region from buffer
424 					ImpRestoreBackground();
425 
426 					// paint overlay content for remembered region, use
427 					// method from base class directly
428 					OverlayManager::ImpDrawMembers(aBufferRememberedRangeLogic, getOutputDevice());
429 				}
430 
431 				// VCL hack for transparent child windows
432 				// Problem is e.g. a radiobuttion form control in life mode. The used window
433 				// is a transparence vcl childwindow. This flag only allows the parent window to
434 				// paint into the child windows area, but there is no mechanism which takes
435 				// care for a repaint of the child window. A transparent child window is NOT
436 				// a window which always keeps it's content consistent over the parent, but it's
437 				// more like just a paint flag for the parent.
438 				// To get the update, the windows in question are updated manulally here.
439 				if(bTargetIsWindow)
440 				{
441 					Window& rWindow = static_cast< Window& >(rmOutputDevice);
442 
443 					if(rWindow.IsChildTransparentModeEnabled() && rWindow.GetChildCount())
444 					{
445 						const Rectangle aRegionRectanglePixel(
446 							maBufferRememberedRangePixel.getMinX(), maBufferRememberedRangePixel.getMinY(),
447 							maBufferRememberedRangePixel.getMaxX(), maBufferRememberedRangePixel.getMaxY());
448 
449 						for(sal_uInt16 a(0); a < rWindow.GetChildCount(); a++)
450 						{
451 							Window* pCandidate = rWindow.GetChild(a);
452 
453 							if(pCandidate && pCandidate->IsPaintTransparent())
454 							{
455 								const Rectangle aCandidatePosSizePixel(pCandidate->GetPosPixel(), pCandidate->GetSizePixel());
456 
457 								if(aCandidatePosSizePixel.IsOver(aRegionRectanglePixel))
458 								{
459 									pCandidate->Invalidate(INVALIDATE_NOTRANSPARENT|INVALIDATE_CHILDREN);
460 									pCandidate->Update();
461 								}
462 							}
463 						}
464 					}
465 				}
466 
467                 // #i80730# restore visibility of VCL cursor
468 				if(bCursorWasEnabled)
469                 {
470 					Window& rWindow = static_cast< Window& >(rmOutputDevice);
471 					Cursor* pCursor = rWindow.GetCursor();
472 
473                     if(pCursor)
474                     {
475                         // check if cursor still exists. It may have been deleted from someone
476                         pCursor->Show();
477                     }
478 				}
479 
480 				// forget remembered Region
481 				maBufferRememberedRangePixel.reset();
482 			}
483 
484 			return 0;
485 		}
486 
OverlayManagerBuffered(OutputDevice & rOutputDevice,bool bRefreshWithPreRendering)487 		OverlayManagerBuffered::OverlayManagerBuffered(
488 			OutputDevice& rOutputDevice,
489 			bool bRefreshWithPreRendering)
490 		:	OverlayManager(rOutputDevice),
491 			mbRefreshWithPreRendering(bRefreshWithPreRendering)
492 		{
493 			// Init timer
494 			maBufferTimer.SetTimeout(1);
495 			maBufferTimer.SetTimeoutHdl(LINK(this, OverlayManagerBuffered, ImpBufferTimerHandler));
496 		}
497 
~OverlayManagerBuffered()498 		OverlayManagerBuffered::~OverlayManagerBuffered()
499 		{
500 			// Clear timer
501 			maBufferTimer.Stop();
502 
503 			if(!maBufferRememberedRangePixel.isEmpty())
504 			{
505 				// Restore all rectangles for remembered region from buffer
506 				ImpRestoreBackground();
507 			}
508 		}
509 
completeRedraw(const Region & rRegion,OutputDevice * pPreRenderDevice) const510 		void OverlayManagerBuffered::completeRedraw(const Region& rRegion, OutputDevice* pPreRenderDevice) const
511 		{
512 			if(!rRegion.IsEmpty())
513 			{
514 				// save new background
515 				((OverlayManagerBuffered*)this)->ImpSaveBackground(rRegion, pPreRenderDevice);
516 			}
517 
518 			// call parent
519 			OverlayManager::completeRedraw(rRegion, pPreRenderDevice);
520 		}
521 
flush()522 		void OverlayManagerBuffered::flush()
523 		{
524 			// call timer handler direct
525 			ImpBufferTimerHandler(0);
526 		}
527 
528 		// #i68597# part of content gets copied, react on it
copyArea(const Point & rDestPt,const Point & rSrcPt,const Size & rSrcSize)529 		void OverlayManagerBuffered::copyArea(const Point& rDestPt, const Point& rSrcPt, const Size& rSrcSize)
530 		{
531 			// scroll local buffered area
532 			maBufferDevice.CopyArea(rDestPt, rSrcPt, rSrcSize);
533 		}
534 
restoreBackground(const Region & rRegion) const535 		void OverlayManagerBuffered::restoreBackground(const Region& rRegion) const
536 		{
537 			// restore
538 			const Region aRegionPixel(getOutputDevice().LogicToPixel(rRegion));
539 			ImpRestoreBackground(aRegionPixel);
540 
541 			// call parent
542 			OverlayManager::restoreBackground(rRegion);
543 		}
544 
invalidateRange(const basegfx::B2DRange & rRange)545 		void OverlayManagerBuffered::invalidateRange(const basegfx::B2DRange& rRange)
546 		{
547             if(!rRange.isEmpty())
548             {
549 			    // buffered output, do not invalidate but use the timer
550 			    // to trigger a timer event for refresh
551 			    maBufferTimer.Start();
552 
553 			    // add the discrete range to the remembered region
554 			    // #i75163# use double precision and floor/ceil rounding to get overlapped pixel region, even
555 			    // when the given logic region has a width/height of 0.0. This does NOT work with LogicToPixel
556 			    // since it just transforms the top left and bottom right points equally without taking
557 			    // discrete pixel coverage into account. An empty B2DRange and thus empty logic Rectangle translated
558 			    // to an also empty discrete pixel rectangle - what is wrong.
559 			    basegfx::B2DRange aDiscreteRange(rRange);
560 			    aDiscreteRange.transform(getOutputDevice().GetViewTransformation());
561 
562 			    if(maDrawinglayerOpt.IsAntiAliasing())
563 			    {
564 				    // assume AA needs one pixel more and invalidate one pixel more
565                     const double fDiscreteOne(getDiscreteOne());
566 				    const basegfx::B2IPoint aTopLeft(
567 					    (sal_Int32)floor(aDiscreteRange.getMinX() - fDiscreteOne),
568 					    (sal_Int32)floor(aDiscreteRange.getMinY() - fDiscreteOne));
569 				    const basegfx::B2IPoint aBottomRight(
570 					    (sal_Int32)ceil(aDiscreteRange.getMaxX() + fDiscreteOne),
571 					    (sal_Int32)ceil(aDiscreteRange.getMaxY() + fDiscreteOne));
572 
573 				    maBufferRememberedRangePixel.expand(aTopLeft);
574 				    maBufferRememberedRangePixel.expand(aBottomRight);
575 			    }
576 			    else
577 			    {
578 				    const basegfx::B2IPoint aTopLeft((sal_Int32)floor(aDiscreteRange.getMinX()), (sal_Int32)floor(aDiscreteRange.getMinY()));
579 				    const basegfx::B2IPoint aBottomRight((sal_Int32)ceil(aDiscreteRange.getMaxX()), (sal_Int32)ceil(aDiscreteRange.getMaxY()));
580 
581 				    maBufferRememberedRangePixel.expand(aTopLeft);
582 				    maBufferRememberedRangePixel.expand(aBottomRight);
583 			    }
584             }
585 		}
586 
SetRefreshWithPreRendering(bool bNew)587 		void OverlayManagerBuffered::SetRefreshWithPreRendering(bool bNew)
588 		{
589 			if((bool)mbRefreshWithPreRendering != bNew)
590 			{
591 				mbRefreshWithPreRendering = bNew;
592 			}
593 		}
594 	} // end of namespace overlay
595 } // end of namespace sdr
596 
597 //////////////////////////////////////////////////////////////////////////////
598 // eof
599