1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: overlaymanagerbuffered.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svx.hxx"
33 #include <svx/sdr/overlay/overlaymanagerbuffered.hxx>
34 #include <vcl/outdev.hxx>
35 #include <basegfx/point/b2dpoint.hxx>
36 #include <basegfx/range/b2drange.hxx>
37 #include <vcl/salbtype.hxx>
38 #include <vcl/window.hxx>
39 #include <vcl/bitmap.hxx>
40 #include <tools/stream.hxx>
41 #include <basegfx/matrix/b2dhommatrix.hxx>
42 #include <vcl/cursor.hxx>
44 //////////////////////////////////////////////////////////////////////////////
50 void OverlayManagerBuffered::ImpPrepareBufferDevice()
52 // compare size of maBufferDevice with size of visible area
53 if(maBufferDevice
.GetOutputSizePixel() != getOutputDevice().GetOutputSizePixel())
55 // set new buffer size, copy as much content as possible (use bool parameter for vcl).
56 // Newly uncovered regions will be repainted.
57 maBufferDevice
.SetOutputSizePixel(getOutputDevice().GetOutputSizePixel(), false);
60 // compare the MapModes for zoom/scroll changes
61 if(maBufferDevice
.GetMapMode() != getOutputDevice().GetMapMode())
64 maBufferDevice
.GetMapMode().GetScaleX() != getOutputDevice().GetMapMode().GetScaleX()
65 || maBufferDevice
.GetMapMode().GetScaleY() != getOutputDevice().GetMapMode().GetScaleY());
69 const Point
& rOriginOld
= maBufferDevice
.GetMapMode().GetOrigin();
70 const Point
& rOriginNew
= getOutputDevice().GetMapMode().GetOrigin();
71 const bool bScrolled(rOriginOld
!= rOriginNew
);
76 const Point
aOriginOldPixel(maBufferDevice
.LogicToPixel(rOriginOld
));
77 const Point
aOriginNewPixel(maBufferDevice
.LogicToPixel(rOriginNew
));
78 const Size
aOutputSizePixel(maBufferDevice
.GetOutputSizePixel());
80 // remember and switch off MapMode
81 const bool bMapModeWasEnabled(maBufferDevice
.IsMapModeEnabled());
82 maBufferDevice
.EnableMapMode(false);
84 // scroll internally buffered stuff
85 const Point
aDestinationOffsetPixel(aOriginNewPixel
- aOriginOldPixel
);
86 maBufferDevice
.DrawOutDev(
87 aDestinationOffsetPixel
, aOutputSizePixel
, // destination
88 Point(), aOutputSizePixel
); // source
91 maBufferDevice
.EnableMapMode(bMapModeWasEnabled
);
93 // scroll remembered region, too.
94 if(!maBufferRememberedRangePixel
.isEmpty())
96 const basegfx::B2IPoint
aIPointDestinationOffsetPixel(aDestinationOffsetPixel
.X(), aDestinationOffsetPixel
.Y());
97 const basegfx::B2IPoint
aNewMinimum(maBufferRememberedRangePixel
.getMinimum() + aIPointDestinationOffsetPixel
);
98 const basegfx::B2IPoint
aNewMaximum(maBufferRememberedRangePixel
.getMaximum() + aIPointDestinationOffsetPixel
);
99 maBufferRememberedRangePixel
= basegfx::B2IRange(aNewMinimum
, aNewMaximum
);
105 maBufferDevice
.SetMapMode(getOutputDevice().GetMapMode());
109 maBufferDevice
.SetDrawMode(getOutputDevice().GetDrawMode());
110 maBufferDevice
.SetSettings(getOutputDevice().GetSettings());
111 maBufferDevice
.SetAntialiasing(getOutputDevice().GetAntialiasing());
114 void OverlayManagerBuffered::ImpRestoreBackground() const
116 const Rectangle
aRegionRectanglePixel(
117 maBufferRememberedRangePixel
.getMinX(), maBufferRememberedRangePixel
.getMinY(),
118 maBufferRememberedRangePixel
.getMaxX(), maBufferRememberedRangePixel
.getMaxY());
119 const Region
aRegionPixel(aRegionRectanglePixel
);
121 ImpRestoreBackground(aRegionPixel
);
124 void OverlayManagerBuffered::ImpRestoreBackground(const Region
& rRegionPixel
) const
127 Region
aRegionPixel(rRegionPixel
);
128 RegionHandle
aRegionHandle(aRegionPixel
.BeginEnumRects());
129 Rectangle aRegionRectanglePixel
;
132 const bool bMapModeWasEnabledDest(getOutputDevice().IsMapModeEnabled());
133 const bool bMapModeWasEnabledSource(maBufferDevice
.IsMapModeEnabled());
134 getOutputDevice().EnableMapMode(false);
135 ((OverlayManagerBuffered
*)this)->maBufferDevice
.EnableMapMode(false);
137 while(aRegionPixel
.GetEnumRects(aRegionHandle
, aRegionRectanglePixel
))
140 // #i72754# possible graphical region test only with non-pro
141 static bool bDoPaintForVisualControl(false);
142 if(bDoPaintForVisualControl
)
144 getOutputDevice().SetLineColor(COL_LIGHTGREEN
);
145 getOutputDevice().SetFillColor();
146 getOutputDevice().DrawRect(aRegionRectanglePixel
);
151 const Point
aTopLeft(aRegionRectanglePixel
.TopLeft());
152 const Size
aSize(aRegionRectanglePixel
.GetSize());
154 getOutputDevice().DrawOutDev(
155 aTopLeft
, aSize
, // destination
156 aTopLeft
, aSize
, // source
160 aRegionPixel
.EndEnumRects(aRegionHandle
);
163 getOutputDevice().EnableMapMode(bMapModeWasEnabledDest
);
164 ((OverlayManagerBuffered
*)this)->maBufferDevice
.EnableMapMode(bMapModeWasEnabledSource
);
167 void OverlayManagerBuffered::ImpSaveBackground(const Region
& rRegion
, OutputDevice
* pPreRenderDevice
)
170 OutputDevice
& rSource
= (pPreRenderDevice
) ? *pPreRenderDevice
: getOutputDevice();
172 // Ensure buffer is valid
173 ImpPrepareBufferDevice();
175 // build region which needs to be copied
176 Region
aRegion(rSource
.LogicToPixel(rRegion
));
178 // limit to PaintRegion if it's a window. This will be evtl. the expanded one,
179 // but always the exact redraw area
180 if(OUTDEV_WINDOW
== rSource
.GetOutDevType())
182 Window
& rWindow
= (Window
&)rSource
;
183 Region aPaintRegionPixel
= rWindow
.LogicToPixel(rWindow
.GetPaintRegion());
184 aRegion
.Intersect(aPaintRegionPixel
);
186 // #i72754# Make sure content is completetly rendered, the window
187 // will be used as source of a DrawOutDev soon
191 // also limit to buffer size
192 const Rectangle aBufferDeviceRectanglePixel
= Rectangle(Point(), maBufferDevice
.GetOutputSizePixel());
193 aRegion
.Intersect(aBufferDeviceRectanglePixel
);
195 // prepare to iterate over the rectangles from the region in pixels
196 RegionHandle
aRegionHandle(aRegion
.BeginEnumRects());
197 Rectangle aRegionRectanglePixel
;
200 const bool bMapModeWasEnabledDest(rSource
.IsMapModeEnabled());
201 const bool bMapModeWasEnabledSource(maBufferDevice
.IsMapModeEnabled());
202 rSource
.EnableMapMode(false);
203 maBufferDevice
.EnableMapMode(false);
205 while(aRegion
.GetEnumRects(aRegionHandle
, aRegionRectanglePixel
))
207 // for each rectangle, save the area
208 Point
aTopLeft(aRegionRectanglePixel
.TopLeft());
209 Size
aSize(aRegionRectanglePixel
.GetSize());
211 maBufferDevice
.DrawOutDev(
212 aTopLeft
, aSize
, // destination
213 aTopLeft
, aSize
, // source
217 // #i72754# possible graphical region test only with non-pro
218 static bool bDoPaintForVisualControl(false);
219 if(bDoPaintForVisualControl
)
221 const bool bMapModeWasEnabledTest(getOutputDevice().IsMapModeEnabled());
222 getOutputDevice().EnableMapMode(false);
223 getOutputDevice().SetLineColor(COL_LIGHTRED
);
224 getOutputDevice().SetFillColor();
225 getOutputDevice().DrawRect(aRegionRectanglePixel
);
226 getOutputDevice().EnableMapMode(bMapModeWasEnabledTest
);
229 static bool bDoSaveForVisualControl(false);
230 if(bDoSaveForVisualControl
)
232 const Bitmap
aBitmap(maBufferDevice
.GetBitmap(aTopLeft
, aSize
));
233 SvFileStream
aNew((const String
&)String(ByteString( "c:\\test.bmp" ), RTL_TEXTENCODING_UTF8
), STREAM_WRITE
|STREAM_TRUNC
);
239 aRegion
.EndEnumRects(aRegionHandle
);
242 rSource
.EnableMapMode(bMapModeWasEnabledDest
);
243 maBufferDevice
.EnableMapMode(bMapModeWasEnabledSource
);
246 IMPL_LINK(OverlayManagerBuffered
, ImpBufferTimerHandler
, AutoTimer
*, /*pTimer*/)
249 maBufferTimer
.Stop();
251 if(!maBufferRememberedRangePixel
.isEmpty())
253 // logic size for impDrawMember call
254 basegfx::B2DRange
aBufferRememberedRangeLogic(
255 maBufferRememberedRangePixel
.getMinX(), maBufferRememberedRangePixel
.getMinY(),
256 maBufferRememberedRangePixel
.getMaxX(), maBufferRememberedRangePixel
.getMaxY());
257 aBufferRememberedRangeLogic
.transform(getOutputDevice().GetInverseViewTransformation());
259 // prepare cursor handling
260 const bool bTargetIsWindow(OUTDEV_WINDOW
== rmOutputDevice
.GetOutDevType());
261 bool bCursorWasEnabled(false);
263 // #i80730# switch off VCL cursor during overlay refresh
266 Window
& rWindow
= static_cast< Window
& >(rmOutputDevice
);
267 Cursor
* pCursor
= rWindow
.GetCursor();
269 if(pCursor
&& pCursor
->IsVisible())
272 bCursorWasEnabled
= true;
276 if(DoRefreshWithPreRendering())
278 // #i73602# ensure valid and sized maOutputBufferDevice
279 const Size
aDestinationSizePixel(maBufferDevice
.GetOutputSizePixel());
280 const Size
aOutputBufferSizePixel(maOutputBufferDevice
.GetOutputSizePixel());
282 if(aDestinationSizePixel
!= aOutputBufferSizePixel
)
284 maOutputBufferDevice
.SetOutputSizePixel(aDestinationSizePixel
);
287 maOutputBufferDevice
.SetMapMode(getOutputDevice().GetMapMode());
288 maOutputBufferDevice
.EnableMapMode(false);
289 maOutputBufferDevice
.SetDrawMode(maBufferDevice
.GetDrawMode());
290 maOutputBufferDevice
.SetSettings(maBufferDevice
.GetSettings());
291 maOutputBufferDevice
.SetAntialiasing(maBufferDevice
.GetAntialiasing());
294 Rectangle
aRegionRectanglePixel(
295 maBufferRememberedRangePixel
.getMinX(), maBufferRememberedRangePixel
.getMinY(),
296 maBufferRememberedRangePixel
.getMaxX(), maBufferRememberedRangePixel
.getMaxY());
298 // truncate aRegionRectanglePixel to destination pixel size, more does
299 // not need to be prepared since destination is a buffer for a window. So,
300 // maximum size indirectly shall be limited to getOutputDevice().GetOutputSizePixel()
301 if(aRegionRectanglePixel
.Left() < 0L)
303 aRegionRectanglePixel
.Left() = 0L;
306 if(aRegionRectanglePixel
.Top() < 0L)
308 aRegionRectanglePixel
.Top() = 0L;
311 if(aRegionRectanglePixel
.Right() > aDestinationSizePixel
.getWidth())
313 aRegionRectanglePixel
.Right() = aDestinationSizePixel
.getWidth();
316 if(aRegionRectanglePixel
.Bottom() > aDestinationSizePixel
.getHeight())
318 aRegionRectanglePixel
.Bottom() = aDestinationSizePixel
.getHeight();
322 const Point
aTopLeft(aRegionRectanglePixel
.TopLeft());
323 const Size
aSize(aRegionRectanglePixel
.GetSize());
326 const bool bMapModeWasEnabledDest(maBufferDevice
.IsMapModeEnabled());
327 maBufferDevice
.EnableMapMode(false);
329 maOutputBufferDevice
.DrawOutDev(
330 aTopLeft
, aSize
, // destination
331 aTopLeft
, aSize
, // source
335 maBufferDevice
.EnableMapMode(bMapModeWasEnabledDest
);
338 // paint overlay content for remembered region, use
339 // method from base class directly
340 maOutputBufferDevice
.EnableMapMode(true);
341 OverlayManager::ImpDrawMembers(aBufferRememberedRangeLogic
, maOutputBufferDevice
);
342 maOutputBufferDevice
.EnableMapMode(false);
346 const bool bMapModeWasEnabledDest(getOutputDevice().IsMapModeEnabled());
347 getOutputDevice().EnableMapMode(false);
349 getOutputDevice().DrawOutDev(
350 aTopLeft
, aSize
, // destination
351 aTopLeft
, aSize
, // source
352 maOutputBufferDevice
);
355 /*getOutputDevice().SetLineColor(COL_RED);
356 getOutputDevice().SetFillColor();
357 getOutputDevice().DrawRect(Rectangle(aTopLeft, aSize));*/
360 getOutputDevice().EnableMapMode(bMapModeWasEnabledDest
);
365 // Restore all rectangles for remembered region from buffer
366 ImpRestoreBackground();
368 // paint overlay content for remembered region, use
369 // method from base class directly
370 OverlayManager::ImpDrawMembers(aBufferRememberedRangeLogic
, getOutputDevice());
373 // #i80730# restore visibility of VCL cursor
374 if(bCursorWasEnabled
)
376 Window
& rWindow
= static_cast< Window
& >(rmOutputDevice
);
377 Cursor
* pCursor
= rWindow
.GetCursor();
381 // check if cursor still exists. It may have been deleted from someone
386 // forget remembered Region
387 maBufferRememberedRangePixel
.reset();
393 OverlayManagerBuffered::OverlayManagerBuffered(
394 OutputDevice
& rOutputDevice
,
395 OverlayManager
* pOldOverlayManager
,
396 bool bRefreshWithPreRendering
)
397 : OverlayManager(rOutputDevice
, pOldOverlayManager
),
398 mbRefreshWithPreRendering(bRefreshWithPreRendering
)
401 maBufferTimer
.SetTimeout(1);
402 maBufferTimer
.SetTimeoutHdl(LINK(this, OverlayManagerBuffered
, ImpBufferTimerHandler
));
405 OverlayManagerBuffered::~OverlayManagerBuffered()
408 maBufferTimer
.Stop();
410 if(!maBufferRememberedRangePixel
.isEmpty())
412 // Restore all rectangles for remembered region from buffer
413 ImpRestoreBackground();
417 void OverlayManagerBuffered::completeRedraw(const Region
& rRegion
, OutputDevice
* pPreRenderDevice
) const
419 if(!rRegion
.IsEmpty())
421 // save new background
422 ((OverlayManagerBuffered
*)this)->ImpSaveBackground(rRegion
, pPreRenderDevice
);
426 OverlayManager::completeRedraw(rRegion
, pPreRenderDevice
);
429 void OverlayManagerBuffered::flush()
431 // call timer handler direct
432 ImpBufferTimerHandler(0);
435 // #i68597# part of content gets copied, react on it
436 void OverlayManagerBuffered::copyArea(const Point
& rDestPt
, const Point
& rSrcPt
, const Size
& rSrcSize
)
438 // scroll local buffered area
439 maBufferDevice
.CopyArea(rDestPt
, rSrcPt
, rSrcSize
);
442 void OverlayManagerBuffered::restoreBackground(const Region
& rRegion
) const
445 const Region
aRegionPixel(getOutputDevice().LogicToPixel(rRegion
));
446 ImpRestoreBackground(aRegionPixel
);
449 OverlayManager::restoreBackground(rRegion
);
452 void OverlayManagerBuffered::invalidateRange(const basegfx::B2DRange
& rRange
)
454 if(!rRange
.isEmpty())
456 // buffered output, do not invalidate but use the timer
457 // to trigger a timer event for refresh
458 maBufferTimer
.Start();
460 // add the discrete range to the remembered region
461 // #i75163# use double precision and floor/ceil rounding to get overlapped pixel region, even
462 // when the given logic region has a width/height of 0.0. This does NOT work with LogicToPixel
463 // since it just transforms the top left and bottom right points equally without taking
464 // discrete pixel coverage into account. An empty B2DRange and thus empty logic Rectangle translated
465 // to an also empty discrete pixel rectangle - what is wrong.
466 basegfx::B2DRange
aDiscreteRange(rRange
);
467 aDiscreteRange
.transform(getOutputDevice().GetViewTransformation());
469 if(maDrawinglayerOpt
.IsAntiAliasing())
471 // assume AA needs one pixel more and invalidate one pixel more
472 const double fDiscreteOne(getDiscreteOne());
473 const basegfx::B2IPoint
aTopLeft(
474 (sal_Int32
)floor(aDiscreteRange
.getMinX() - fDiscreteOne
),
475 (sal_Int32
)floor(aDiscreteRange
.getMinY() - fDiscreteOne
));
476 const basegfx::B2IPoint
aBottomRight(
477 (sal_Int32
)ceil(aDiscreteRange
.getMaxX() + fDiscreteOne
),
478 (sal_Int32
)ceil(aDiscreteRange
.getMaxY() + fDiscreteOne
));
480 maBufferRememberedRangePixel
.expand(aTopLeft
);
481 maBufferRememberedRangePixel
.expand(aBottomRight
);
485 const basegfx::B2IPoint
aTopLeft((sal_Int32
)floor(aDiscreteRange
.getMinX()), (sal_Int32
)floor(aDiscreteRange
.getMinY()));
486 const basegfx::B2IPoint
aBottomRight((sal_Int32
)ceil(aDiscreteRange
.getMaxX()), (sal_Int32
)ceil(aDiscreteRange
.getMaxY()));
488 maBufferRememberedRangePixel
.expand(aTopLeft
);
489 maBufferRememberedRangePixel
.expand(aBottomRight
);
494 void OverlayManagerBuffered::SetRefreshWithPreRendering(bool bNew
)
496 if((bool)mbRefreshWithPreRendering
!= bNew
)
498 mbRefreshWithPreRendering
= bNew
;
501 } // end of namespace overlay
502 } // end of namespace sdr
504 //////////////////////////////////////////////////////////////////////////////