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