LCOV - code coverage report
Current view: top level - canvas/source/vcl - spritecanvashelper.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 0 231 0.0 %
Date: 2015-06-13 12:38:46 Functions: 0 32 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11