LibreOffice Module canvas (master)  1
dx_spritecanvashelper.cxx
Go to the documentation of this file.
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 #include <sal/config.h>
21 
22 #include <boost/cast.hpp>
23 
27 #include <tools/diagnose_ex.h>
28 
29 #include <canvas/canvastools.hxx>
30 
33 
34 using namespace ::com::sun::star;
35 
36 namespace dxcanvas
37 {
38  namespace
39  {
40  void repaintBackground( const ::basegfx::B2DRange& rUpdateArea,
41  const ::basegfx::B2IRange& rOutputArea,
42  const DXSurfaceBitmapSharedPtr& rBackBuffer )
43  {
44  // TODO(E1): Use numeric_cast to catch overflow here
45  ::basegfx::B2IRange aActualArea( 0, 0,
46  static_cast<sal_Int32>(rOutputArea.getWidth()),
47  static_cast<sal_Int32>(rOutputArea.getHeight()) );
48  aActualArea.intersect( fround( rUpdateArea ) );
49 
50  // repaint the given area of the screen with background content
51  rBackBuffer->draw(aActualArea);
52  }
53 
54  void spriteRedraw( const ::canvas::Sprite::Reference& rSprite )
55  {
56  // downcast to derived dxcanvas::Sprite interface, which
57  // provides the actual redraw methods.
58  ::boost::polymorphic_downcast< Sprite* >(
59  rSprite.get() )->redraw();
60  }
61  }
62 
64  mpSpriteSurface( nullptr ),
65  mpRedrawManager( nullptr ),
66  mpRenderModule(),
67  mpSurfaceProxy(),
68  mpBackBuffer(),
69  maUpdateRect(),
70  maScrapRect(),
71  mbShowSpriteBounds( false )
72  {
73 #if OSL_DEBUG_LEVEL > 0
74  // inverse default for verbose debug mode
75  mbShowSpriteBounds = true;
76 #endif
77  }
78 
80  ::canvas::SpriteRedrawManager& rManager,
81  const IDXRenderModuleSharedPtr& rRenderModule,
82  const std::shared_ptr<canvas::ISurfaceProxyManager>& rSurfaceProxy,
83  const DXSurfaceBitmapSharedPtr& rBackBuffer,
84  const ::basegfx::B2ISize& rOutputOffset )
85  {
86  // init base
87  setDevice( rParent );
88  setTarget( rBackBuffer, rOutputOffset );
89 
90  mpSpriteSurface = &rParent;
91  mpRedrawManager = &rManager;
92  mpRenderModule = rRenderModule;
93  mpSurfaceProxy = rSurfaceProxy;
94  mpBackBuffer = rBackBuffer;
95  }
96 
98  {
99  if(mpRenderModule)
100  mpRenderModule->disposing();
101 
102  mpBackBuffer.reset();
103  mpRenderModule.reset();
104  mpRedrawManager = nullptr;
105  mpSpriteSurface = nullptr;
106 
107  // forward to base
109  }
110 
111  uno::Reference< rendering::XAnimatedSprite > SpriteCanvasHelper::createSpriteFromAnimation(
112  const uno::Reference< rendering::XAnimation >& /*animation*/ )
113  {
114  return uno::Reference< rendering::XAnimatedSprite >();
115  }
116 
117  uno::Reference< rendering::XAnimatedSprite > SpriteCanvasHelper::createSpriteFromBitmaps(
118  const uno::Sequence< uno::Reference< rendering::XBitmap > >& /*animationBitmaps*/,
119  sal_Int8 /*interpolationMode*/ )
120  {
121  return uno::Reference< rendering::XAnimatedSprite >();
122  }
123 
124  uno::Reference< rendering::XCustomSprite > SpriteCanvasHelper::createCustomSprite( const geometry::RealSize2D& spriteSize )
125  {
126  if( !mpRedrawManager )
127  return uno::Reference< rendering::XCustomSprite >(); // we're disposed
128 
129  return uno::Reference< rendering::XCustomSprite >(
130  new CanvasCustomSprite( spriteSize,
134  mbShowSpriteBounds ) );
135  }
136 
137  uno::Reference< rendering::XSprite > SpriteCanvasHelper::createClonedSprite( const uno::Reference< rendering::XSprite >& /*original*/ )
138  {
139  return uno::Reference< rendering::XSprite >();
140  }
141 
142  bool SpriteCanvasHelper::updateScreen( const ::basegfx::B2IRectangle& rCurrArea,
143  bool bUpdateAll,
144  bool& io_bSurfaceDirty )
145  {
146  if( !mpRedrawManager ||
147  !mpRenderModule ||
148  !mpBackBuffer )
149  {
150  return false; // disposed, or otherwise dysfunctional
151  }
152 
153  // store current output area (need to tunnel that to the
154  // background, scroll, opaque and general sprite repaint
155  // routines)
156  maScrapRect = rCurrArea;
157 
158  // clear area that needs to be blitted to screen beforehand
159  maUpdateRect.reset();
160 
161  // TODO(P1): Might be worthwhile to track areas of background
162  // changes, too.
163 
164  // TODO(P2): Might be worthwhile to use page-flipping only if
165  // a certain percentage of screen area has changed - and
166  // compose directly to the front buffer otherwise.
167  if( !bUpdateAll && !io_bSurfaceDirty )
168  {
169  // background has not changed, so we're free to optimize
170  // repaint to areas where a sprite has changed
171 
172  // process each independent area of overlapping sprites
173  // separately.
175 
176  // flip primary surface to screen
177  // ==============================
178 
179  // perform buffer flipping
181  rCurrArea );
182  }
183  else
184  {
185  // limit update to parent window area (ignored for fullscreen)
186  // TODO(E1): Use numeric_cast to catch overflow here
187  const ::basegfx::B2IRectangle aUpdateArea( 0,0,
188  static_cast<sal_Int32>(rCurrArea.getWidth()),
189  static_cast<sal_Int32>(rCurrArea.getHeight()) );
190 
191  // background has changed, or called requested full
192  // update, or we're performing double buffering via page
193  // flipping, so we currently have no choice but repaint
194  // everything
195 
196  // repaint the whole screen with background content
197  mpBackBuffer->draw(aUpdateArea);
198 
199  // redraw sprites
200  mpRedrawManager->forEachSprite( &spriteRedraw );
201 
202  // flip primary surface to screen
203  // ==============================
204 
205  // perform buffer flipping
206  mpRenderModule->flip( aUpdateArea,
207  rCurrArea );
208  }
209 
210  // change record vector must be cleared, for the next turn of
211  // rendering and sprite changing
213 
214  io_bSurfaceDirty = false;
215 
216  return true;
217  }
218 
219  void SpriteCanvasHelper::backgroundPaint( const ::basegfx::B2DRange& rUpdateRect )
220  {
222  mpBackBuffer,
223  "SpriteCanvasHelper::backgroundPaint(): NULL device pointer " );
224 
225  repaintBackground( rUpdateRect,
226  maScrapRect,
227  mpBackBuffer );
228  }
229 
230  void SpriteCanvasHelper::scrollUpdate( const ::basegfx::B2DRange& /*rMoveStart*/,
231  const ::basegfx::B2DRange& rMoveEnd,
232  const ::canvas::SpriteRedrawManager::UpdateArea& rUpdateArea )
233  {
235  mpBackBuffer,
236  "SpriteCanvasHelper::scrollUpdate(): NULL device pointer " );
237 
238  // round rectangles to integer pixel. Note: have to be
239  // extremely careful here, to avoid off-by-one errors for
240  // the destination area: otherwise, the next scroll update
241  // would copy pixel that are not supposed to be part of
242  // the sprite.
243  const ::basegfx::B2IRange& rDestRect(
245 
246  // not much sense in really implementing scrollUpdate here,
247  // since outputting a sprite only partially would result in
248  // expensive clipping. Furthermore, we cannot currently render
249  // 3D directly to the front buffer, thus, would have to blit
250  // the full sprite area, anyway. But at least optimized in the
251  // sense that unnecessary background paints behind the sprites
252  // are avoided.
253  for( const auto& rComponent : rUpdateArea.maComponentList )
254  {
255  const ::canvas::Sprite::Reference& rSprite( rComponent.second.getSprite() );
256 
257  if( rSprite.is() )
258  {
259  // downcast to derived dxcanvas::Sprite interface, which
260  // provides the actual redraw methods.
261  ::boost::polymorphic_downcast< Sprite* >( rSprite.get() )->redraw();
262  }
263  }
264 
265  // repaint uncovered areas from backbuffer - take the
266  // _rounded_ rectangles from above, to have the update
267  // consistent with the scroll above.
268  std::vector< ::basegfx::B2DRange > aUncoveredAreas;
269  ::basegfx::computeSetDifference( aUncoveredAreas,
270  rUpdateArea.maTotalBounds,
271  ::basegfx::B2DRange( rDestRect ) );
272  for( const auto& rUncoveredArea : aUncoveredAreas )
273  repaintBackground( rUncoveredArea, maScrapRect, mpBackBuffer );
274 
275  // TODO(E1): Use numeric_cast to catch overflow here
276  ::basegfx::B2IRange aActualArea( 0, 0,
277  static_cast<sal_Int32>(maScrapRect.getWidth()),
278  static_cast<sal_Int32>(maScrapRect.getHeight()) );
279  aActualArea.intersect( fround( rUpdateArea.maTotalBounds ) );
280 
281  // add given update area to the 'blit to foreground' rect
282  maUpdateRect.expand( aActualArea );
283  }
284 
285  void SpriteCanvasHelper::opaqueUpdate( const ::basegfx::B2DRange& rTotalArea,
286  const std::vector< ::canvas::Sprite::Reference >& rSortedUpdateSprites )
287  {
289  mpBackBuffer,
290  "SpriteCanvasHelper::opaqueUpdate(): NULL device pointer " );
291 
292  // TODO(P2): optimize this by truly rendering to the front
293  // buffer. Currently, we've the 3D device only for the back
294  // buffer.
295  for( const auto& rSprite : rSortedUpdateSprites )
296  {
297  if( rSprite.is() )
298  {
299  // downcast to derived dxcanvas::Sprite interface, which
300  // provides the actual redraw methods.
301  ::boost::polymorphic_downcast< Sprite* >( rSprite.get() )->redraw();
302  }
303  }
304 
305  // TODO(E1): Use numeric_cast to catch overflow here
306  ::basegfx::B2IRange aActualArea( 0, 0,
307  static_cast<sal_Int32>(maScrapRect.getWidth()),
308  static_cast<sal_Int32>(maScrapRect.getHeight()) );
309  aActualArea.intersect( fround( rTotalArea ) );
310 
311  // add given update area to the 'blit to foreground' rect
312  maUpdateRect.expand( aActualArea );
313  }
314 
315  void SpriteCanvasHelper::genericUpdate( const ::basegfx::B2DRange& rTotalArea,
316  const std::vector< ::canvas::Sprite::Reference >& rSortedUpdateSprites )
317  {
319  mpBackBuffer,
320  "SpriteCanvasHelper::genericUpdate(): NULL device pointer " );
321 
322  // paint background
323  // ================
324 
325  // TODO(E1): Use numeric_cast to catch overflow here
326  ::basegfx::B2IRange aActualArea( 0, 0,
327  static_cast<sal_Int32>(maScrapRect.getWidth()),
328  static_cast<sal_Int32>(maScrapRect.getHeight()) );
329  aActualArea.intersect( fround( rTotalArea ) );
330 
331  // repaint the given area of the screen with background content
332  mpBackBuffer->draw(aActualArea);
333 
334  // paint sprite
335  // ============
336 
337  for( const auto& rSprite : rSortedUpdateSprites )
338  {
339  if( rSprite.is() )
340  {
341  // downcast to derived dxcanvas::Sprite interface, which
342  // provides the actual redraw methods.
343  ::boost::polymorphic_downcast< Sprite* >( rSprite.get() )->redraw();
344  }
345  }
346 
347  // add given update area to the 'blit to foreground' rect
348  maUpdateRect.expand( aActualArea );
349  }
350 }
351 
352 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
void intersect(const B2IRange &rRange)
void clearChangeRecords()
Clear sprite change records (typically directly after a screen update)
void forEachSpriteArea(Functor &rFunc) const
Call given functor for each sprite area that needs an update.
signed char sal_Int8
std::shared_ptr< IDXRenderModule > IDXRenderModuleSharedPtr
mutable::basegfx::B2IRange maUpdateRect
Completely temporary rect storage (used by sprite repaint)
void disposing()
Dispose all internal references.
void disposing()
Release all references.
mutable::basegfx::B2IRange maScrapRect
Completely temporary rect storage (used by sprite repaint)
void setTarget(const IBitmapSharedPtr &rTarget)
Set the target for rendering operations.
void setDevice(css::rendering::XGraphicDevice &rDevice)
Initialize canvas helper.
css::uno::Reference< css::rendering::XSprite > createClonedSprite(const css::uno::Reference< css::rendering::XSprite > &original)
void backgroundPaint(const ::basegfx::B2DRange &rUpdateRect)
Gets called for simple background repaints.
This class manages smooth SpriteCanvas updates.
B2IRange fround(const B2DRange &rRange)
::basegfx::B2IRange spritePixelAreaFromB2DRange(const ::basegfx::B2DRange &rRange)
Clip a blit between two differently surfaces.
void opaqueUpdate(const ::basegfx::B2DRange &rTotalArea, const std::vector< ::canvas::Sprite::Reference > &rSortedUpdateSprites)
DXSurfaceBitmapSharedPtr mpBackBuffer
Backbuffer, contains the static canvas render output.
void init(SpriteCanvas &rParent,::canvas::SpriteRedrawManager &rManager, const IDXRenderModuleSharedPtr &rRenderModule, const std::shared_ptr< canvas::ISurfaceProxyManager > &rSurfaceProxy, const DXSurfaceBitmapSharedPtr &rBackBuffer, const ::basegfx::B2ISize &rOutputOffset)
std::shared_ptr< canvas::ISurfaceProxyManager > mpSurfaceProxy
css::uno::Reference< css::rendering::XAnimatedSprite > createSpriteFromAnimation(const css::uno::Reference< css::rendering::XAnimation > &animation)
std::shared_ptr< DXSurfaceBitmap > DXSurfaceBitmapSharedPtr
void forEachSprite(const Functor &rFunc) const
Call given functor for each active sprite.
SpriteCanvas * mpSpriteSurface
For generating sprites.
::canvas::SpriteRedrawManager * mpRedrawManager
Set from the SpriteCanvas: instance coordinating sprite redraw.
css::uno::Reference< css::rendering::XCustomSprite > createCustomSprite(const css::geometry::RealSize2D &spriteSize)
#define ENSURE_OR_THROW(c, m)
bool updateScreen(const ::basegfx::B2IRectangle &rCurrArea, bool bUpdateAll, bool &io_bSurfaceDirty)
Actually perform the screen update.
css::uno::Reference< css::rendering::XAnimatedSprite > createSpriteFromBitmaps(const css::uno::Sequence< css::uno::Reference< css::rendering::XBitmap > > &animationBitmaps, sal_Int8 interpolationMode)
Product of this component's factory.
void genericUpdate(const ::basegfx::B2DRange &rTotalArea, const std::vector< ::canvas::Sprite::Reference > &rSortedUpdateSprites)
bool mbShowSpriteBounds
When true, show small bound rects around each sprite.
void scrollUpdate(const ::basegfx::B2DRange &rMoveStart, const ::basegfx::B2DRange &rMoveEnd, const ::canvas::SpriteRedrawManager::UpdateArea &rUpdateArea)
Gets called when area can be handled by scrolling.
IDXRenderModuleSharedPtr mpRenderModule
DX device, handling all low-level rendering.