1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <canvas/debug.hxx>
22 #include <canvas/verbosetrace.hxx>
23 #include <canvas/canvastools.hxx>
24 #include <tools/diagnose_ex.h>
26 #include <comphelper/scopeguard.hxx>
28 #include <basegfx/range/b2drectangle.hxx>
29 #include <basegfx/tools/canvastools.hxx>
31 #include <boost/cast.hpp>
33 #include "dx_spritecanvashelper.hxx"
34 #include "dx_canvascustomsprite.hxx"
36 #if defined(DX_DEBUG_IMAGES)
37 # if OSL_DEBUG_LEVEL > 0
44 using namespace ::com::sun::star
;
50 void repaintBackground( const ::basegfx::B2DRange
& rUpdateArea
,
51 const ::basegfx::B2IRange
& rOutputArea
,
52 const DXSurfaceBitmapSharedPtr
& rBackBuffer
)
54 // TODO(E1): Use numeric_cast to catch overflow here
55 ::basegfx::B2IRange
aActualArea( 0, 0,
56 static_cast<sal_Int32
>(rOutputArea
.getWidth()),
57 static_cast<sal_Int32
>(rOutputArea
.getHeight()) );
58 aActualArea
.intersect( fround( rUpdateArea
) );
60 // repaint the given area of the screen with background content
61 rBackBuffer
->draw(aActualArea
);
64 void spriteRedraw( const ::canvas::Sprite::Reference
& rSprite
)
66 // downcast to derived dxcanvas::Sprite interface, which
67 // provides the actual redraw methods.
68 ::boost::polymorphic_downcast
< Sprite
* >(
69 rSprite
.get() )->redraw();
72 void spriteRedrawStub( const ::canvas::Sprite::Reference
& rSprite
)
76 // downcast to derived dxcanvas::Sprite interface, which
77 // provides the actual redraw methods.
78 ::boost::polymorphic_downcast
< Sprite
* >(
79 rSprite
.get() )->redraw();
83 void spriteRedrawStub2( const ::canvas::SpriteRedrawManager::AreaComponent
& rComponent
)
85 if( rComponent
.second
.getSprite().is() )
87 // downcast to derived dxcanvas::Sprite interface, which
88 // provides the actual redraw methods.
89 ::boost::polymorphic_downcast
< Sprite
* >(
90 rComponent
.second
.getSprite().get() )->redraw();
95 SpriteCanvasHelper::SpriteCanvasHelper() :
96 mpSpriteSurface( NULL
),
97 mpRedrawManager( NULL
),
103 mbShowSpriteBounds( false )
105 #if OSL_DEBUG_LEVEL > 2
106 // inverse default for verbose debug mode
107 mbShowSpriteBounds
= true;
111 void SpriteCanvasHelper::init( SpriteCanvas
& rParent
,
112 ::canvas::SpriteRedrawManager
& rManager
,
113 const IDXRenderModuleSharedPtr
& rRenderModule
,
114 const ::canvas::ISurfaceProxyManagerSharedPtr
& rSurfaceProxy
,
115 const DXSurfaceBitmapSharedPtr
& rBackBuffer
,
116 const ::basegfx::B2ISize
& rOutputOffset
)
119 setDevice( rParent
);
120 setTarget( rBackBuffer
, rOutputOffset
);
122 mpSpriteSurface
= &rParent
;
123 mpRedrawManager
= &rManager
;
124 mpRenderModule
= rRenderModule
;
125 mpSurfaceProxy
= rSurfaceProxy
;
126 mpBackBuffer
= rBackBuffer
;
129 void SpriteCanvasHelper::disposing()
132 mpRenderModule
->disposing();
134 mpBackBuffer
.reset();
135 mpRenderModule
.reset();
136 mpRedrawManager
= NULL
;
137 mpSpriteSurface
= NULL
;
140 CanvasHelper::disposing();
143 uno::Reference
< rendering::XAnimatedSprite
> SpriteCanvasHelper::createSpriteFromAnimation(
144 const uno::Reference
< rendering::XAnimation
>& /*animation*/ )
146 return uno::Reference
< rendering::XAnimatedSprite
>();
149 uno::Reference
< rendering::XAnimatedSprite
> SpriteCanvasHelper::createSpriteFromBitmaps(
150 const uno::Sequence
< uno::Reference
< rendering::XBitmap
> >& /*animationBitmaps*/,
151 sal_Int8
/*interpolationMode*/ )
153 return uno::Reference
< rendering::XAnimatedSprite
>();
156 uno::Reference
< rendering::XCustomSprite
> SpriteCanvasHelper::createCustomSprite( const geometry::RealSize2D
& spriteSize
)
158 if( !mpRedrawManager
)
159 return uno::Reference
< rendering::XCustomSprite
>(); // we're disposed
161 return uno::Reference
< rendering::XCustomSprite
>(
162 new CanvasCustomSprite( spriteSize
,
166 mbShowSpriteBounds
) );
169 uno::Reference
< rendering::XSprite
> SpriteCanvasHelper::createClonedSprite( const uno::Reference
< rendering::XSprite
>& /*original*/ )
171 return uno::Reference
< rendering::XSprite
>();
174 bool SpriteCanvasHelper::updateScreen( const ::basegfx::B2IRectangle
& rCurrArea
,
176 bool& io_bSurfaceDirty
)
178 if( !mpRedrawManager
||
182 return false; // disposed, or otherwise dysfunctional
185 #if defined(DX_DEBUG_IMAGES)
186 # if OSL_DEBUG_LEVEL > 0
187 mpBackBuffer
->imageDebugger();
191 // store current output area (need to tunnel that to the
192 // background, scroll, opaque and general sprite repaint
194 maScrapRect
= rCurrArea
;
196 // clear area that needs to be blitted to screen beforehand
197 maUpdateRect
.reset();
199 // TODO(P1): Might be worthwile to track areas of background
202 // TODO(P2): Might be worthwhile to use page-flipping only if
203 // a certain percentage of screen area has changed - and
204 // compose directly to the front buffer otherwise.
205 if( !bUpdateAll
&& !io_bSurfaceDirty
)
207 // background has not changed, so we're free to optimize
208 // repaint to areas where a sprite has changed
210 // process each independent area of overlapping sprites
212 mpRedrawManager
->forEachSpriteArea( *this );
214 // flip primary surface to screen
215 // ==============================
217 // perform buffer flipping
218 mpRenderModule
->flip( maUpdateRect
,
223 // limit update to parent window area (ignored for fullscreen)
224 // TODO(E1): Use numeric_cast to catch overflow here
225 const ::basegfx::B2IRectangle
aUpdateArea( 0,0,
226 static_cast<sal_Int32
>(rCurrArea
.getWidth()),
227 static_cast<sal_Int32
>(rCurrArea
.getHeight()) );
229 // background has changed, or called requested full
230 // update, or we're performing double buffering via page
231 // flipping, so we currently have no choice but repaint
234 // repaint the whole screen with background content
235 mpBackBuffer
->draw(aUpdateArea
);
238 mpRedrawManager
->forEachSprite( &spriteRedraw
);
240 // flip primary surface to screen
241 // ==============================
243 // perform buffer flipping
244 mpRenderModule
->flip( aUpdateArea
,
248 // change record vector must be cleared, for the next turn of
249 // rendering and sprite changing
250 mpRedrawManager
->clearChangeRecords();
252 io_bSurfaceDirty
= false;
257 void SpriteCanvasHelper::backgroundPaint( const ::basegfx::B2DRange
& rUpdateRect
)
259 ENSURE_OR_THROW( mpRenderModule
&&
261 "SpriteCanvasHelper::backgroundPaint(): NULL device pointer " );
263 repaintBackground( rUpdateRect
,
268 void SpriteCanvasHelper::scrollUpdate( const ::basegfx::B2DRange
& /*rMoveStart*/,
269 const ::basegfx::B2DRange
& rMoveEnd
,
270 const ::canvas::SpriteRedrawManager::UpdateArea
& rUpdateArea
)
272 ENSURE_OR_THROW( mpRenderModule
&&
274 "SpriteCanvasHelper::scrollUpdate(): NULL device pointer " );
276 // round rectangles to integer pixel. Note: have to be
277 // extremely careful here, to avoid off-by-one errors for
278 // the destination area: otherwise, the next scroll update
279 // would copy pixel that are not supposed to be part of
281 const ::basegfx::B2IRange
& rDestRect(
282 ::canvas::tools::spritePixelAreaFromB2DRange( rMoveEnd
) );
284 // not much sense in really implementing scrollUpdate here,
285 // since outputting a sprite only partially would result in
286 // expensive clipping. Furthermore, we cannot currently render
287 // 3D directly to the front buffer, thus, would have to blit
288 // the full sprite area, anyway. But at least optimized in the
289 // sense that unnecessary background paints behind the sprites
291 ::std::for_each( rUpdateArea
.maComponentList
.begin(),
292 rUpdateArea
.maComponentList
.end(),
293 &spriteRedrawStub2
);
295 // repaint uncovered areas from backbuffer - take the
296 // _rounded_ rectangles from above, to have the update
297 // consistent with the scroll above.
298 ::std::vector
< ::basegfx::B2DRange
> aUncoveredAreas
;
299 ::basegfx::computeSetDifference( aUncoveredAreas
,
300 rUpdateArea
.maTotalBounds
,
301 ::basegfx::B2DRange( rDestRect
) );
302 ::std::for_each( aUncoveredAreas
.begin(),
303 aUncoveredAreas
.end(),
304 ::boost::bind( &repaintBackground
,
306 ::boost::cref(maScrapRect
),
307 ::boost::cref(mpBackBuffer
) ) );
309 // TODO(E1): Use numeric_cast to catch overflow here
310 ::basegfx::B2IRange
aActualArea( 0, 0,
311 static_cast<sal_Int32
>(maScrapRect
.getWidth()),
312 static_cast<sal_Int32
>(maScrapRect
.getHeight()) );
313 aActualArea
.intersect( fround( rUpdateArea
.maTotalBounds
) );
315 // add given update area to the 'blit to foreground' rect
316 maUpdateRect
.expand( aActualArea
);
319 void SpriteCanvasHelper::opaqueUpdate( const ::basegfx::B2DRange
& rTotalArea
,
320 const ::std::vector
< ::canvas::Sprite::Reference
>& rSortedUpdateSprites
)
322 ENSURE_OR_THROW( mpRenderModule
&&
324 "SpriteCanvasHelper::opaqueUpdate(): NULL device pointer " );
326 // TODO(P2): optimize this by truly rendering to the front
327 // buffer. Currently, we've the 3D device only for the back
329 ::std::for_each( rSortedUpdateSprites
.begin(),
330 rSortedUpdateSprites
.end(),
333 // TODO(E1): Use numeric_cast to catch overflow here
334 ::basegfx::B2IRange
aActualArea( 0, 0,
335 static_cast<sal_Int32
>(maScrapRect
.getWidth()),
336 static_cast<sal_Int32
>(maScrapRect
.getHeight()) );
337 aActualArea
.intersect( fround( rTotalArea
) );
339 // add given update area to the 'blit to foreground' rect
340 maUpdateRect
.expand( aActualArea
);
343 void SpriteCanvasHelper::genericUpdate( const ::basegfx::B2DRange
& rTotalArea
,
344 const ::std::vector
< ::canvas::Sprite::Reference
>& rSortedUpdateSprites
)
346 ENSURE_OR_THROW( mpRenderModule
&&
348 "SpriteCanvasHelper::genericUpdate(): NULL device pointer " );
353 // TODO(E1): Use numeric_cast to catch overflow here
354 ::basegfx::B2IRange
aActualArea( 0, 0,
355 static_cast<sal_Int32
>(maScrapRect
.getWidth()),
356 static_cast<sal_Int32
>(maScrapRect
.getHeight()) );
357 aActualArea
.intersect( fround( rTotalArea
) );
359 // repaint the given area of the screen with background content
360 mpBackBuffer
->draw(aActualArea
);
365 ::std::for_each( rSortedUpdateSprites
.begin(),
366 rSortedUpdateSprites
.end(),
369 // add given update area to the 'blit to foreground' rect
370 maUpdateRect
.expand( aActualArea
);
374 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */