1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #ifndef INCLUDED_CANVAS_SPRITEREDRAWMANAGER_HXX
21 #define INCLUDED_CANVAS_SPRITEREDRAWMANAGER_HXX
23 #include <basegfx/range/b2dconnectedranges.hxx>
24 #include <basegfx/point/b2dpoint.hxx>
25 #include <basegfx/vector/b2dvector.hxx>
26 #include <basegfx/range/b2drange.hxx>
27 #include <basegfx/range/b2irange.hxx>
28 #include <basegfx/matrix/b2dhommatrix.hxx>
29 #include <canvas/base/spritesurface.hxx>
35 #include <boost/utility.hpp>
36 #include <boost/bind.hpp>
38 #include <canvas/canvastoolsdllapi.h>
40 /* Definition of SpriteRedrawManager class */
44 /** This class manages smooth SpriteCanvas updates
46 Use this class to handle the ::canvas::SpriteSurface methods,
47 that track and process sprite update events. Recorded update
48 events are later grouped by connected areas (i.e. all sprites
49 that somehow overlap over a rectangular area are grouped
50 together); the forEachSpriteArea() method calls the passed
51 functor for each of those connected areas.
53 Note that, although this class generally works with IEEE
54 doubles, the calculation of connected areas happens in the
55 integer domain - it is generally expected that repaints can
56 only be divided at pixel boundaries, without causing visible
57 artifacts. Therefore, sprites that touch the same pixel (but
58 don't necessarily have the same floating point coordinates
59 there) will reside in a common sprite area and handled
60 together in the forEachSpriteArea functor call.
62 class CANVASTOOLS_DLLPUBLIC SpriteRedrawManager
: private ::boost::noncopyable
65 /** Data container for the connected components list
72 /** Create sprite info
75 Sprite this info represents (might be the NULL ref)
77 @param rTrueUpdateArea
78 True (un-rounded) update area this sprite has recorded
81 When false, this sprite is not a member of the change
82 record list. Thus, it only needs redraw if within the
83 update area of other, changed sprites.
87 SpriteInfo( const Sprite::Reference
& rRef
,
88 const ::basegfx::B2DRange
& rTrueUpdateArea
,
91 maTrueUpdateArea( rTrueUpdateArea
),
92 mbNeedsUpdate( bNeedsUpdate
),
97 /** Create sprite info, specify move type
100 Sprite this info represents (might be the NULL ref)
102 @param rTrueUpdateArea
103 True (un-rounded) update area this sprite has recorded
106 When false, this sprite is not a member of the change
107 record list. Thus, it only needs redraw if within the
108 update area of other, changed sprites.
111 When true, this sprite is _only_ moved, no other
116 SpriteInfo( const Sprite::Reference
& rRef
,
117 const ::basegfx::B2DRange
& rTrueUpdateArea
,
121 maTrueUpdateArea( rTrueUpdateArea
),
122 mbNeedsUpdate( bNeedsUpdate
),
123 mbIsPureMove( bIsPureMove
)
127 const Sprite::Reference
& getSprite() const { return mpSprite
; }
129 // #i61843# need to return by value here, to be used safely from bind
130 ::basegfx::B2DRange
getUpdateArea() const { return maTrueUpdateArea
; }
131 bool needsUpdate() const { return mbNeedsUpdate
; }
132 bool isPureMove() const { return mbIsPureMove
; }
135 Sprite::Reference mpSprite
;
136 ::basegfx::B2DRange maTrueUpdateArea
;
142 /** Helper struct for SpriteTracer template
144 This struct stores change information to a sprite's visual
145 appearance (move, content updated, and the like).
147 struct SpriteChangeRecord
149 typedef enum{ none
=0, move
, update
} ChangeType
;
151 SpriteChangeRecord() :
152 meChangeType( none
),
159 SpriteChangeRecord( const Sprite::Reference
& rSprite
,
160 const ::basegfx::B2DPoint
& rOldPos
,
161 const ::basegfx::B2DPoint
& rNewPos
,
162 const ::basegfx::B2DVector
& rSpriteSize
) :
163 meChangeType( move
),
164 mpAffectedSprite( rSprite
),
166 maUpdateArea( rNewPos
.getX(),
168 rNewPos
.getX() + rSpriteSize
.getX(),
169 rNewPos
.getY() + rSpriteSize
.getY() )
173 SpriteChangeRecord( const Sprite::Reference
& rSprite
,
174 const ::basegfx::B2DPoint
& rPos
,
175 const ::basegfx::B2DRange
& rUpdateArea
) :
176 meChangeType( update
),
177 mpAffectedSprite( rSprite
),
179 maUpdateArea( rUpdateArea
)
183 Sprite::Reference
getSprite() const { return mpAffectedSprite
; }
185 ChangeType meChangeType
;
186 Sprite::Reference mpAffectedSprite
;
187 ::basegfx::B2DPoint maOldPos
;
188 ::basegfx::B2DRange maUpdateArea
;
191 typedef ::std::vector
< SpriteChangeRecord
> VectorOfChangeRecords
;
192 typedef ::std::list
< Sprite::Reference
> ListOfSprites
;
193 typedef ::basegfx::B2DConnectedRanges
< SpriteInfo
> SpriteConnectedRanges
;
194 typedef SpriteConnectedRanges::ComponentType AreaComponent
;
195 typedef SpriteConnectedRanges::ConnectedComponents UpdateArea
;
196 typedef ::std::vector
< Sprite::Reference
> VectorOfSprites
;
198 SpriteRedrawManager();
200 /** Must be called when user of this object gets
201 disposed. Frees all internal references.
205 /** Functor, to be used from forEachSpriteArea
207 template< typename Functor
> struct AreaUpdateCaller
209 AreaUpdateCaller( Functor
& rFunc
,
210 const SpriteRedrawManager
& rManager
) :
212 mrManager( rManager
)
216 void operator()( const UpdateArea
& rUpdateArea
)
218 mrManager
.handleArea( mrFunc
, rUpdateArea
);
222 const SpriteRedrawManager
& mrManager
;
225 /** Call given functor for each sprite area that needs an
228 This method calls the given functor for each update area
229 (calculated from the sprite change records).
232 Must provide the following four methods:
234 void backgroundPaint( ::basegfx::B2DRange aUpdateRect );
235 void scrollUpdate( ::basegfx::B2DRange& o_rMoveStart,
236 ::basegfx::B2DRange& o_rMoveEnd,
237 UpdateArea aUpdateArea );
238 void opaqueUpdate( const ::basegfx::B2DRange& rTotalArea,
239 const ::std::vector< ::canvas::Sprite::Reference >& rSortedUpdateSprites );
240 void genericUpdate( const ::basegfx::B2DRange& rTotalArea,
241 const ::std::vector< ::canvas::Sprite::Reference >& rSortedUpdateSprites );
243 The backgroundPaint() method is called to simply repaint
244 background content, the scrollUpdate() method is used to
245 scroll a given area, and paint background in the uncovered
246 areas, the opaqueUpdate() method is called when a sprite
247 can be painted in the given area without taking background
248 content into account, and finally, genericUpdate() is
249 called for complex updates, where first the background and
250 then all sprites consecutively have to be repainted.
252 template< typename Functor
> void forEachSpriteArea( Functor
& rFunc
) const
254 SpriteConnectedRanges aUpdateAreas
;
256 setupUpdateAreas( aUpdateAreas
);
258 aUpdateAreas
.forEachAggregate(
259 AreaUpdateCaller
< Functor
>( rFunc
, *this ) );
262 /** Call given functor for each active sprite.
264 This method calls the given functor for each active
265 sprite, in the order of sprite priority.
268 Must provide a Functor::operator( Sprite::Reference& )
271 template< typename Functor
> void forEachSprite( const Functor
& rFunc
) const
273 ::std::for_each( maSprites
.begin(),
278 /// Clear sprite change records (typically directly after a screen update)
279 void clearChangeRecords();
281 // SpriteSurface interface, is delegated to e.g. from SpriteCanvas
282 void showSprite( const Sprite::Reference
& rSprite
);
283 void hideSprite( const Sprite::Reference
& rSprite
);
284 void moveSprite( const Sprite::Reference
& rSprite
,
285 const ::basegfx::B2DPoint
& rOldPos
,
286 const ::basegfx::B2DPoint
& rNewPos
,
287 const ::basegfx::B2DVector
& rSpriteSize
);
288 void updateSprite( const Sprite::Reference
& rSprite
,
289 const ::basegfx::B2DPoint
& rPos
,
290 const ::basegfx::B2DRange
& rUpdateArea
);
292 /** Internal, handles each distinct component for forEachAggregate()
294 The reason why this must be public is that it needs to be
295 accessible from the AreaUpdateCaller functor.
299 template< typename Functor
> void handleArea( Functor
& rFunc
,
300 const UpdateArea
& rUpdateArea
) const
302 // check whether this area contains changed sprites at all
303 // (if not, just ignore it)
304 if( areSpritesChanged( rUpdateArea
) )
306 // at least one of the sprites actually needs an
307 // update - process whole area.
309 // check whether this area could be handled special
310 // (background paint, direct update, scroll, etc.)
311 ::basegfx::B2DRange aMoveStart
;
312 ::basegfx::B2DRange aMoveEnd
;
313 if( rUpdateArea
.maComponentList
.empty() )
315 rFunc
.backgroundPaint( rUpdateArea
.maTotalBounds
);
319 // cache number of sprites in this area (it's a
320 // list, and both isAreaUpdateScroll() and
321 // isAreaUpdateOpaque() need it).
322 const ::std::size_t nNumSprites(
323 rUpdateArea
.maComponentList
.size() );
325 if( isAreaUpdateScroll( aMoveStart
,
330 rFunc
.scrollUpdate( aMoveStart
,
336 // potentially, more than a single sprite
337 // involved. Have to sort component lists for
339 VectorOfSprites aSortedUpdateSprites
;
340 SpriteConnectedRanges::ComponentListType::const_iterator
aCurr(
341 rUpdateArea
.maComponentList
.begin() );
342 const SpriteConnectedRanges::ComponentListType::const_iterator
aEnd(
343 rUpdateArea
.maComponentList
.end() );
344 while( aCurr
!= aEnd
)
346 const Sprite::Reference
& rSprite( aCurr
->second
.getSprite() );
348 aSortedUpdateSprites
.push_back( rSprite
);
353 ::std::sort( aSortedUpdateSprites
.begin(),
354 aSortedUpdateSprites
.end(),
357 if( isAreaUpdateOpaque( rUpdateArea
,
360 rFunc
.opaqueUpdate( rUpdateArea
.maTotalBounds
,
361 aSortedUpdateSprites
);
365 rFunc
.genericUpdate( rUpdateArea
.maTotalBounds
,
366 aSortedUpdateSprites
);
374 /** Central method of this class. Calculates the set of
375 disjunct components that need an update.
377 void setupUpdateAreas( SpriteConnectedRanges
& rUpdateAreas
) const;
379 bool areSpritesChanged( const UpdateArea
& rUpdateArea
) const;
381 bool isAreaUpdateNotOpaque( const ::basegfx::B2DRange
& rUpdateRect
,
382 const AreaComponent
& rComponent
) const;
384 bool isAreaUpdateOpaque( const UpdateArea
& rUpdateArea
,
385 ::std::size_t nNumSprites
) const;
387 /** Check whether given update area can be handled by a simple
391 Start rect of the move
394 End rect of the move. The content must be moved from start
398 Area to check for scroll update optimization
400 bool isAreaUpdateScroll( ::basegfx::B2DRange
& o_rMoveStart
,
401 ::basegfx::B2DRange
& o_rMoveEnd
,
402 const UpdateArea
& rUpdateArea
,
403 ::std::size_t nNumSprites
) const;
406 ListOfSprites maSprites
; // list of active
418 VectorOfChangeRecords maChangeRecords
; // vector of
427 #endif /* INCLUDED_CANVAS_SPRITEREDRAWMANAGER_HXX */
429 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */