1*cdf0e10cSrcweir /*************************************************************************
2*cdf0e10cSrcweir  *
3*cdf0e10cSrcweir  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4*cdf0e10cSrcweir  *
5*cdf0e10cSrcweir  * Copyright 2000, 2010 Oracle and/or its affiliates.
6*cdf0e10cSrcweir  *
7*cdf0e10cSrcweir  * OpenOffice.org - a multi-platform office productivity suite
8*cdf0e10cSrcweir  *
9*cdf0e10cSrcweir  * This file is part of OpenOffice.org.
10*cdf0e10cSrcweir  *
11*cdf0e10cSrcweir  * OpenOffice.org is free software: you can redistribute it and/or modify
12*cdf0e10cSrcweir  * it under the terms of the GNU Lesser General Public License version 3
13*cdf0e10cSrcweir  * only, as published by the Free Software Foundation.
14*cdf0e10cSrcweir  *
15*cdf0e10cSrcweir  * OpenOffice.org is distributed in the hope that it will be useful,
16*cdf0e10cSrcweir  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17*cdf0e10cSrcweir  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18*cdf0e10cSrcweir  * GNU Lesser General Public License version 3 for more details
19*cdf0e10cSrcweir  * (a copy is included in the LICENSE file that accompanied this code).
20*cdf0e10cSrcweir  *
21*cdf0e10cSrcweir  * You should have received a copy of the GNU Lesser General Public License
22*cdf0e10cSrcweir  * version 3 along with OpenOffice.org.  If not, see
23*cdf0e10cSrcweir  * <http://www.openoffice.org/license.html>
24*cdf0e10cSrcweir  * for a copy of the LGPLv3 License.
25*cdf0e10cSrcweir  *
26*cdf0e10cSrcweir  ************************************************************************/
27*cdf0e10cSrcweir 
28*cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
29*cdf0e10cSrcweir #include "precompiled_canvas.hxx"
30*cdf0e10cSrcweir 
31*cdf0e10cSrcweir #include <canvas/debug.hxx>
32*cdf0e10cSrcweir #include <tools/diagnose_ex.h>
33*cdf0e10cSrcweir #include <canvas/verbosetrace.hxx>
34*cdf0e10cSrcweir #include <canvas/canvastools.hxx>
35*cdf0e10cSrcweir 
36*cdf0e10cSrcweir #include <vcl/canvastools.hxx>
37*cdf0e10cSrcweir #include <vcl/outdev.hxx>
38*cdf0e10cSrcweir #include <vcl/window.hxx>
39*cdf0e10cSrcweir #include <vcl/bitmapex.hxx>
40*cdf0e10cSrcweir 
41*cdf0e10cSrcweir #include <basegfx/range/b2drectangle.hxx>
42*cdf0e10cSrcweir #include <basegfx/tools/canvastools.hxx>
43*cdf0e10cSrcweir 
44*cdf0e10cSrcweir #include <boost/cast.hpp>
45*cdf0e10cSrcweir 
46*cdf0e10cSrcweir #include "spritecanvashelper.hxx"
47*cdf0e10cSrcweir #include "canvascustomsprite.hxx"
48*cdf0e10cSrcweir 
49*cdf0e10cSrcweir 
50*cdf0e10cSrcweir using namespace ::com::sun::star;
51*cdf0e10cSrcweir 
52*cdf0e10cSrcweir #define FPS_BOUNDS Rectangle(0,0,130,90)
53*cdf0e10cSrcweir #define INFO_COLOR COL_RED
54*cdf0e10cSrcweir 
55*cdf0e10cSrcweir namespace vclcanvas
56*cdf0e10cSrcweir {
57*cdf0e10cSrcweir     namespace
58*cdf0e10cSrcweir     {
59*cdf0e10cSrcweir         /** Sprite redraw at original position
60*cdf0e10cSrcweir 
61*cdf0e10cSrcweir             Used to repaint the whole canvas (background and all
62*cdf0e10cSrcweir             sprites)
63*cdf0e10cSrcweir          */
64*cdf0e10cSrcweir         void spriteRedraw( OutputDevice&                      rOutDev,
65*cdf0e10cSrcweir                            const ::canvas::Sprite::Reference& rSprite )
66*cdf0e10cSrcweir         {
67*cdf0e10cSrcweir             // downcast to derived vclcanvas::Sprite interface, which
68*cdf0e10cSrcweir             // provides the actual redraw methods.
69*cdf0e10cSrcweir             ::boost::polymorphic_downcast< Sprite* >(rSprite.get())->redraw(rOutDev,
70*cdf0e10cSrcweir                                                                             true);
71*cdf0e10cSrcweir         }
72*cdf0e10cSrcweir 
73*cdf0e10cSrcweir         double calcNumPixel( const ::canvas::Sprite::Reference&	rSprite )
74*cdf0e10cSrcweir         {
75*cdf0e10cSrcweir             const ::basegfx::B2DSize& rSize(
76*cdf0e10cSrcweir                 ::boost::polymorphic_downcast< Sprite* >(rSprite.get())->getSizePixel() );
77*cdf0e10cSrcweir 
78*cdf0e10cSrcweir             return rSize.getX() * rSize.getY();
79*cdf0e10cSrcweir         }
80*cdf0e10cSrcweir 
81*cdf0e10cSrcweir         void repaintBackground( OutputDevice& 				rOutDev,
82*cdf0e10cSrcweir                                 OutputDevice& 				rBackBuffer,
83*cdf0e10cSrcweir                                 const ::basegfx::B2DRange&	rArea )
84*cdf0e10cSrcweir         {
85*cdf0e10cSrcweir             const ::Point& rPos( ::vcl::unotools::pointFromB2DPoint( rArea.getMinimum()) );
86*cdf0e10cSrcweir             const ::Size& rSize( ::vcl::unotools::sizeFromB2DSize( rArea.getRange()) );
87*cdf0e10cSrcweir 
88*cdf0e10cSrcweir             rOutDev.DrawOutDev( rPos, rSize, rPos, rSize, rBackBuffer );
89*cdf0e10cSrcweir         }
90*cdf0e10cSrcweir 
91*cdf0e10cSrcweir         void opaqueUpdateSpriteArea( const ::canvas::Sprite::Reference& rSprite,
92*cdf0e10cSrcweir                                      OutputDevice&                      rOutDev,
93*cdf0e10cSrcweir                                      const ::basegfx::B2IRange&         rArea )
94*cdf0e10cSrcweir         {
95*cdf0e10cSrcweir             const Rectangle& rRequestedArea(
96*cdf0e10cSrcweir                 ::vcl::unotools::rectangleFromB2IRectangle( rArea ) );
97*cdf0e10cSrcweir 
98*cdf0e10cSrcweir             // clip output to actual update region (otherwise a)
99*cdf0e10cSrcweir             // wouldn't save much render time, and b) will clutter
100*cdf0e10cSrcweir             // scrolled sprite content outside this area)
101*cdf0e10cSrcweir             rOutDev.EnableMapMode( sal_False );
102*cdf0e10cSrcweir             rOutDev.SetClipRegion( rRequestedArea );
103*cdf0e10cSrcweir 
104*cdf0e10cSrcweir             // repaint affected sprite directly to output device (at
105*cdf0e10cSrcweir             // the actual screen output position)
106*cdf0e10cSrcweir             ::boost::polymorphic_downcast< Sprite* >(
107*cdf0e10cSrcweir                 rSprite.get() )->redraw( rOutDev,
108*cdf0e10cSrcweir                                          false ); // rendering
109*cdf0e10cSrcweir                                                   // directly to
110*cdf0e10cSrcweir                                                   // frontbuffer
111*cdf0e10cSrcweir         }
112*cdf0e10cSrcweir 
113*cdf0e10cSrcweir         /** Repaint sprite at original position
114*cdf0e10cSrcweir 
115*cdf0e10cSrcweir             Used for opaque updates, which render directly to the
116*cdf0e10cSrcweir             front buffer.
117*cdf0e10cSrcweir          */
118*cdf0e10cSrcweir         void spriteRedrawStub( OutputDevice&                      rOutDev,
119*cdf0e10cSrcweir                                const ::canvas::Sprite::Reference& rSprite )
120*cdf0e10cSrcweir         {
121*cdf0e10cSrcweir             if( rSprite.is() )
122*cdf0e10cSrcweir             {
123*cdf0e10cSrcweir                 ::boost::polymorphic_downcast< Sprite* >(
124*cdf0e10cSrcweir                     rSprite.get() )->redraw( rOutDev,
125*cdf0e10cSrcweir                                              false );
126*cdf0e10cSrcweir             }
127*cdf0e10cSrcweir         }
128*cdf0e10cSrcweir 
129*cdf0e10cSrcweir         /** Repaint sprite at given position
130*cdf0e10cSrcweir 
131*cdf0e10cSrcweir             Used for generic update, which renders into vdev of
132*cdf0e10cSrcweir             adapted size.
133*cdf0e10cSrcweir          */
134*cdf0e10cSrcweir         void spriteRedrawStub2( OutputDevice&                       rOutDev,
135*cdf0e10cSrcweir                                 const ::basegfx::B2DPoint& 			rOutPos,
136*cdf0e10cSrcweir                                 const ::canvas::Sprite::Reference&	rSprite )
137*cdf0e10cSrcweir         {
138*cdf0e10cSrcweir             if( rSprite.is() )
139*cdf0e10cSrcweir             {
140*cdf0e10cSrcweir                 Sprite* pSprite = ::boost::polymorphic_downcast< Sprite* >(
141*cdf0e10cSrcweir                     rSprite.get() );
142*cdf0e10cSrcweir 
143*cdf0e10cSrcweir 				// calc relative sprite position in rUpdateArea (which
144*cdf0e10cSrcweir 				// need not be the whole screen!)
145*cdf0e10cSrcweir                 const ::basegfx::B2DPoint& rSpriteScreenPos( pSprite->getPosPixel() );
146*cdf0e10cSrcweir                 const ::basegfx::B2DPoint& rSpriteRenderPos( rSpriteScreenPos - rOutPos );
147*cdf0e10cSrcweir 
148*cdf0e10cSrcweir                 pSprite->redraw( rOutDev, rSpriteRenderPos, true );
149*cdf0e10cSrcweir             }
150*cdf0e10cSrcweir         }
151*cdf0e10cSrcweir 
152*cdf0e10cSrcweir         /** Repaint sprite at original position
153*cdf0e10cSrcweir 
154*cdf0e10cSrcweir             Used for opaque updates from scrollUpdate(), which render
155*cdf0e10cSrcweir             directly to the front buffer.
156*cdf0e10cSrcweir          */
157*cdf0e10cSrcweir         void spriteRedrawStub3( OutputDevice&                                       rOutDev,
158*cdf0e10cSrcweir                                 const ::canvas::SpriteRedrawManager::AreaComponent& rComponent )
159*cdf0e10cSrcweir         {
160*cdf0e10cSrcweir             const ::canvas::Sprite::Reference& rSprite( rComponent.second.getSprite() );
161*cdf0e10cSrcweir 
162*cdf0e10cSrcweir             if( rSprite.is() )
163*cdf0e10cSrcweir             {
164*cdf0e10cSrcweir                 ::boost::polymorphic_downcast< Sprite* >(
165*cdf0e10cSrcweir                     rSprite.get() )->redraw( rOutDev,
166*cdf0e10cSrcweir                                              false );
167*cdf0e10cSrcweir             }
168*cdf0e10cSrcweir         }
169*cdf0e10cSrcweir 
170*cdf0e10cSrcweir         void renderInfoText( OutputDevice& 			rOutDev,
171*cdf0e10cSrcweir                              const ::rtl::OUString& rStr,
172*cdf0e10cSrcweir                              const Point&		    rPos )
173*cdf0e10cSrcweir         {
174*cdf0e10cSrcweir             Font aVCLFont;
175*cdf0e10cSrcweir             aVCLFont.SetHeight( 20 );
176*cdf0e10cSrcweir             aVCLFont.SetColor( Color( INFO_COLOR ) );
177*cdf0e10cSrcweir 
178*cdf0e10cSrcweir             rOutDev.SetTextAlign(ALIGN_TOP);
179*cdf0e10cSrcweir             rOutDev.SetTextColor( Color( INFO_COLOR ) );
180*cdf0e10cSrcweir             rOutDev.SetFont( aVCLFont );
181*cdf0e10cSrcweir 
182*cdf0e10cSrcweir             rOutDev.DrawText( rPos, rStr );
183*cdf0e10cSrcweir         }
184*cdf0e10cSrcweir 
185*cdf0e10cSrcweir     }
186*cdf0e10cSrcweir 
187*cdf0e10cSrcweir     SpriteCanvasHelper::SpriteCanvasHelper() :
188*cdf0e10cSrcweir         mpRedrawManager( NULL ),
189*cdf0e10cSrcweir         mpOwningSpriteCanvas( NULL ),
190*cdf0e10cSrcweir         maVDev(),
191*cdf0e10cSrcweir         maLastUpdate(),
192*cdf0e10cSrcweir         mbShowFrameInfo( false ),
193*cdf0e10cSrcweir         mbShowSpriteBounds( false ),
194*cdf0e10cSrcweir         mbIsUnsafeScrolling( false )
195*cdf0e10cSrcweir     {
196*cdf0e10cSrcweir #if defined(VERBOSE) && OSL_DEBUG_LEVEL > 0
197*cdf0e10cSrcweir         // inverse defaults for verbose debug mode
198*cdf0e10cSrcweir         mbShowSpriteBounds = mbShowFrameInfo = true;
199*cdf0e10cSrcweir #endif
200*cdf0e10cSrcweir     }
201*cdf0e10cSrcweir 
202*cdf0e10cSrcweir     void SpriteCanvasHelper::init( const OutDevProviderSharedPtr& rOutDev,
203*cdf0e10cSrcweir                                    SpriteCanvas&                  rOwningSpriteCanvas,
204*cdf0e10cSrcweir                                    ::canvas::SpriteRedrawManager& rManager,
205*cdf0e10cSrcweir                                    bool                           bProtect,
206*cdf0e10cSrcweir                                    bool                           bHaveAlpha )
207*cdf0e10cSrcweir     {
208*cdf0e10cSrcweir         mpOwningSpriteCanvas = &rOwningSpriteCanvas;
209*cdf0e10cSrcweir         mpRedrawManager = &rManager;
210*cdf0e10cSrcweir 
211*cdf0e10cSrcweir         CanvasHelper::init(rOwningSpriteCanvas,rOutDev,bProtect,bHaveAlpha);
212*cdf0e10cSrcweir     }
213*cdf0e10cSrcweir 
214*cdf0e10cSrcweir     void SpriteCanvasHelper::disposing()
215*cdf0e10cSrcweir     {
216*cdf0e10cSrcweir         mpRedrawManager = NULL;
217*cdf0e10cSrcweir         mpOwningSpriteCanvas = NULL;
218*cdf0e10cSrcweir 
219*cdf0e10cSrcweir         // forward to base
220*cdf0e10cSrcweir         CanvasHelper::disposing();
221*cdf0e10cSrcweir     }
222*cdf0e10cSrcweir 
223*cdf0e10cSrcweir     uno::Reference< rendering::XAnimatedSprite > SpriteCanvasHelper::createSpriteFromAnimation(
224*cdf0e10cSrcweir         const uno::Reference< rendering::XAnimation >&  )
225*cdf0e10cSrcweir     {
226*cdf0e10cSrcweir         return uno::Reference< rendering::XAnimatedSprite >();
227*cdf0e10cSrcweir     }
228*cdf0e10cSrcweir 
229*cdf0e10cSrcweir     uno::Reference< rendering::XAnimatedSprite > SpriteCanvasHelper::createSpriteFromBitmaps(
230*cdf0e10cSrcweir         const uno::Sequence< uno::Reference< rendering::XBitmap > >& ,
231*cdf0e10cSrcweir         sal_Int8                                                      )
232*cdf0e10cSrcweir     {
233*cdf0e10cSrcweir         return uno::Reference< rendering::XAnimatedSprite >();
234*cdf0e10cSrcweir     }
235*cdf0e10cSrcweir 
236*cdf0e10cSrcweir     uno::Reference< rendering::XCustomSprite > SpriteCanvasHelper::createCustomSprite( const geometry::RealSize2D& spriteSize )
237*cdf0e10cSrcweir     {
238*cdf0e10cSrcweir         if( !mpRedrawManager || !mpDevice )
239*cdf0e10cSrcweir             return uno::Reference< rendering::XCustomSprite >(); // we're disposed
240*cdf0e10cSrcweir 
241*cdf0e10cSrcweir         return uno::Reference< rendering::XCustomSprite >(
242*cdf0e10cSrcweir             new CanvasCustomSprite( spriteSize,
243*cdf0e10cSrcweir                                     *mpDevice,
244*cdf0e10cSrcweir                                     mpOwningSpriteCanvas,
245*cdf0e10cSrcweir                                     mpOwningSpriteCanvas->getFrontBuffer(),
246*cdf0e10cSrcweir                                     mbShowSpriteBounds ) );
247*cdf0e10cSrcweir     }
248*cdf0e10cSrcweir 
249*cdf0e10cSrcweir     uno::Reference< rendering::XSprite > SpriteCanvasHelper::createClonedSprite( const uno::Reference< rendering::XSprite >&  )
250*cdf0e10cSrcweir     {
251*cdf0e10cSrcweir         return uno::Reference< rendering::XSprite >();
252*cdf0e10cSrcweir     }
253*cdf0e10cSrcweir 
254*cdf0e10cSrcweir     sal_Bool SpriteCanvasHelper::updateScreen( sal_Bool bUpdateAll,
255*cdf0e10cSrcweir                                                bool&	io_bSurfaceDirty )
256*cdf0e10cSrcweir     {
257*cdf0e10cSrcweir         if( !mpRedrawManager ||
258*cdf0e10cSrcweir             !mpOwningSpriteCanvas ||
259*cdf0e10cSrcweir             !mpOwningSpriteCanvas->getFrontBuffer() ||
260*cdf0e10cSrcweir             !mpOwningSpriteCanvas->getBackBuffer() )
261*cdf0e10cSrcweir         {
262*cdf0e10cSrcweir             return sal_False; // disposed, or otherwise dysfunctional
263*cdf0e10cSrcweir         }
264*cdf0e10cSrcweir 
265*cdf0e10cSrcweir         // commit to backbuffer
266*cdf0e10cSrcweir         flush();
267*cdf0e10cSrcweir 
268*cdf0e10cSrcweir         OutputDevice& 		rOutDev( mpOwningSpriteCanvas->getFrontBuffer()->getOutDev() );
269*cdf0e10cSrcweir         BackBufferSharedPtr pBackBuffer( mpOwningSpriteCanvas->getBackBuffer() );
270*cdf0e10cSrcweir         OutputDevice& 		rBackOutDev( pBackBuffer->getOutDev() );
271*cdf0e10cSrcweir 
272*cdf0e10cSrcweir         // actual OutputDevice is a shared resource - restore its
273*cdf0e10cSrcweir         // state when done.
274*cdf0e10cSrcweir         tools::OutDevStateKeeper aStateKeeper( rOutDev );
275*cdf0e10cSrcweir 
276*cdf0e10cSrcweir         const Size 	aOutDevSize( rBackOutDev.GetOutputSizePixel() );
277*cdf0e10cSrcweir         const Point aEmptyPoint(0,0);
278*cdf0e10cSrcweir 
279*cdf0e10cSrcweir         Window* pTargetWindow = NULL;
280*cdf0e10cSrcweir         if( rOutDev.GetOutDevType() == OUTDEV_WINDOW )
281*cdf0e10cSrcweir         {
282*cdf0e10cSrcweir             pTargetWindow = &static_cast<Window&>(rOutDev); // TODO(Q3): Evil downcast.
283*cdf0e10cSrcweir 
284*cdf0e10cSrcweir             // we're double-buffered, thus no need for paint area-limiting
285*cdf0e10cSrcweir             // clips. besides that, will interfere with animations (as for
286*cdf0e10cSrcweir             // Window-invalidate repaints, only parts of the window will
287*cdf0e10cSrcweir             // be redrawn otherwise)
288*cdf0e10cSrcweir             const Region aFullWindowRegion( Rectangle(aEmptyPoint,
289*cdf0e10cSrcweir                                                       aOutDevSize) );
290*cdf0e10cSrcweir             pTargetWindow->ExpandPaintClipRegion(aFullWindowRegion);
291*cdf0e10cSrcweir         }
292*cdf0e10cSrcweir 
293*cdf0e10cSrcweir         // TODO(P1): Might be worthwile to track areas of background
294*cdf0e10cSrcweir         // changes, too.
295*cdf0e10cSrcweir         if( !bUpdateAll && !io_bSurfaceDirty )
296*cdf0e10cSrcweir         {
297*cdf0e10cSrcweir             if( mbShowFrameInfo )
298*cdf0e10cSrcweir             {
299*cdf0e10cSrcweir                 // also repaint background below frame counter (fake
300*cdf0e10cSrcweir                 // that as a sprite vanishing in this area)
301*cdf0e10cSrcweir                 mpRedrawManager->updateSprite( ::canvas::Sprite::Reference(),
302*cdf0e10cSrcweir                                                ::basegfx::B2DPoint(),
303*cdf0e10cSrcweir                                                ::basegfx::B2DRectangle( 0.0, 0.0,
304*cdf0e10cSrcweir                                                                         FPS_BOUNDS.Right(),
305*cdf0e10cSrcweir                                                                         FPS_BOUNDS.Bottom() ) );
306*cdf0e10cSrcweir             }
307*cdf0e10cSrcweir 
308*cdf0e10cSrcweir             // background has not changed, so we're free to optimize
309*cdf0e10cSrcweir             // repaint to areas where a sprite has changed
310*cdf0e10cSrcweir 
311*cdf0e10cSrcweir             // process each independent area of overlapping sprites
312*cdf0e10cSrcweir             // separately.
313*cdf0e10cSrcweir             mpRedrawManager->forEachSpriteArea( *this );
314*cdf0e10cSrcweir         }
315*cdf0e10cSrcweir         else
316*cdf0e10cSrcweir         {
317*cdf0e10cSrcweir             // background has changed, so we currently have no choice
318*cdf0e10cSrcweir             // but repaint everything (or caller requested that)
319*cdf0e10cSrcweir 
320*cdf0e10cSrcweir             maVDev->SetOutputSizePixel( aOutDevSize );
321*cdf0e10cSrcweir             maVDev->EnableMapMode( sal_False );
322*cdf0e10cSrcweir             maVDev->DrawOutDev( aEmptyPoint, aOutDevSize,
323*cdf0e10cSrcweir                                 aEmptyPoint, aOutDevSize,
324*cdf0e10cSrcweir                                 rBackOutDev );
325*cdf0e10cSrcweir 
326*cdf0e10cSrcweir             // repaint all active sprites on top of background into
327*cdf0e10cSrcweir             // VDev.
328*cdf0e10cSrcweir             mpRedrawManager->forEachSprite(
329*cdf0e10cSrcweir                 ::boost::bind(
330*cdf0e10cSrcweir                     &spriteRedraw,
331*cdf0e10cSrcweir                     ::boost::ref( maVDev.get() ),
332*cdf0e10cSrcweir                     _1 ) );
333*cdf0e10cSrcweir 
334*cdf0e10cSrcweir             // flush to screen
335*cdf0e10cSrcweir             rOutDev.EnableMapMode( sal_False );
336*cdf0e10cSrcweir             rOutDev.SetClipRegion();
337*cdf0e10cSrcweir             rOutDev.DrawOutDev( aEmptyPoint, aOutDevSize,
338*cdf0e10cSrcweir                                 aEmptyPoint, aOutDevSize,
339*cdf0e10cSrcweir                                 *maVDev );
340*cdf0e10cSrcweir         }
341*cdf0e10cSrcweir 
342*cdf0e10cSrcweir         // change record vector must be cleared, for the next turn of
343*cdf0e10cSrcweir         // rendering and sprite changing
344*cdf0e10cSrcweir         mpRedrawManager->clearChangeRecords();
345*cdf0e10cSrcweir 
346*cdf0e10cSrcweir         io_bSurfaceDirty = false;
347*cdf0e10cSrcweir 
348*cdf0e10cSrcweir         if( mbShowFrameInfo )
349*cdf0e10cSrcweir         {
350*cdf0e10cSrcweir             renderFrameCounter( rOutDev );
351*cdf0e10cSrcweir             renderSpriteCount( rOutDev );
352*cdf0e10cSrcweir             renderMemUsage( rOutDev );
353*cdf0e10cSrcweir         }
354*cdf0e10cSrcweir 
355*cdf0e10cSrcweir #if defined(VERBOSE) && OSL_DEBUG_LEVEL > 0
356*cdf0e10cSrcweir         static ::canvas::tools::ElapsedTime aElapsedTime;
357*cdf0e10cSrcweir 
358*cdf0e10cSrcweir         // log time immediately after surface flip
359*cdf0e10cSrcweir         OSL_TRACE( "SpriteCanvasHelper::updateScreen(): flip done at %f",
360*cdf0e10cSrcweir                    aElapsedTime.getElapsedTime() );
361*cdf0e10cSrcweir #endif
362*cdf0e10cSrcweir 
363*cdf0e10cSrcweir         // sync output with screen, to ensure that we don't queue up
364*cdf0e10cSrcweir         // render requests (calling code might rely on timing,
365*cdf0e10cSrcweir         // i.e. assume that things are visible on screen after
366*cdf0e10cSrcweir         // updateScreen() returns).
367*cdf0e10cSrcweir         if( pTargetWindow )
368*cdf0e10cSrcweir         {
369*cdf0e10cSrcweir             // commit to screen
370*cdf0e10cSrcweir             pTargetWindow->Sync();
371*cdf0e10cSrcweir         }
372*cdf0e10cSrcweir 
373*cdf0e10cSrcweir         return sal_True;
374*cdf0e10cSrcweir     }
375*cdf0e10cSrcweir 
376*cdf0e10cSrcweir     void SpriteCanvasHelper::backgroundPaint( const ::basegfx::B2DRange& rUpdateRect )
377*cdf0e10cSrcweir     {
378*cdf0e10cSrcweir         ENSURE_OR_THROW( mpOwningSpriteCanvas &&
379*cdf0e10cSrcweir                          mpOwningSpriteCanvas->getBackBuffer() &&
380*cdf0e10cSrcweir                          mpOwningSpriteCanvas->getFrontBuffer(),
381*cdf0e10cSrcweir                          "SpriteCanvasHelper::backgroundPaint(): NULL device pointer " );
382*cdf0e10cSrcweir 
383*cdf0e10cSrcweir         OutputDevice& 		rOutDev( mpOwningSpriteCanvas->getFrontBuffer()->getOutDev() );
384*cdf0e10cSrcweir         BackBufferSharedPtr pBackBuffer( mpOwningSpriteCanvas->getBackBuffer() );
385*cdf0e10cSrcweir         OutputDevice& 		rBackOutDev( pBackBuffer->getOutDev() );
386*cdf0e10cSrcweir 
387*cdf0e10cSrcweir         repaintBackground( rOutDev, rBackOutDev, rUpdateRect );
388*cdf0e10cSrcweir     }
389*cdf0e10cSrcweir 
390*cdf0e10cSrcweir     void SpriteCanvasHelper::scrollUpdate( const ::basegfx::B2DRange& 						rMoveStart,
391*cdf0e10cSrcweir                                            const ::basegfx::B2DRange& 						rMoveEnd,
392*cdf0e10cSrcweir                                            const ::canvas::SpriteRedrawManager::UpdateArea& rUpdateArea )
393*cdf0e10cSrcweir     {
394*cdf0e10cSrcweir         ENSURE_OR_THROW( mpOwningSpriteCanvas &&
395*cdf0e10cSrcweir                          mpOwningSpriteCanvas->getBackBuffer() &&
396*cdf0e10cSrcweir                          mpOwningSpriteCanvas->getFrontBuffer(),
397*cdf0e10cSrcweir                          "SpriteCanvasHelper::scrollUpdate(): NULL device pointer " );
398*cdf0e10cSrcweir 
399*cdf0e10cSrcweir         OutputDevice& 		rOutDev( mpOwningSpriteCanvas->getFrontBuffer()->getOutDev() );
400*cdf0e10cSrcweir         BackBufferSharedPtr pBackBuffer( mpOwningSpriteCanvas->getBackBuffer() );
401*cdf0e10cSrcweir         OutputDevice& 		rBackOutDev( pBackBuffer->getOutDev() );
402*cdf0e10cSrcweir 
403*cdf0e10cSrcweir         const Size&                rTargetSizePixel( rOutDev.GetOutputSizePixel() );
404*cdf0e10cSrcweir         const ::basegfx::B2IRange  aOutputBounds( 0,0,
405*cdf0e10cSrcweir                                                   rTargetSizePixel.Width(),
406*cdf0e10cSrcweir                                                   rTargetSizePixel.Height() );
407*cdf0e10cSrcweir 
408*cdf0e10cSrcweir         // round rectangles to integer pixel. Note: have to be
409*cdf0e10cSrcweir         // extremely careful here, to avoid off-by-one errors for
410*cdf0e10cSrcweir         // the destination area: otherwise, the next scroll update
411*cdf0e10cSrcweir         // would copy pixel that are not supposed to be part of
412*cdf0e10cSrcweir         // the sprite.
413*cdf0e10cSrcweir         ::basegfx::B2IRange aSourceRect(
414*cdf0e10cSrcweir             ::canvas::tools::spritePixelAreaFromB2DRange( rMoveStart ) );
415*cdf0e10cSrcweir         const ::basegfx::B2IRange& rDestRect(
416*cdf0e10cSrcweir             ::canvas::tools::spritePixelAreaFromB2DRange( rMoveEnd ) );
417*cdf0e10cSrcweir         ::basegfx::B2IPoint aDestPos( rDestRect.getMinimum() );
418*cdf0e10cSrcweir 
419*cdf0e10cSrcweir         ::std::vector< ::basegfx::B2IRange > aUnscrollableAreas;
420*cdf0e10cSrcweir 
421*cdf0e10cSrcweir         // Since strictly speaking, this scroll algorithm is plain
422*cdf0e10cSrcweir         // buggy, the scrolled area might actually lie _below_ another
423*cdf0e10cSrcweir         // window - we've made this feature configurable via
424*cdf0e10cSrcweir         // mbIsUnsafeScrolling.
425*cdf0e10cSrcweir 
426*cdf0e10cSrcweir         // clip to output bounds (cannot properly scroll stuff
427*cdf0e10cSrcweir         // _outside_ our screen area)
428*cdf0e10cSrcweir         if( !mbIsUnsafeScrolling ||
429*cdf0e10cSrcweir             !::canvas::tools::clipScrollArea( aSourceRect,
430*cdf0e10cSrcweir                                               aDestPos,
431*cdf0e10cSrcweir                                               aUnscrollableAreas,
432*cdf0e10cSrcweir                                               aOutputBounds ) )
433*cdf0e10cSrcweir         {
434*cdf0e10cSrcweir             // fully clipped scroll area: cannot simply scroll
435*cdf0e10cSrcweir             // then. Perform normal opaque update (can use that, since
436*cdf0e10cSrcweir             // one of the preconditions for scrollable update is
437*cdf0e10cSrcweir             // opaque sprite content)
438*cdf0e10cSrcweir 
439*cdf0e10cSrcweir             // repaint all affected sprites directly to output device
440*cdf0e10cSrcweir             ::std::for_each( rUpdateArea.maComponentList.begin(),
441*cdf0e10cSrcweir                              rUpdateArea.maComponentList.end(),
442*cdf0e10cSrcweir                              ::boost::bind(
443*cdf0e10cSrcweir                                  &spriteRedrawStub3,
444*cdf0e10cSrcweir                                  ::boost::ref( rOutDev ),
445*cdf0e10cSrcweir                                  _1 ) );
446*cdf0e10cSrcweir         }
447*cdf0e10cSrcweir         else
448*cdf0e10cSrcweir         {
449*cdf0e10cSrcweir             // scroll rOutDev content
450*cdf0e10cSrcweir             rOutDev.CopyArea( ::vcl::unotools::pointFromB2IPoint( aDestPos ),
451*cdf0e10cSrcweir                               ::vcl::unotools::pointFromB2IPoint( aSourceRect.getMinimum() ),
452*cdf0e10cSrcweir                               // TODO(Q2): use numeric_cast to check range
453*cdf0e10cSrcweir                               ::Size( static_cast<sal_Int32>(aSourceRect.getRange().getX()),
454*cdf0e10cSrcweir                                       static_cast<sal_Int32>(aSourceRect.getRange().getY()) ) );
455*cdf0e10cSrcweir 
456*cdf0e10cSrcweir             const ::canvas::SpriteRedrawManager::SpriteConnectedRanges::ComponentListType::const_iterator
457*cdf0e10cSrcweir                 aFirst( rUpdateArea.maComponentList.begin() );
458*cdf0e10cSrcweir             ::canvas::SpriteRedrawManager::SpriteConnectedRanges::ComponentListType::const_iterator
459*cdf0e10cSrcweir                   aSecond( aFirst ); ++aSecond;
460*cdf0e10cSrcweir 
461*cdf0e10cSrcweir             ENSURE_OR_THROW( aFirst->second.getSprite().is(),
462*cdf0e10cSrcweir                               "VCLCanvas::scrollUpdate(): no sprite" );
463*cdf0e10cSrcweir 
464*cdf0e10cSrcweir             // repaint uncovered areas from sprite. Need to actually
465*cdf0e10cSrcweir             // clip here, since we're only repainting _parts_ of the
466*cdf0e10cSrcweir             // sprite
467*cdf0e10cSrcweir             rOutDev.Push( PUSH_CLIPREGION );
468*cdf0e10cSrcweir             ::std::for_each( aUnscrollableAreas.begin(),
469*cdf0e10cSrcweir                              aUnscrollableAreas.end(),
470*cdf0e10cSrcweir                              ::boost::bind( &opaqueUpdateSpriteArea,
471*cdf0e10cSrcweir                                             ::boost::cref(aFirst->second.getSprite()),
472*cdf0e10cSrcweir                                             ::boost::ref(rOutDev),
473*cdf0e10cSrcweir                                             _1 ) );
474*cdf0e10cSrcweir             rOutDev.Pop();
475*cdf0e10cSrcweir         }
476*cdf0e10cSrcweir 
477*cdf0e10cSrcweir         // repaint uncovered areas from backbuffer - take the
478*cdf0e10cSrcweir         // _rounded_ rectangles from above, to have the update
479*cdf0e10cSrcweir         // consistent with the scroll above.
480*cdf0e10cSrcweir         ::std::vector< ::basegfx::B2DRange > aUncoveredAreas;
481*cdf0e10cSrcweir         ::basegfx::computeSetDifference( aUncoveredAreas,
482*cdf0e10cSrcweir                                          rUpdateArea.maTotalBounds,
483*cdf0e10cSrcweir                                          ::basegfx::B2DRange( rDestRect ) );
484*cdf0e10cSrcweir         ::std::for_each( aUncoveredAreas.begin(),
485*cdf0e10cSrcweir                          aUncoveredAreas.end(),
486*cdf0e10cSrcweir                          ::boost::bind( &repaintBackground,
487*cdf0e10cSrcweir                                         ::boost::ref(rOutDev),
488*cdf0e10cSrcweir                                         ::boost::ref(rBackOutDev),
489*cdf0e10cSrcweir                                         _1 ) );
490*cdf0e10cSrcweir     }
491*cdf0e10cSrcweir 
492*cdf0e10cSrcweir     void SpriteCanvasHelper::opaqueUpdate( const ::basegfx::B2DRange&                          rTotalArea,
493*cdf0e10cSrcweir                                            const ::std::vector< ::canvas::Sprite::Reference >& rSortedUpdateSprites )
494*cdf0e10cSrcweir     {
495*cdf0e10cSrcweir         (void)rTotalArea;
496*cdf0e10cSrcweir 
497*cdf0e10cSrcweir         ENSURE_OR_THROW( mpOwningSpriteCanvas &&
498*cdf0e10cSrcweir                          mpOwningSpriteCanvas->getBackBuffer() &&
499*cdf0e10cSrcweir                          mpOwningSpriteCanvas->getFrontBuffer(),
500*cdf0e10cSrcweir                          "SpriteCanvasHelper::opaqueUpdate(): NULL device pointer " );
501*cdf0e10cSrcweir 
502*cdf0e10cSrcweir         OutputDevice& rOutDev( mpOwningSpriteCanvas->getFrontBuffer()->getOutDev() );
503*cdf0e10cSrcweir 
504*cdf0e10cSrcweir         // no need to clip output to actual update region - there will
505*cdf0e10cSrcweir         // always be ALL sprites contained in the rectangular update
506*cdf0e10cSrcweir         // area containd in rTotalArea (that's the way
507*cdf0e10cSrcweir         // B2DConnectedRanges work). If rTotalArea appears to be
508*cdf0e10cSrcweir         // smaller than the sprite - then this sprite carries a clip,
509*cdf0e10cSrcweir         // and the update will be constrained to that rect.
510*cdf0e10cSrcweir 
511*cdf0e10cSrcweir         // repaint all affected sprites directly to output device
512*cdf0e10cSrcweir         ::std::for_each( rSortedUpdateSprites.begin(),
513*cdf0e10cSrcweir                          rSortedUpdateSprites.end(),
514*cdf0e10cSrcweir                          ::boost::bind(
515*cdf0e10cSrcweir                              &spriteRedrawStub,
516*cdf0e10cSrcweir                              ::boost::ref( rOutDev ),
517*cdf0e10cSrcweir                              _1 ) );
518*cdf0e10cSrcweir     }
519*cdf0e10cSrcweir 
520*cdf0e10cSrcweir     void SpriteCanvasHelper::genericUpdate( const ::basegfx::B2DRange&                          rRequestedArea,
521*cdf0e10cSrcweir                                             const ::std::vector< ::canvas::Sprite::Reference >& rSortedUpdateSprites )
522*cdf0e10cSrcweir     {
523*cdf0e10cSrcweir         ENSURE_OR_THROW( mpOwningSpriteCanvas &&
524*cdf0e10cSrcweir                          mpOwningSpriteCanvas->getBackBuffer() &&
525*cdf0e10cSrcweir                          mpOwningSpriteCanvas->getFrontBuffer(),
526*cdf0e10cSrcweir                          "SpriteCanvasHelper::genericUpdate(): NULL device pointer " );
527*cdf0e10cSrcweir 
528*cdf0e10cSrcweir         OutputDevice& 		rOutDev( mpOwningSpriteCanvas->getFrontBuffer()->getOutDev() );
529*cdf0e10cSrcweir         BackBufferSharedPtr pBackBuffer( mpOwningSpriteCanvas->getBackBuffer() );
530*cdf0e10cSrcweir         OutputDevice& 		rBackOutDev( pBackBuffer->getOutDev() );
531*cdf0e10cSrcweir 
532*cdf0e10cSrcweir         // limit size of update VDev to target outdev's size
533*cdf0e10cSrcweir         const Size& rTargetSizePixel( rOutDev.GetOutputSizePixel() );
534*cdf0e10cSrcweir 
535*cdf0e10cSrcweir         // round output position towards zero. Don't want to truncate
536*cdf0e10cSrcweir         // a fraction of a sprite pixel...  Clip position at origin,
537*cdf0e10cSrcweir         // otherwise, truncation of size below might leave visible
538*cdf0e10cSrcweir         // areas uncovered by VDev.
539*cdf0e10cSrcweir         const ::Point aOutputPosition(
540*cdf0e10cSrcweir             ::std::max( sal_Int32( 0 ),
541*cdf0e10cSrcweir                         static_cast< sal_Int32 >(rRequestedArea.getMinX()) ),
542*cdf0e10cSrcweir             ::std::max( sal_Int32( 0 ),
543*cdf0e10cSrcweir                         static_cast< sal_Int32 >(rRequestedArea.getMinY()) ) );
544*cdf0e10cSrcweir         // round output size towards +infty. Don't want to truncate a
545*cdf0e10cSrcweir         // fraction of a sprite pixel... Limit coverage of VDev to
546*cdf0e10cSrcweir         // output device's area (i.e. not only to total size, but to
547*cdf0e10cSrcweir         // cover _only_ the visible parts).
548*cdf0e10cSrcweir         const ::Size aOutputSize(
549*cdf0e10cSrcweir             ::std::max( sal_Int32( 0 ),
550*cdf0e10cSrcweir                         ::std::min( static_cast< sal_Int32 >(rTargetSizePixel.Width() - aOutputPosition.X()),
551*cdf0e10cSrcweir                                     ::canvas::tools::roundUp( rRequestedArea.getMaxX() - aOutputPosition.X() ))),
552*cdf0e10cSrcweir             ::std::max( sal_Int32( 0 ),
553*cdf0e10cSrcweir                         ::std::min( static_cast< sal_Int32 >(rTargetSizePixel.Height() - aOutputPosition.Y()),
554*cdf0e10cSrcweir                                     ::canvas::tools::roundUp( rRequestedArea.getMaxY() - aOutputPosition.Y() ))));
555*cdf0e10cSrcweir 
556*cdf0e10cSrcweir         // early exit for empty output area.
557*cdf0e10cSrcweir         if( aOutputSize.Width() == 0 &&
558*cdf0e10cSrcweir             aOutputSize.Height() == 0 )
559*cdf0e10cSrcweir         {
560*cdf0e10cSrcweir             return;
561*cdf0e10cSrcweir         }
562*cdf0e10cSrcweir 
563*cdf0e10cSrcweir         const Point aEmptyPoint(0,0);
564*cdf0e10cSrcweir         const Size  aCurrOutputSize( maVDev->GetOutputSizePixel() );
565*cdf0e10cSrcweir 
566*cdf0e10cSrcweir         // adapt maVDev's size to the area that actually needs the
567*cdf0e10cSrcweir         // repaint.
568*cdf0e10cSrcweir         if( aCurrOutputSize.Width() < aOutputSize.Width() ||
569*cdf0e10cSrcweir             aCurrOutputSize.Height() < aOutputSize.Height() )
570*cdf0e10cSrcweir         {
571*cdf0e10cSrcweir             // TODO(P1): Come up with a clever tactic to reduce maVDev
572*cdf0e10cSrcweir             // from time to time. Reduction with threshold (say, if
573*cdf0e10cSrcweir             // maVDev is more than twice too large) is not wise, as
574*cdf0e10cSrcweir             // this might then toggle within the same updateScreen(),
575*cdf0e10cSrcweir             // but for different disjunct sprite areas.
576*cdf0e10cSrcweir             maVDev->SetOutputSizePixel( aOutputSize );
577*cdf0e10cSrcweir         }
578*cdf0e10cSrcweir 
579*cdf0e10cSrcweir         // paint background
580*cdf0e10cSrcweir         maVDev->EnableMapMode( sal_False );
581*cdf0e10cSrcweir         maVDev->SetClipRegion();
582*cdf0e10cSrcweir         maVDev->DrawOutDev( aEmptyPoint, aOutputSize,
583*cdf0e10cSrcweir                             aOutputPosition, aOutputSize,
584*cdf0e10cSrcweir                             rBackOutDev );
585*cdf0e10cSrcweir 
586*cdf0e10cSrcweir         // repaint all affected sprites on top of background into
587*cdf0e10cSrcweir         // VDev.
588*cdf0e10cSrcweir         ::std::for_each( rSortedUpdateSprites.begin(),
589*cdf0e10cSrcweir                          rSortedUpdateSprites.end(),
590*cdf0e10cSrcweir                          ::boost::bind( &spriteRedrawStub2,
591*cdf0e10cSrcweir                                         ::boost::ref( maVDev.get() ),
592*cdf0e10cSrcweir                                         ::boost::cref(
593*cdf0e10cSrcweir                                             ::vcl::unotools::b2DPointFromPoint(aOutputPosition)),
594*cdf0e10cSrcweir                                         _1 ) );
595*cdf0e10cSrcweir 
596*cdf0e10cSrcweir         // flush to screen
597*cdf0e10cSrcweir         rOutDev.EnableMapMode( sal_False );
598*cdf0e10cSrcweir         rOutDev.DrawOutDev( aOutputPosition, aOutputSize,
599*cdf0e10cSrcweir                             aEmptyPoint, aOutputSize,
600*cdf0e10cSrcweir                             *maVDev );
601*cdf0e10cSrcweir     }
602*cdf0e10cSrcweir 
603*cdf0e10cSrcweir     void SpriteCanvasHelper::renderFrameCounter( OutputDevice& rOutDev )
604*cdf0e10cSrcweir     {
605*cdf0e10cSrcweir         const double denominator( maLastUpdate.getElapsedTime() );
606*cdf0e10cSrcweir         maLastUpdate.reset();
607*cdf0e10cSrcweir 
608*cdf0e10cSrcweir         ::rtl::OUString text( ::rtl::math::doubleToUString( denominator == 0.0 ? 100.0 : 1.0/denominator,
609*cdf0e10cSrcweir                                                             rtl_math_StringFormat_F,
610*cdf0e10cSrcweir                                                             2,'.',NULL,' ') );
611*cdf0e10cSrcweir 
612*cdf0e10cSrcweir         // pad with leading space
613*cdf0e10cSrcweir         while( text.getLength() < 6 )
614*cdf0e10cSrcweir             text = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM (" ")) + text;
615*cdf0e10cSrcweir 
616*cdf0e10cSrcweir         text += ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM (" fps"));
617*cdf0e10cSrcweir 
618*cdf0e10cSrcweir         renderInfoText( rOutDev,
619*cdf0e10cSrcweir                         text,
620*cdf0e10cSrcweir                         Point(0, 0) );
621*cdf0e10cSrcweir     }
622*cdf0e10cSrcweir 
623*cdf0e10cSrcweir     namespace
624*cdf0e10cSrcweir     {
625*cdf0e10cSrcweir         template< typename T > struct Adder
626*cdf0e10cSrcweir         {
627*cdf0e10cSrcweir             typedef void result_type;
628*cdf0e10cSrcweir 
629*cdf0e10cSrcweir             Adder( T& rAdderTarget,
630*cdf0e10cSrcweir                    T  nIncrement ) :
631*cdf0e10cSrcweir                 mpTarget( &rAdderTarget ),
632*cdf0e10cSrcweir                 mnIncrement( nIncrement )
633*cdf0e10cSrcweir             {
634*cdf0e10cSrcweir             }
635*cdf0e10cSrcweir 
636*cdf0e10cSrcweir             void operator()() { *mpTarget += mnIncrement; }
637*cdf0e10cSrcweir             void operator()( const ::canvas::Sprite::Reference& ) { *mpTarget += mnIncrement; }
638*cdf0e10cSrcweir             void operator()( T nIncrement ) { *mpTarget += nIncrement; }
639*cdf0e10cSrcweir 
640*cdf0e10cSrcweir             T* mpTarget;
641*cdf0e10cSrcweir             T  mnIncrement;
642*cdf0e10cSrcweir         };
643*cdf0e10cSrcweir 
644*cdf0e10cSrcweir         template< typename T> Adder<T> makeAdder( T& rAdderTarget,
645*cdf0e10cSrcweir                                                   T  nIncrement )
646*cdf0e10cSrcweir         {
647*cdf0e10cSrcweir             return Adder<T>(rAdderTarget, nIncrement);
648*cdf0e10cSrcweir         }
649*cdf0e10cSrcweir     }
650*cdf0e10cSrcweir 
651*cdf0e10cSrcweir     void SpriteCanvasHelper::renderSpriteCount( OutputDevice& rOutDev )
652*cdf0e10cSrcweir     {
653*cdf0e10cSrcweir         if( mpRedrawManager )
654*cdf0e10cSrcweir         {
655*cdf0e10cSrcweir             sal_Int32 nCount(0);
656*cdf0e10cSrcweir 
657*cdf0e10cSrcweir             mpRedrawManager->forEachSprite( makeAdder(nCount,sal_Int32(1)) );
658*cdf0e10cSrcweir             ::rtl::OUString text(
659*cdf0e10cSrcweir                 ::rtl::OUString::valueOf(
660*cdf0e10cSrcweir                     // disambiguate overload...
661*cdf0e10cSrcweir                     static_cast<sal_Int64>(nCount) ) );
662*cdf0e10cSrcweir 
663*cdf0e10cSrcweir             // pad with leading space
664*cdf0e10cSrcweir             while( text.getLength() < 3 )
665*cdf0e10cSrcweir                 text = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM (" ")) + text;
666*cdf0e10cSrcweir 
667*cdf0e10cSrcweir             text = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM ("Sprites: ")) + text;
668*cdf0e10cSrcweir 
669*cdf0e10cSrcweir             renderInfoText( rOutDev,
670*cdf0e10cSrcweir                             text,
671*cdf0e10cSrcweir                             Point(0, 30) );
672*cdf0e10cSrcweir         }
673*cdf0e10cSrcweir     }
674*cdf0e10cSrcweir 
675*cdf0e10cSrcweir     void SpriteCanvasHelper::renderMemUsage( OutputDevice& rOutDev )
676*cdf0e10cSrcweir     {
677*cdf0e10cSrcweir         BackBufferSharedPtr pBackBuffer( mpOwningSpriteCanvas->getBackBuffer() );
678*cdf0e10cSrcweir 
679*cdf0e10cSrcweir         if( mpRedrawManager &&
680*cdf0e10cSrcweir             pBackBuffer )
681*cdf0e10cSrcweir         {
682*cdf0e10cSrcweir             double nPixel(0.0);
683*cdf0e10cSrcweir 
684*cdf0e10cSrcweir             // accumulate pixel count for each sprite into fCount
685*cdf0e10cSrcweir             mpRedrawManager->forEachSprite( ::boost::bind(
686*cdf0e10cSrcweir                                                 makeAdder(nPixel,1.0),
687*cdf0e10cSrcweir                                                 ::boost::bind(
688*cdf0e10cSrcweir                                                     &calcNumPixel,
689*cdf0e10cSrcweir                                                     _1 ) ) );
690*cdf0e10cSrcweir 
691*cdf0e10cSrcweir             static const int NUM_VIRDEV(2);
692*cdf0e10cSrcweir             static const int BYTES_PER_PIXEL(3);
693*cdf0e10cSrcweir 
694*cdf0e10cSrcweir             const Size& rVDevSize( maVDev->GetOutputSizePixel() );
695*cdf0e10cSrcweir             const Size& rBackBufferSize( pBackBuffer->getOutDev().GetOutputSizePixel() );
696*cdf0e10cSrcweir 
697*cdf0e10cSrcweir             const double nMemUsage( nPixel * NUM_VIRDEV * BYTES_PER_PIXEL +
698*cdf0e10cSrcweir                                     rVDevSize.Width()*rVDevSize.Height() * BYTES_PER_PIXEL +
699*cdf0e10cSrcweir                                     rBackBufferSize.Width()*rBackBufferSize.Height() * BYTES_PER_PIXEL );
700*cdf0e10cSrcweir 
701*cdf0e10cSrcweir             ::rtl::OUString text( ::rtl::math::doubleToUString( nMemUsage / 1048576.0,
702*cdf0e10cSrcweir                                                                 rtl_math_StringFormat_F,
703*cdf0e10cSrcweir                                                                 2,'.',NULL,' ') );
704*cdf0e10cSrcweir 
705*cdf0e10cSrcweir             // pad with leading space
706*cdf0e10cSrcweir             while( text.getLength() < 4 )
707*cdf0e10cSrcweir                 text = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM (" ")) + text;
708*cdf0e10cSrcweir 
709*cdf0e10cSrcweir             text = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM ("Mem: ")) +
710*cdf0e10cSrcweir                 text +
711*cdf0e10cSrcweir                 ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM ("MB"));
712*cdf0e10cSrcweir 
713*cdf0e10cSrcweir             renderInfoText( rOutDev,
714*cdf0e10cSrcweir                             text,
715*cdf0e10cSrcweir                             Point(0, 60) );
716*cdf0e10cSrcweir         }
717*cdf0e10cSrcweir     }
718*cdf0e10cSrcweir }
719