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 <canvas/canvastoolsdllapi.h>
37 /* Definition of SpriteRedrawManager class */
41 /** This class manages smooth SpriteCanvas updates
43 Use this class to handle the ::canvas::SpriteSurface methods,
44 that track and process sprite update events. Recorded update
45 events are later grouped by connected areas (i.e. all sprites
46 that somehow overlap over a rectangular area are grouped
47 together); the forEachSpriteArea() method calls the passed
48 functor for each of those connected areas.
50 Note that, although this class generally works with IEEE
51 doubles, the calculation of connected areas happens in the
52 integer domain - it is generally expected that repaints can
53 only be divided at pixel boundaries, without causing visible
54 artifacts. Therefore, sprites that touch the same pixel (but
55 don't necessarily have the same floating point coordinates
56 there) will reside in a common sprite area and handled
57 together in the forEachSpriteArea functor call.
59 class CANVASTOOLS_DLLPUBLIC SpriteRedrawManager
62 /** Data container for the connected components list
69 /** Create sprite info
72 Sprite this info represents (might be the NULL ref)
74 @param rTrueUpdateArea
75 True (un-rounded) update area this sprite has recorded
78 When false, this sprite is not a member of the change
79 record list. Thus, it only needs redraw if within the
80 update area of other, changed sprites.
84 SpriteInfo( const Sprite::Reference
& rRef
,
85 const ::basegfx::B2DRange
& rTrueUpdateArea
,
88 maTrueUpdateArea( rTrueUpdateArea
),
89 mbNeedsUpdate( bNeedsUpdate
),
94 /** Create sprite info, specify move type
97 Sprite this info represents (might be the NULL ref)
99 @param rTrueUpdateArea
100 True (un-rounded) update area this sprite has recorded
103 When false, this sprite is not a member of the change
104 record list. Thus, it only needs redraw if within the
105 update area of other, changed sprites.
108 When true, this sprite is _only_ moved, no other
113 SpriteInfo( const Sprite::Reference
& rRef
,
114 const ::basegfx::B2DRange
& rTrueUpdateArea
,
118 maTrueUpdateArea( rTrueUpdateArea
),
119 mbNeedsUpdate( bNeedsUpdate
),
120 mbIsPureMove( bIsPureMove
)
124 const Sprite::Reference
& getSprite() const { return mpSprite
; }
126 // #i61843# need to return by value here, to be used safely from bind
127 const ::basegfx::B2DRange
& getUpdateArea() const { return maTrueUpdateArea
; }
128 bool needsUpdate() const { return mbNeedsUpdate
; }
129 bool isPureMove() const { return mbIsPureMove
; }
132 Sprite::Reference mpSprite
;
133 ::basegfx::B2DRange maTrueUpdateArea
;
139 /** Helper struct for SpriteTracer template
141 This struct stores change information to a sprite's visual
142 appearance (move, content updated, and the like).
144 struct SpriteChangeRecord
146 enum class ChangeType
{ none
=0, move
, update
};
148 SpriteChangeRecord() :
149 meChangeType( ChangeType::none
),
156 SpriteChangeRecord( const Sprite::Reference
& rSprite
,
157 const ::basegfx::B2DPoint
& rOldPos
,
158 const ::basegfx::B2DPoint
& rNewPos
,
159 const ::basegfx::B2DVector
& rSpriteSize
) :
160 meChangeType( ChangeType::move
),
161 mpAffectedSprite( rSprite
),
163 maUpdateArea( rNewPos
.getX(),
165 rNewPos
.getX() + rSpriteSize
.getX(),
166 rNewPos
.getY() + rSpriteSize
.getY() )
170 SpriteChangeRecord( const Sprite::Reference
& rSprite
,
171 const ::basegfx::B2DPoint
& rPos
,
172 const ::basegfx::B2DRange
& rUpdateArea
) :
173 meChangeType( ChangeType::update
),
174 mpAffectedSprite( rSprite
),
176 maUpdateArea( rUpdateArea
)
180 const Sprite::Reference
& getSprite() const { return mpAffectedSprite
; }
182 ChangeType meChangeType
;
183 Sprite::Reference mpAffectedSprite
;
184 ::basegfx::B2DPoint maOldPos
;
185 ::basegfx::B2DRange maUpdateArea
;
188 typedef ::std::vector
< SpriteChangeRecord
> VectorOfChangeRecords
;
189 typedef ::std::list
< Sprite::Reference
> ListOfSprites
;
190 typedef ::basegfx::B2DConnectedRanges
< SpriteInfo
> SpriteConnectedRanges
;
191 typedef SpriteConnectedRanges::ComponentType AreaComponent
;
192 typedef SpriteConnectedRanges::ConnectedComponents UpdateArea
;
193 typedef ::std::vector
< Sprite::Reference
> VectorOfSprites
;
195 SpriteRedrawManager();
196 SpriteRedrawManager(const SpriteRedrawManager
&) = delete;
197 SpriteRedrawManager
& operator=( const SpriteRedrawManager
& ) = delete;
199 /** Must be called when user of this object gets
200 disposed. Frees all internal references.
204 /** Functor, to be used from forEachSpriteArea
206 template< typename Functor
> struct AreaUpdateCaller
208 AreaUpdateCaller( Functor
& rFunc
,
209 const SpriteRedrawManager
& rManager
) :
211 mrManager( rManager
)
215 void operator()( const UpdateArea
& rUpdateArea
)
217 mrManager
.handleArea( mrFunc
, rUpdateArea
);
221 const SpriteRedrawManager
& mrManager
;
224 /** Call given functor for each sprite area that needs an
227 This method calls the given functor for each update area
228 (calculated from the sprite change records).
231 Must provide the following four methods:
233 void backgroundPaint( ::basegfx::B2DRange aUpdateRect );
234 void scrollUpdate( ::basegfx::B2DRange& o_rMoveStart,
235 ::basegfx::B2DRange& o_rMoveEnd,
236 UpdateArea aUpdateArea );
237 void opaqueUpdate( const ::basegfx::B2DRange& rTotalArea,
238 const ::std::vector< ::canvas::Sprite::Reference >& rSortedUpdateSprites );
239 void genericUpdate( const ::basegfx::B2DRange& rTotalArea,
240 const ::std::vector< ::canvas::Sprite::Reference >& rSortedUpdateSprites );
242 The backgroundPaint() method is called to simply repaint
243 background content, the scrollUpdate() method is used to
244 scroll a given area, and paint background in the uncovered
245 areas, the opaqueUpdate() method is called when a sprite
246 can be painted in the given area without taking background
247 content into account, and finally, genericUpdate() is
248 called for complex updates, where first the background and
249 then all sprites consecutively have to be repainted.
251 template< typename Functor
> void forEachSpriteArea( Functor
& rFunc
) const
253 SpriteConnectedRanges aUpdateAreas
;
255 setupUpdateAreas( aUpdateAreas
);
257 aUpdateAreas
.forEachAggregate(
258 AreaUpdateCaller
< Functor
>( rFunc
, *this ) );
261 /** Call given functor for each active sprite.
263 This method calls the given functor for each active
264 sprite, in the order of sprite priority.
267 Must provide a Functor::operator( Sprite::Reference& )
270 template< typename Functor
> void forEachSprite( const Functor
& rFunc
) const
272 ::std::for_each( maSprites
.begin(),
277 /// Clear sprite change records (typically directly after a screen update)
278 void clearChangeRecords();
280 // SpriteSurface interface, is delegated to e.g. from SpriteCanvas
281 void showSprite( const Sprite::Reference
& rSprite
);
282 void hideSprite( const Sprite::Reference
& rSprite
);
283 void moveSprite( const Sprite::Reference
& rSprite
,
284 const ::basegfx::B2DPoint
& rOldPos
,
285 const ::basegfx::B2DPoint
& rNewPos
,
286 const ::basegfx::B2DVector
& rSpriteSize
);
287 void updateSprite( const Sprite::Reference
& rSprite
,
288 const ::basegfx::B2DPoint
& rPos
,
289 const ::basegfx::B2DRange
& rUpdateArea
);
291 /** Internal, handles each distinct component for forEachAggregate()
293 The reason why this must be public is that it needs to be
294 accessible from the AreaUpdateCaller functor.
298 template< typename Functor
> void handleArea( Functor
& rFunc
,
299 const UpdateArea
& rUpdateArea
) const
301 // check whether this area contains changed sprites at all
302 // (if not, just ignore it)
303 if( areSpritesChanged( rUpdateArea
) )
305 // at least one of the sprites actually needs an
306 // update - process whole area.
308 // check whether this area could be handled special
309 // (background paint, direct update, scroll, etc.)
310 ::basegfx::B2DRange aMoveStart
;
311 ::basegfx::B2DRange aMoveEnd
;
312 if( rUpdateArea
.maComponentList
.empty() )
314 rFunc
.backgroundPaint( rUpdateArea
.maTotalBounds
);
318 // cache number of sprites in this area (it's a
319 // list, and both isAreaUpdateScroll() and
320 // isAreaUpdateOpaque() need it).
321 const ::std::size_t nNumSprites(
322 rUpdateArea
.maComponentList
.size() );
324 if( isAreaUpdateScroll( aMoveStart
,
329 rFunc
.scrollUpdate( aMoveStart
,
335 // potentially, more than a single sprite
336 // involved. Have to sort component lists for
338 VectorOfSprites aSortedUpdateSprites
;
339 SpriteConnectedRanges::ComponentListType::const_iterator
aCurr(
340 rUpdateArea
.maComponentList
.begin() );
341 const SpriteConnectedRanges::ComponentListType::const_iterator
aEnd(
342 rUpdateArea
.maComponentList
.end() );
343 while( aCurr
!= aEnd
)
345 const Sprite::Reference
& rSprite( aCurr
->second
.getSprite() );
347 aSortedUpdateSprites
.push_back( rSprite
);
352 ::std::sort( aSortedUpdateSprites
.begin(),
353 aSortedUpdateSprites
.end(),
356 if( isAreaUpdateOpaque( rUpdateArea
,
359 rFunc
.opaqueUpdate( rUpdateArea
.maTotalBounds
,
360 aSortedUpdateSprites
);
364 rFunc
.genericUpdate( rUpdateArea
.maTotalBounds
,
365 aSortedUpdateSprites
);
373 /** Central method of this class. Calculates the set of
374 disjunct components that need an update.
376 void setupUpdateAreas( SpriteConnectedRanges
& rUpdateAreas
) const;
378 bool areSpritesChanged( const UpdateArea
& rUpdateArea
) const;
380 bool isAreaUpdateNotOpaque( const ::basegfx::B2DRange
& rUpdateRect
,
381 const AreaComponent
& rComponent
) const;
383 bool isAreaUpdateOpaque( const UpdateArea
& rUpdateArea
,
384 ::std::size_t nNumSprites
) const;
386 /** Check whether given update area can be handled by a simple
390 Start rect of the move
393 End rect of the move. The content must be moved from start
397 Area to check for scroll update optimization
399 bool isAreaUpdateScroll( ::basegfx::B2DRange
& o_rMoveStart
,
400 ::basegfx::B2DRange
& o_rMoveEnd
,
401 const UpdateArea
& rUpdateArea
,
402 ::std::size_t nNumSprites
) const;
405 ListOfSprites maSprites
; // list of active
417 VectorOfChangeRecords maChangeRecords
; // vector of
426 #endif /* INCLUDED_CANVAS_SPRITEREDRAWMANAGER_HXX */
428 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */