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>
32 #include "base/sprite.hxx"
33 #include <canvas/canvastoolsdllapi.h>
35 /* Definition of SpriteRedrawManager class */
39 /** This class manages smooth SpriteCanvas updates
41 Use this class to handle the ::canvas::SpriteSurface methods,
42 that track and process sprite update events. Recorded update
43 events are later grouped by connected areas (i.e. all sprites
44 that somehow overlap over a rectangular area are grouped
45 together); the forEachSpriteArea() method calls the passed
46 functor for each of those connected areas.
48 Note that, although this class generally works with IEEE
49 doubles, the calculation of connected areas happens in the
50 integer domain - it is generally expected that repaints can
51 only be divided at pixel boundaries, without causing visible
52 artifacts. Therefore, sprites that touch the same pixel (but
53 don't necessarily have the same floating point coordinates
54 there) will reside in a common sprite area and handled
55 together in the forEachSpriteArea functor call.
57 class CANVASTOOLS_DLLPUBLIC SpriteRedrawManager
60 /** Data container for the connected components list
65 /** Create sprite info
68 Sprite this info represents (might be the NULL ref)
70 @param rTrueUpdateArea
71 True (un-rounded) update area this sprite has recorded
74 When false, this sprite is not a member of the change
75 record list. Thus, it only needs redraw if within the
76 update area of other, changed sprites.
80 SpriteInfo( Sprite::Reference aRef
,
81 const ::basegfx::B2DRange
& rTrueUpdateArea
,
83 mpSprite(std::move( aRef
)),
84 maTrueUpdateArea( rTrueUpdateArea
),
85 mbNeedsUpdate( bNeedsUpdate
),
90 /** Create sprite info, specify move type
93 Sprite this info represents (might be the NULL ref)
95 @param rTrueUpdateArea
96 True (un-rounded) update area this sprite has recorded
99 When false, this sprite is not a member of the change
100 record list. Thus, it only needs redraw if within the
101 update area of other, changed sprites.
104 When true, this sprite is _only_ moved, no other
109 SpriteInfo( Sprite::Reference aRef
,
110 const ::basegfx::B2DRange
& rTrueUpdateArea
,
113 mpSprite(std::move( aRef
)),
114 maTrueUpdateArea( rTrueUpdateArea
),
115 mbNeedsUpdate( bNeedsUpdate
),
116 mbIsPureMove( bIsPureMove
)
120 const Sprite::Reference
& getSprite() const { return mpSprite
; }
122 // #i61843# need to return by value here, to be used safely from bind
123 const ::basegfx::B2DRange
& getUpdateArea() const { return maTrueUpdateArea
; }
124 bool needsUpdate() const { return mbNeedsUpdate
; }
125 bool isPureMove() const { return mbIsPureMove
; }
128 Sprite::Reference mpSprite
;
129 ::basegfx::B2DRange maTrueUpdateArea
;
135 /** Helper struct for SpriteTracer template
137 This struct stores change information to a sprite's visual
138 appearance (move, content updated, and the like).
140 struct SpriteChangeRecord
142 enum class ChangeType
{ move
, update
};
144 SpriteChangeRecord( Sprite::Reference rSprite
,
145 const ::basegfx::B2DPoint
& rOldPos
,
146 const ::basegfx::B2DPoint
& rNewPos
,
147 const ::basegfx::B2DVector
& rSpriteSize
) :
148 meChangeType( ChangeType::move
),
149 mpAffectedSprite(std::move( rSprite
)),
151 maUpdateArea( rNewPos
.getX(),
153 rNewPos
.getX() + rSpriteSize
.getX(),
154 rNewPos
.getY() + rSpriteSize
.getY() )
158 SpriteChangeRecord( Sprite::Reference rSprite
,
159 const ::basegfx::B2DPoint
& rPos
,
160 const ::basegfx::B2DRange
& rUpdateArea
) :
161 meChangeType( ChangeType::update
),
162 mpAffectedSprite(std::move( rSprite
)),
164 maUpdateArea( rUpdateArea
)
168 const Sprite::Reference
& getSprite() const { return mpAffectedSprite
; }
170 ChangeType meChangeType
;
171 Sprite::Reference mpAffectedSprite
;
172 ::basegfx::B2DPoint maOldPos
;
173 ::basegfx::B2DRange maUpdateArea
;
176 typedef ::std::vector
< SpriteChangeRecord
> VectorOfChangeRecords
;
177 typedef ::basegfx::B2DConnectedRanges
< SpriteInfo
> SpriteConnectedRanges
;
178 typedef SpriteConnectedRanges::ComponentType AreaComponent
;
179 typedef SpriteConnectedRanges::ConnectedComponents UpdateArea
;
180 typedef ::std::vector
< Sprite::Reference
> VectorOfSprites
;
182 SpriteRedrawManager();
183 SpriteRedrawManager(const SpriteRedrawManager
&) = delete;
184 SpriteRedrawManager
& operator=( const SpriteRedrawManager
& ) = delete;
186 /** Must be called when user of this object gets
187 disposed. Frees all internal references.
191 /** Functor, to be used from forEachSpriteArea
193 template< typename Functor
> struct AreaUpdateCaller
195 AreaUpdateCaller( Functor
& rFunc
,
196 const SpriteRedrawManager
& rManager
) :
198 mrManager( rManager
)
202 void operator()( const UpdateArea
& rUpdateArea
)
204 mrManager
.handleArea( mrFunc
, rUpdateArea
);
208 const SpriteRedrawManager
& mrManager
;
211 /** Call given functor for each sprite area that needs an
214 This method calls the given functor for each update area
215 (calculated from the sprite change records).
218 Must provide the following four methods:
220 void backgroundPaint( ::basegfx::B2DRange aUpdateRect );
221 void scrollUpdate( ::basegfx::B2DRange& o_rMoveStart,
222 ::basegfx::B2DRange& o_rMoveEnd,
223 UpdateArea aUpdateArea );
224 void opaqueUpdate( const ::basegfx::B2DRange& rTotalArea,
225 const ::std::vector< ::canvas::Sprite::Reference >& rSortedUpdateSprites );
226 void genericUpdate( const ::basegfx::B2DRange& rTotalArea,
227 const ::std::vector< ::canvas::Sprite::Reference >& rSortedUpdateSprites );
229 The backgroundPaint() method is called to simply repaint
230 background content, the scrollUpdate() method is used to
231 scroll a given area, and paint background in the uncovered
232 areas, the opaqueUpdate() method is called when a sprite
233 can be painted in the given area without taking background
234 content into account, and finally, genericUpdate() is
235 called for complex updates, where first the background and
236 then all sprites consecutively have to be repainted.
238 template< typename Functor
> void forEachSpriteArea( Functor
& rFunc
) const
240 SpriteConnectedRanges aUpdateAreas
;
242 setupUpdateAreas( aUpdateAreas
);
244 aUpdateAreas
.forEachAggregate(
245 AreaUpdateCaller
< Functor
>( rFunc
, *this ) );
248 /** Call given functor for each active sprite.
250 This method calls the given functor for each active
251 sprite, in the order of sprite priority.
254 Must provide a Functor::operator( Sprite::Reference& )
257 template< typename Functor
> void forEachSprite( const Functor
& rFunc
) const
259 ::std::for_each( maSprites
.begin(),
264 /// Clear sprite change records (typically directly after a screen update)
265 void clearChangeRecords();
267 // SpriteSurface interface, is delegated to e.g. from SpriteCanvas
268 void showSprite( const Sprite::Reference
& rSprite
);
269 void hideSprite( const Sprite::Reference
& rSprite
);
270 void moveSprite( const Sprite::Reference
& rSprite
,
271 const ::basegfx::B2DPoint
& rOldPos
,
272 const ::basegfx::B2DPoint
& rNewPos
,
273 const ::basegfx::B2DVector
& rSpriteSize
);
274 void updateSprite( const Sprite::Reference
& rSprite
,
275 const ::basegfx::B2DPoint
& rPos
,
276 const ::basegfx::B2DRange
& rUpdateArea
);
278 /** Internal, handles each distinct component for forEachAggregate()
280 The reason why this must be public is that it needs to be
281 accessible from the AreaUpdateCaller functor.
285 template< typename Functor
> void handleArea( Functor
& rFunc
,
286 const UpdateArea
& rUpdateArea
) const
288 // check whether this area contains changed sprites at all
289 // (if not, just ignore it)
290 if( !areSpritesChanged( rUpdateArea
) )
293 // at least one of the sprites actually needs an
294 // update - process whole area.
296 // check whether this area could be handled special
297 // (background paint, direct update, scroll, etc.)
298 ::basegfx::B2DRange aMoveStart
;
299 ::basegfx::B2DRange aMoveEnd
;
300 if( rUpdateArea
.maComponentList
.empty() )
302 rFunc
.backgroundPaint( rUpdateArea
.maTotalBounds
);
306 // cache number of sprites in this area (it's a
307 // list, and both isAreaUpdateScroll() and
308 // isAreaUpdateOpaque() need it).
309 const ::std::size_t nNumSprites(
310 rUpdateArea
.maComponentList
.size() );
312 if( isAreaUpdateScroll( aMoveStart
,
317 rFunc
.scrollUpdate( aMoveStart
,
323 // potentially, more than a single sprite
324 // involved. Have to sort component lists for
326 VectorOfSprites aSortedUpdateSprites
;
327 for (auto const& elem
: rUpdateArea
.maComponentList
)
329 const Sprite::Reference
& rSprite( elem
.second
.getSprite() );
331 aSortedUpdateSprites
.push_back( rSprite
);
334 ::std::sort( aSortedUpdateSprites
.begin(),
335 aSortedUpdateSprites
.end(),
338 if( isAreaUpdateOpaque( rUpdateArea
,
341 rFunc
.opaqueUpdate( rUpdateArea
.maTotalBounds
,
342 aSortedUpdateSprites
);
346 rFunc
.genericUpdate( rUpdateArea
.maTotalBounds
,
347 aSortedUpdateSprites
);
354 /** Central method of this class. Calculates the set of
355 disjunct components that need an update.
357 void setupUpdateAreas( SpriteConnectedRanges
& rUpdateAreas
) const;
359 bool areSpritesChanged( const UpdateArea
& rUpdateArea
) const;
361 bool isAreaUpdateNotOpaque( const ::basegfx::B2DRectangle
& rUpdateRect
,
362 const AreaComponent
& rComponent
) const;
364 bool isAreaUpdateOpaque( const UpdateArea
& rUpdateArea
,
365 ::std::size_t nNumSprites
) const;
367 /** Check whether given update area can be handled by a simple
371 Start rect of the move
374 End rect of the move. The content must be moved from start
378 Area to check for scroll update optimization
380 bool isAreaUpdateScroll( ::basegfx::B2DRectangle
& o_rMoveStart
,
381 ::basegfx::B2DRectangle
& o_rMoveEnd
,
382 const UpdateArea
& rUpdateArea
,
383 ::std::size_t nNumSprites
) const;
386 VectorOfSprites maSprites
; // list of active
398 VectorOfChangeRecords maChangeRecords
; // vector of
407 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */