office-gobmx/canvas/inc/canvas/spriteredrawmanager.hxx
Bjoern Michaelsen 941020379b Merge branch 'master' into feature/gnumake4
Conflicts:
	basebmp/prj/d.lst
	basebmp/test/basictest.cxx
	basebmp/test/makefile.mk
	basegfx/inc/basegfx/basegfxdllapi.h
	basegfx/inc/basegfx/tools/debugplotter.hxx
	basegfx/inc/basegfx/tuple/b2ituple.hxx
	basegfx/prj/d.lst
	basegfx/source/numeric/makefile.mk
	basegfx/source/polygon/makefile.mk
	basegfx/source/range/makefile.mk
	basegfx/source/raster/makefile.mk
	basegfx/source/tuple/makefile.mk
	basegfx/source/vector/makefile.mk
	basegfx/test/basegfx1d.cxx
	basegfx/test/makefile.mk
	basegfx/util/makefile.mk
	canvas/Library_canvasfactory.mk
	canvas/Module_canvas.mk
	canvas/prj/build.lst
	canvas/prj/d.lst
	canvas/source/cairo/cairo_canvashelper_texturefill.cxx
	canvas/source/cairo/makefile.mk
	canvas/source/tools/makefile.mk
	comphelper/qa/string/makefile.mk
	cppcanvas/Module_cppcanvas.mk
	cppcanvas/inc/cppcanvas/cppcanvasdllapi.h
	cppcanvas/prj/build.lst
	cppcanvas/prj/d.lst
	cppcanvas/source/mtfrenderer/makefile.mk
	cppcanvas/util/makefile.mk
	i18npool/source/search/makefile.mk
	regexp/Library_regexp.mk
	regexp/prj/d.lst
	sax/CppunitTest_sax.mk
	sax/Library_sax.mk
	sax/prj/d.lst
	sax/qa/cppunit/test_converter.cxx
	sax/source/expatwrap/attrlistimpl.hxx
	sax/util/makefile.mk
	svtools/Library_svt.mk
	tools/Executable_sspretty.mk
	ucbhelper/prj/d.lst
	ucbhelper/source/provider/configureucb.cxx
	ucbhelper/source/provider/provconf.cxx
	ucbhelper/util/makefile.mk
	unotools/Library_utl.mk
	unotools/Module_unotools.mk
	unotools/Package_inc.mk
	unotools/prj/build.lst
	vcl/Library_desktop_detector.mk
	vcl/Library_vcl.mk
	vcl/Library_vclplug_gtk.mk
	vcl/aqua/source/gdi/salprn.cxx
	vcl/inc/aqua/saldata.hxx
	vcl/unx/generic/gdi/salgdi3.cxx
2011-06-19 12:47:44 +02:00

438 lines
18 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright 2000, 2010 Oracle and/or its affiliates.
*
* OpenOffice.org - a multi-platform office productivity suite
*
* This file is part of OpenOffice.org.
*
* OpenOffice.org is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3
* only, as published by the Free Software Foundation.
*
* OpenOffice.org 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 version 3 for more details
* (a copy is included in the LICENSE file that accompanied this code).
*
* You should have received a copy of the GNU Lesser General Public License
* version 3 along with OpenOffice.org. If not, see
* <http://www.openoffice.org/license.html>
* for a copy of the LGPLv3 License.
*
************************************************************************/
#ifndef INCLUDED_CANVAS_SPRITEREDRAWMANAGER_HXX
#define INCLUDED_CANVAS_SPRITEREDRAWMANAGER_HXX
#include <basegfx/range/b2dconnectedranges.hxx>
#include <basegfx/point/b2dpoint.hxx>
#include <basegfx/vector/b2dvector.hxx>
#include <basegfx/range/b2drange.hxx>
#include <basegfx/range/b2irange.hxx>
#include <basegfx/matrix/b2dhommatrix.hxx>
#include <canvas/base/spritesurface.hxx>
#include <list>
#include <vector>
#include <algorithm>
#include <boost/utility.hpp>
#include <boost/bind.hpp>
#include <canvas/canvastoolsdllapi.h>
/* 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 CANVASTOOLS_DLLPUBLIC SpriteRedrawManager : private ::boost::noncopyable
{
public:
/** Data container for the connected components list
*/
class SpriteInfo
{
public:
~SpriteInfo() {}
/** 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; }
// #i61843# need to return by value here, to be used safely from bind
::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 */
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */