summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--canvas/inc/canvas/spriteredrawmanager.hxx453
1 files changed, 453 insertions, 0 deletions
diff --git a/canvas/inc/canvas/spriteredrawmanager.hxx b/canvas/inc/canvas/spriteredrawmanager.hxx
new file mode 100644
index 000000000000..fd781e4552df
--- /dev/null
+++ b/canvas/inc/canvas/spriteredrawmanager.hxx
@@ -0,0 +1,453 @@
+/*************************************************************************
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * $RCSfile: spriteredrawmanager.hxx,v $
+ *
+ * $Revision: 1.2 $
+ *
+ * last change: $Author: kz $ $Date: 2005-11-02 12:41:12 $
+ *
+ * The Contents of this file are made available subject to
+ * the terms of GNU Lesser General Public License Version 2.1.
+ *
+ *
+ * GNU Lesser General Public License Version 2.1
+ * =============================================
+ * Copyright 2005 by Sun Microsystems, Inc.
+ * 901 San Antonio Road, Palo Alto, CA 94303, USA
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ ************************************************************************/
+
+#ifndef INCLUDED_CANVAS_SPRITEREDRAWMANAGER_HXX
+#define INCLUDED_CANVAS_SPRITEREDRAWMANAGER_HXX
+
+#ifndef _BGFX_RANGE_B2DCONNECTEDRANGES_HXX
+#include <basegfx/range/b2dconnectedranges.hxx>
+#endif
+#ifndef _BGFX_POINT_B2DPOINT_HXX
+#include <basegfx/point/b2dpoint.hxx>
+#endif
+#ifndef _BGFX_VECTOR_B2DVECTOR_HXX
+#include <basegfx/vector/b2dvector.hxx>
+#endif
+#ifndef _BGFX_RANGE_B2DRANGE_HXX
+#include <basegfx/range/b2drange.hxx>
+#endif
+#ifndef _BGFX_RANGE_B2IRANGE_HXX
+#include <basegfx/range/b2irange.hxx>
+#endif
+#ifndef _BGFX_MATRIX_B2DHOMMATRIX_HXX
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#endif
+
+#ifndef INCLUDED_CANVAS_SPRITESURFACE_HXX
+#include <canvas/base/spritesurface.hxx>
+#endif
+
+#include <list>
+#include <vector>
+#include <algorithm>
+
+#include <boost/utility.hpp>
+#include <boost/bind.hpp>
+
+
+/* Definition of SpriteRedrawManager class */
+
+namespace canvas
+{
+ /** This class manages smooth SpriteCanvas updates
+
+ Use this class to handle the ::canvas::SpriteSurface methods,
+ that track and process sprite update events. Recorded update
+ events are later grouped by connected areas (i.e. all sprites
+ that somehow overlap over a rectangular area are grouped
+ together); the forEachSpriteArea() method calls the passed
+ functor for each of those connected areas.
+
+ Note that, although this class generally works with IEEE
+ doubles, the calculation of connected areas happens in the
+ integer domain - it is generally expected that repaints can
+ only be divided at pixel boundaries, without causing visible
+ artifacts. Therefore, sprites that touch the same pixel (but
+ don't necessarily have the same floating point coordinates
+ there) will reside in a common sprite area and handled
+ together in the forEachSpriteArea functor call.
+ */
+ class SpriteRedrawManager : private ::boost::noncopyable
+ {
+ public:
+ /** Data container for the connected components list
+ */
+ class SpriteInfo
+ {
+ public:
+ /** Create sprite info
+
+ @param rRef
+ Sprite this info represents (might be the NULL ref)
+
+ @param rTrueUpdateArea
+ True (un-rounded) update area this sprite has recorded
+
+ @param bNeedsUpdate
+ When false, this sprite is not a member of the change
+ record list. Thus, it only needs redraw if within the
+ update area of other, changed sprites.
+
+ @internal
+ */
+ SpriteInfo( const Sprite::Reference& rRef,
+ const ::basegfx::B2DRange& rTrueUpdateArea,
+ bool bNeedsUpdate ) :
+ mpSprite( rRef ),
+ maTrueUpdateArea( rTrueUpdateArea ),
+ mbNeedsUpdate( bNeedsUpdate ),
+ mbIsPureMove( false )
+ {
+ }
+
+ /** Create sprite info, specify move type
+
+ @param rRef
+ Sprite this info represents (might be the NULL ref)
+
+ @param rTrueUpdateArea
+ True (un-rounded) update area this sprite has recorded
+
+ @param bNeedsUpdate
+ When false, this sprite is not a member of the change
+ record list. Thus, it only needs redraw if within the
+ update area of other, changed sprites.
+
+ @param bIsPureMove
+ When true, this sprite is _only_ moved, no other
+ changes happened.
+
+ @internal
+ */
+ SpriteInfo( const Sprite::Reference& rRef,
+ const ::basegfx::B2DRange& rTrueUpdateArea,
+ bool bNeedsUpdate,
+ bool bIsPureMove ) :
+ mpSprite( rRef ),
+ maTrueUpdateArea( rTrueUpdateArea ),
+ mbNeedsUpdate( bNeedsUpdate ),
+ mbIsPureMove( bIsPureMove )
+ {
+ }
+
+ const Sprite::Reference& getSprite() const { return mpSprite; }
+ const ::basegfx::B2DRange& getUpdateArea() const { return maTrueUpdateArea; }
+ bool needsUpdate() const { return mbNeedsUpdate; }
+ bool isPureMove() const { return mbIsPureMove; }
+
+ private:
+ Sprite::Reference mpSprite;
+ ::basegfx::B2DRange maTrueUpdateArea;
+ bool mbNeedsUpdate;
+ bool mbIsPureMove;
+ };
+
+
+ /** Helper struct for SpriteTracer template
+
+ This struct stores change information to a sprite's visual
+ appearance (move, content updated, and the like).
+ */
+ struct SpriteChangeRecord
+ {
+ typedef enum{ none=0, move, update } ChangeType;
+
+ SpriteChangeRecord() :
+ meChangeType( none ),
+ mpAffectedSprite(),
+ maOldPos(),
+ maUpdateArea()
+ {
+ }
+
+ SpriteChangeRecord( const Sprite::Reference& rSprite,
+ const ::basegfx::B2DPoint& rOldPos,
+ const ::basegfx::B2DPoint& rNewPos,
+ const ::basegfx::B2DVector& rSpriteSize ) :
+ meChangeType( move ),
+ mpAffectedSprite( rSprite ),
+ maOldPos( rOldPos ),
+ maUpdateArea( rNewPos.getX(),
+ rNewPos.getY(),
+ rNewPos.getX() + rSpriteSize.getX(),
+ rNewPos.getY() + rSpriteSize.getY() )
+ {
+ }
+
+ SpriteChangeRecord( const Sprite::Reference& rSprite,
+ const ::basegfx::B2DPoint& rPos,
+ const ::basegfx::B2DRange& rUpdateArea ) :
+ meChangeType( update ),
+ mpAffectedSprite( rSprite ),
+ maOldPos( rPos ),
+ maUpdateArea( rUpdateArea )
+ {
+ }
+
+ Sprite::Reference getSprite() const { return mpAffectedSprite; }
+
+ ChangeType meChangeType;
+ Sprite::Reference mpAffectedSprite;
+ ::basegfx::B2DPoint maOldPos;
+ ::basegfx::B2DRange maUpdateArea;
+ };
+
+ typedef ::std::vector< SpriteChangeRecord > VectorOfChangeRecords;
+ typedef ::std::list< Sprite::Reference > ListOfSprites;
+ typedef ::basegfx::B2DConnectedRanges< SpriteInfo > SpriteConnectedRanges;
+ typedef SpriteConnectedRanges::ComponentType AreaComponent;
+ typedef SpriteConnectedRanges::ConnectedComponents UpdateArea;
+ typedef ::std::vector< Sprite::Reference > VectorOfSprites;
+
+ SpriteRedrawManager();
+
+ /** Must be called when user of this object gets
+ disposed. Frees all internal references.
+ */
+ void disposing();
+
+ /** Functor, to be used from forEachSpriteArea
+ */
+ template< typename Functor > struct AreaUpdateCaller
+ {
+ AreaUpdateCaller( Functor& rFunc,
+ const SpriteRedrawManager& rManager ) :
+ mrFunc( rFunc ),
+ mrManager( rManager )
+ {
+ }
+
+ void operator()( const UpdateArea& rUpdateArea )
+ {
+ mrManager.handleArea( mrFunc, rUpdateArea );
+ }
+
+ Functor& mrFunc;
+ const SpriteRedrawManager& mrManager;
+ };
+
+ /** Call given functor for each sprite area that needs an
+ update.
+
+ This method calls the given functor for each update area
+ (calculated from the sprite change records).
+
+ @tpl Functor
+ Must provide the following four methods:
+ <pre>
+ void backgroundPaint( ::basegfx::B2DRange aUpdateRect );
+ void scrollUpdate( ::basegfx::B2DRange& o_rMoveStart,
+ ::basegfx::B2DRange& o_rMoveEnd,
+ UpdateArea aUpdateArea );
+ void opaqueUpdate( const ::basegfx::B2DRange& rTotalArea,
+ const ::std::vector< ::canvas::Sprite::Reference >& rSortedUpdateSprites );
+ void genericUpdate( const ::basegfx::B2DRange& rTotalArea,
+ const ::std::vector< ::canvas::Sprite::Reference >& rSortedUpdateSprites );
+ </pre>
+ The backgroundPaint() method is called to simply repaint
+ background content, the scrollUpdate() method is used to
+ scroll a given area, and paint background in the uncovered
+ areas, the opaqueUpdate() method is called when a sprite
+ can be painted in the given area without taking background
+ content into account, and finally, genericUpdate() is
+ called for complex updates, where first the background and
+ then all sprites consecutively have to be repainted.
+ */
+ template< typename Functor > void forEachSpriteArea( Functor& rFunc ) const
+ {
+ SpriteConnectedRanges aUpdateAreas;
+
+ setupUpdateAreas( aUpdateAreas );
+
+ aUpdateAreas.forEachAggregate(
+ AreaUpdateCaller< Functor >( rFunc, *this ) );
+ }
+
+ /** Call given functor for each active sprite.
+
+ This method calls the given functor for each active
+ sprite, in the order of sprite priority.
+
+ @tpl Functor
+ Must provide a Functor::operator( Sprite::Reference& )
+ method.
+ */
+ template< typename Functor > void forEachSprite( const Functor& rFunc ) const
+ {
+ ::std::for_each( maSprites.begin(),
+ maSprites.end(),
+ rFunc );
+ }
+
+ /// Clear sprite change records (typically directly after a screen update)
+ void clearChangeRecords();
+
+ // SpriteSurface interface, is delegated to e.g. from SpriteCanvas
+ void showSprite( const Sprite::Reference& rSprite );
+ void hideSprite( const Sprite::Reference& rSprite );
+ void moveSprite( const Sprite::Reference& rSprite,
+ const ::basegfx::B2DPoint& rOldPos,
+ const ::basegfx::B2DPoint& rNewPos,
+ const ::basegfx::B2DVector& rSpriteSize );
+ void updateSprite( const Sprite::Reference& rSprite,
+ const ::basegfx::B2DPoint& rPos,
+ const ::basegfx::B2DRange& rUpdateArea );
+
+ /** Internal, handles each distinct component for forEachAggregate()
+
+ The reason why this must be public is that it needs to be
+ accessible from the AreaUpdateCaller functor.
+
+ @internal
+ */
+ template< typename Functor > void handleArea( Functor& rFunc,
+ const UpdateArea& rUpdateArea ) const
+ {
+ // check whether this area contains changed sprites at all
+ // (if not, just ignore it)
+ if( areSpritesChanged( rUpdateArea ) )
+ {
+ // at least one of the sprites actually needs an
+ // update - process whole area.
+
+ // check whether this area could be handled special
+ // (background paint, direct update, scroll, etc.)
+ ::basegfx::B2DRange aMoveStart;
+ ::basegfx::B2DRange aMoveEnd;
+ if( rUpdateArea.maComponentList.empty() )
+ {
+ rFunc.backgroundPaint( rUpdateArea.maTotalBounds );
+ }
+ else
+ {
+ // cache number of sprites in this area (it's a
+ // list, and both isAreaUpdateScroll() and
+ // isAreaUpdateOpaque() need it).
+ const ::std::size_t nNumSprites(
+ rUpdateArea.maComponentList.size() );
+
+ if( isAreaUpdateScroll( aMoveStart,
+ aMoveEnd,
+ rUpdateArea,
+ nNumSprites ) )
+ {
+ rFunc.scrollUpdate( aMoveStart,
+ aMoveEnd,
+ rUpdateArea );
+ }
+ else
+ {
+ // potentially, more than a single sprite
+ // involved. Have to sort component lists for
+ // sprite prio.
+ VectorOfSprites aSortedUpdateSprites;
+ SpriteConnectedRanges::ComponentListType::const_iterator aCurr(
+ rUpdateArea.maComponentList.begin() );
+ const SpriteConnectedRanges::ComponentListType::const_iterator aEnd(
+ rUpdateArea.maComponentList.end() );
+ while( aCurr != aEnd )
+ {
+ const Sprite::Reference& rSprite( aCurr->second.getSprite() );
+ if( rSprite.is() )
+ aSortedUpdateSprites.push_back( rSprite );
+
+ ++aCurr;
+ }
+
+ ::std::sort( aSortedUpdateSprites.begin(),
+ aSortedUpdateSprites.end(),
+ SpriteComparator() );
+
+ if( isAreaUpdateOpaque( rUpdateArea,
+ nNumSprites ) )
+ {
+ rFunc.opaqueUpdate( rUpdateArea.maTotalBounds,
+ aSortedUpdateSprites );
+ }
+ else
+ {
+ rFunc.genericUpdate( rUpdateArea.maTotalBounds,
+ aSortedUpdateSprites );
+ }
+ }
+ }
+ }
+ }
+
+ private:
+ /** Central method of this class. Calculates the set of
+ disjunct components that need an update.
+ */
+ void setupUpdateAreas( SpriteConnectedRanges& rUpdateAreas ) const;
+
+ bool areSpritesChanged( const UpdateArea& rUpdateArea ) const;
+
+ bool isAreaUpdateNotOpaque( const ::basegfx::B2DRange& rUpdateRect,
+ const AreaComponent& rComponent ) const;
+
+ bool isAreaUpdateOpaque( const UpdateArea& rUpdateArea,
+ ::std::size_t nNumSprites ) const;
+
+ /** Check whether given update area can be handled by a simple
+ scroll
+
+ @param o_rMoveStart
+ Start rect of the move
+
+ @param o_rMoveEnd
+ End rect of the move. The content must be moved from start
+ to end rect
+
+ @param rUpdateArea
+ Area to check for scroll update optimization
+ */
+ bool isAreaUpdateScroll( ::basegfx::B2DRange& o_rMoveStart,
+ ::basegfx::B2DRange& o_rMoveEnd,
+ const UpdateArea& rUpdateArea,
+ ::std::size_t nNumSprites ) const;
+
+
+ ListOfSprites maSprites; // list of active
+ // sprite
+ // objects. this
+ // list is only
+ // used for full
+ // repaints,
+ // otherwise, we
+ // rely on the
+ // active sprites
+ // itself to notify
+ // us.
+
+ VectorOfChangeRecords maChangeRecords; // vector of
+ // sprites
+ // changes
+ // since last
+ // updateScreen()
+ // call
+ };
+}
+
+#endif /* INCLUDED_CANVAS_SPRITEREDRAWMANAGER_HXX */