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 .
22 #include <basegfx/range/b2dconnectedranges.hxx>
23 #include <basegfx/point/b2dpoint.hxx>
24 #include <basegfx/vector/b2dvector.hxx>
25 #include <basegfx/range/b2drange.hxx>
26 #include <basegfx/range/b2drectangle.hxx>
31 #include "base/sprite.hxx"
32 #include <canvas/canvastoolsdllapi.h>
34 /* Definition of SpriteRedrawManager class */
38 /** This class manages smooth SpriteCanvas updates
40 Use this class to handle the ::canvas::SpriteSurface methods,
41 that track and process sprite update events. Recorded update
42 events are later grouped by connected areas (i.e. all sprites
43 that somehow overlap over a rectangular area are grouped
44 together); the forEachSpriteArea() method calls the passed
45 functor for each of those connected areas.
47 Note that, although this class generally works with IEEE
48 doubles, the calculation of connected areas happens in the
49 integer domain - it is generally expected that repaints can
50 only be divided at pixel boundaries, without causing visible
51 artifacts. Therefore, sprites that touch the same pixel (but
52 don't necessarily have the same floating point coordinates
53 there) will reside in a common sprite area and handled
54 together in the forEachSpriteArea functor call.
56 class CANVASTOOLS_DLLPUBLIC SpriteRedrawManager
59 /** Data container for the connected components list
64 /** Create sprite info
67 Sprite this info represents (might be the NULL ref)
69 @param rTrueUpdateArea
70 True (un-rounded) update area this sprite has recorded
73 When false, this sprite is not a member of the change
74 record list. Thus, it only needs redraw if within the
75 update area of other, changed sprites.
79 SpriteInfo( const Sprite::Reference
& rRef
,
80 const ::basegfx::B2DRange
& rTrueUpdateArea
,
83 maTrueUpdateArea( rTrueUpdateArea
),
84 mbNeedsUpdate( bNeedsUpdate
),
89 /** Create sprite info, specify move type
92 Sprite this info represents (might be the NULL ref)
94 @param rTrueUpdateArea
95 True (un-rounded) update area this sprite has recorded
98 When false, this sprite is not a member of the change
99 record list. Thus, it only needs redraw if within the
100 update area of other, changed sprites.
103 When true, this sprite is _only_ moved, no other
108 SpriteInfo( const Sprite::Reference
& rRef
,
109 const ::basegfx::B2DRange
& rTrueUpdateArea
,
113 maTrueUpdateArea( rTrueUpdateArea
),
114 mbNeedsUpdate( bNeedsUpdate
),
115 mbIsPureMove( bIsPureMove
)
119 const Sprite::Reference
& getSprite() const { return mpSprite
; }
121 // #i61843# need to return by value here, to be used safely from bind
122 const ::basegfx::B2DRange
& getUpdateArea() const { return maTrueUpdateArea
; }
123 bool needsUpdate() const { return mbNeedsUpdate
; }
124 bool isPureMove() const { return mbIsPureMove
; }
127 Sprite::Reference mpSprite
;
128 ::basegfx::B2DRange maTrueUpdateArea
;
134 /** Helper struct for SpriteTracer template
136 This struct stores change information to a sprite's visual
137 appearance (move, content updated, and the like).
139 struct SpriteChangeRecord
141 enum class ChangeType
{ move
, update
};
143 SpriteChangeRecord( const Sprite::Reference
& rSprite
,
144 const ::basegfx::B2DPoint
& rOldPos
,
145 const ::basegfx::B2DPoint
& rNewPos
,
146 const ::basegfx::B2DVector
& rSpriteSize
) :
147 meChangeType( ChangeType::move
),
148 mpAffectedSprite( rSprite
),
150 maUpdateArea( rNewPos
.getX(),
152 rNewPos
.getX() + rSpriteSize
.getX(),
153 rNewPos
.getY() + rSpriteSize
.getY() )
157 SpriteChangeRecord( const Sprite::Reference
& rSprite
,
158 const ::basegfx::B2DPoint
& rPos
,
159 const ::basegfx::B2DRange
& rUpdateArea
) :
160 meChangeType( ChangeType::update
),
161 mpAffectedSprite( rSprite
),
163 maUpdateArea( rUpdateArea
)
167 const Sprite::Reference
& getSprite() const { return mpAffectedSprite
; }
169 ChangeType meChangeType
;
170 Sprite::Reference mpAffectedSprite
;
171 ::basegfx::B2DPoint maOldPos
;
172 ::basegfx::B2DRange maUpdateArea
;
175 typedef ::std::vector
< SpriteChangeRecord
> VectorOfChangeRecords
;
176 typedef ::basegfx::B2DConnectedRanges
< SpriteInfo
> SpriteConnectedRanges
;
177 typedef SpriteConnectedRanges::ComponentType AreaComponent
;
178 typedef SpriteConnectedRanges::ConnectedComponents UpdateArea
;
179 typedef ::std::vector
< Sprite::Reference
> VectorOfSprites
;
181 SpriteRedrawManager();
182 SpriteRedrawManager(const SpriteRedrawManager
&) = delete;
183 SpriteRedrawManager
& operator=( const SpriteRedrawManager
& ) = delete;
185 /** Must be called when user of this object gets
186 disposed. Frees all internal references.
190 /** Functor, to be used from forEachSpriteArea
192 template< typename Functor
> struct AreaUpdateCaller
194 AreaUpdateCaller( Functor
& rFunc
,
195 const SpriteRedrawManager
& rManager
) :
197 mrManager( rManager
)
201 void operator()( const UpdateArea
& rUpdateArea
)
203 mrManager
.handleArea( mrFunc
, rUpdateArea
);
207 const SpriteRedrawManager
& mrManager
;
210 /** Call given functor for each sprite area that needs an
213 This method calls the given functor for each update area
214 (calculated from the sprite change records).
217 Must provide the following four methods:
219 void backgroundPaint( ::basegfx::B2DRange aUpdateRect );
220 void scrollUpdate( ::basegfx::B2DRange& o_rMoveStart,
221 ::basegfx::B2DRange& o_rMoveEnd,
222 UpdateArea aUpdateArea );
223 void opaqueUpdate( const ::basegfx::B2DRange& rTotalArea,
224 const ::std::vector< ::canvas::Sprite::Reference >& rSortedUpdateSprites );
225 void genericUpdate( const ::basegfx::B2DRange& rTotalArea,
226 const ::std::vector< ::canvas::Sprite::Reference >& rSortedUpdateSprites );
228 The backgroundPaint() method is called to simply repaint
229 background content, the scrollUpdate() method is used to
230 scroll a given area, and paint background in the uncovered
231 areas, the opaqueUpdate() method is called when a sprite
232 can be painted in the given area without taking background
233 content into account, and finally, genericUpdate() is
234 called for complex updates, where first the background and
235 then all sprites consecutively have to be repainted.
237 template< typename Functor
> void forEachSpriteArea( Functor
& rFunc
) const
239 SpriteConnectedRanges aUpdateAreas
;
241 setupUpdateAreas( aUpdateAreas
);
243 aUpdateAreas
.forEachAggregate(
244 AreaUpdateCaller
< Functor
>( rFunc
, *this ) );
247 /** Call given functor for each active sprite.
249 This method calls the given functor for each active
250 sprite, in the order of sprite priority.
253 Must provide a Functor::operator( Sprite::Reference& )
256 template< typename Functor
> void forEachSprite( const Functor
& rFunc
) const
258 ::std::for_each( maSprites
.begin(),
263 /// Clear sprite change records (typically directly after a screen update)
264 void clearChangeRecords();
266 // SpriteSurface interface, is delegated to e.g. from SpriteCanvas
267 void showSprite( const Sprite::Reference
& rSprite
);
268 void hideSprite( const Sprite::Reference
& rSprite
);
269 void moveSprite( const Sprite::Reference
& rSprite
,
270 const ::basegfx::B2DPoint
& rOldPos
,
271 const ::basegfx::B2DPoint
& rNewPos
,
272 const ::basegfx::B2DVector
& rSpriteSize
);
273 void updateSprite( const Sprite::Reference
& rSprite
,
274 const ::basegfx::B2DPoint
& rPos
,
275 const ::basegfx::B2DRange
& rUpdateArea
);
277 /** Internal, handles each distinct component for forEachAggregate()
279 The reason why this must be public is that it needs to be
280 accessible from the AreaUpdateCaller functor.
284 template< typename Functor
> void handleArea( Functor
& rFunc
,
285 const UpdateArea
& rUpdateArea
) const
287 // check whether this area contains changed sprites at all
288 // (if not, just ignore it)
289 if( areSpritesChanged( rUpdateArea
) )
291 // at least one of the sprites actually needs an
292 // update - process whole area.
294 // check whether this area could be handled special
295 // (background paint, direct update, scroll, etc.)
296 ::basegfx::B2DRange aMoveStart
;
297 ::basegfx::B2DRange aMoveEnd
;
298 if( rUpdateArea
.maComponentList
.empty() )
300 rFunc
.backgroundPaint( rUpdateArea
.maTotalBounds
);
304 // cache number of sprites in this area (it's a
305 // list, and both isAreaUpdateScroll() and
306 // isAreaUpdateOpaque() need it).
307 const ::std::size_t nNumSprites(
308 rUpdateArea
.maComponentList
.size() );
310 if( isAreaUpdateScroll( aMoveStart
,
315 rFunc
.scrollUpdate( aMoveStart
,
321 // potentially, more than a single sprite
322 // involved. Have to sort component lists for
324 VectorOfSprites aSortedUpdateSprites
;
325 for (auto const& elem
: rUpdateArea
.maComponentList
)
327 const Sprite::Reference
& rSprite( elem
.second
.getSprite() );
329 aSortedUpdateSprites
.push_back( rSprite
);
332 ::std::sort( aSortedUpdateSprites
.begin(),
333 aSortedUpdateSprites
.end(),
336 if( isAreaUpdateOpaque( rUpdateArea
,
339 rFunc
.opaqueUpdate( rUpdateArea
.maTotalBounds
,
340 aSortedUpdateSprites
);
344 rFunc
.genericUpdate( rUpdateArea
.maTotalBounds
,
345 aSortedUpdateSprites
);
353 /** Central method of this class. Calculates the set of
354 disjunct components that need an update.
356 void setupUpdateAreas( SpriteConnectedRanges
& rUpdateAreas
) const;
358 bool areSpritesChanged( const UpdateArea
& rUpdateArea
) const;
360 bool isAreaUpdateNotOpaque( const ::basegfx::B2DRectangle
& rUpdateRect
,
361 const AreaComponent
& rComponent
) const;
363 bool isAreaUpdateOpaque( const UpdateArea
& rUpdateArea
,
364 ::std::size_t nNumSprites
) const;
366 /** Check whether given update area can be handled by a simple
370 Start rect of the move
373 End rect of the move. The content must be moved from start
377 Area to check for scroll update optimization
379 bool isAreaUpdateScroll( ::basegfx::B2DRectangle
& o_rMoveStart
,
380 ::basegfx::B2DRectangle
& o_rMoveEnd
,
381 const UpdateArea
& rUpdateArea
,
382 ::std::size_t nNumSprites
) const;
385 VectorOfSprites maSprites
; // list of active
397 VectorOfChangeRecords maChangeRecords
; // vector of
406 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */