diff options
Diffstat (limited to 'canvas/inc/canvas/spriteredrawmanager.hxx')
-rw-r--r-- | canvas/inc/canvas/spriteredrawmanager.hxx | 453 |
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 */ |