Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : : #ifndef INCLUDED_CANVAS_SPRITEREDRAWMANAGER_HXX
30 : : #define INCLUDED_CANVAS_SPRITEREDRAWMANAGER_HXX
31 : :
32 : : #include <basegfx/range/b2dconnectedranges.hxx>
33 : : #include <basegfx/point/b2dpoint.hxx>
34 : : #include <basegfx/vector/b2dvector.hxx>
35 : : #include <basegfx/range/b2drange.hxx>
36 : : #include <basegfx/range/b2irange.hxx>
37 : : #include <basegfx/matrix/b2dhommatrix.hxx>
38 : : #include <canvas/base/spritesurface.hxx>
39 : :
40 : : #include <list>
41 : : #include <vector>
42 : : #include <algorithm>
43 : :
44 : : #include <boost/utility.hpp>
45 : : #include <boost/bind.hpp>
46 : :
47 : : #include <canvas/canvastoolsdllapi.h>
48 : :
49 : : /* Definition of SpriteRedrawManager class */
50 : :
51 : : namespace canvas
52 : : {
53 : : /** This class manages smooth SpriteCanvas updates
54 : :
55 : : Use this class to handle the ::canvas::SpriteSurface methods,
56 : : that track and process sprite update events. Recorded update
57 : : events are later grouped by connected areas (i.e. all sprites
58 : : that somehow overlap over a rectangular area are grouped
59 : : together); the forEachSpriteArea() method calls the passed
60 : : functor for each of those connected areas.
61 : :
62 : : Note that, although this class generally works with IEEE
63 : : doubles, the calculation of connected areas happens in the
64 : : integer domain - it is generally expected that repaints can
65 : : only be divided at pixel boundaries, without causing visible
66 : : artifacts. Therefore, sprites that touch the same pixel (but
67 : : don't necessarily have the same floating point coordinates
68 : : there) will reside in a common sprite area and handled
69 : : together in the forEachSpriteArea functor call.
70 : : */
71 : 0 : class CANVASTOOLS_DLLPUBLIC SpriteRedrawManager : private ::boost::noncopyable
72 : : {
73 : : public:
74 : : /** Data container for the connected components list
75 : : */
76 : 0 : class SpriteInfo
77 : : {
78 : : public:
79 : 0 : ~SpriteInfo() {}
80 : :
81 : : /** Create sprite info
82 : :
83 : : @param rRef
84 : : Sprite this info represents (might be the NULL ref)
85 : :
86 : : @param rTrueUpdateArea
87 : : True (un-rounded) update area this sprite has recorded
88 : :
89 : : @param bNeedsUpdate
90 : : When false, this sprite is not a member of the change
91 : : record list. Thus, it only needs redraw if within the
92 : : update area of other, changed sprites.
93 : :
94 : : @internal
95 : : */
96 : 0 : SpriteInfo( const Sprite::Reference& rRef,
97 : : const ::basegfx::B2DRange& rTrueUpdateArea,
98 : : bool bNeedsUpdate ) :
99 : : mpSprite( rRef ),
100 : : maTrueUpdateArea( rTrueUpdateArea ),
101 : : mbNeedsUpdate( bNeedsUpdate ),
102 : 0 : mbIsPureMove( false )
103 : : {
104 : 0 : }
105 : :
106 : : /** Create sprite info, specify move type
107 : :
108 : : @param rRef
109 : : Sprite this info represents (might be the NULL ref)
110 : :
111 : : @param rTrueUpdateArea
112 : : True (un-rounded) update area this sprite has recorded
113 : :
114 : : @param bNeedsUpdate
115 : : When false, this sprite is not a member of the change
116 : : record list. Thus, it only needs redraw if within the
117 : : update area of other, changed sprites.
118 : :
119 : : @param bIsPureMove
120 : : When true, this sprite is _only_ moved, no other
121 : : changes happened.
122 : :
123 : : @internal
124 : : */
125 : 0 : SpriteInfo( const Sprite::Reference& rRef,
126 : : const ::basegfx::B2DRange& rTrueUpdateArea,
127 : : bool bNeedsUpdate,
128 : : bool bIsPureMove ) :
129 : : mpSprite( rRef ),
130 : : maTrueUpdateArea( rTrueUpdateArea ),
131 : : mbNeedsUpdate( bNeedsUpdate ),
132 : 0 : mbIsPureMove( bIsPureMove )
133 : : {
134 : 0 : }
135 : :
136 : 0 : const Sprite::Reference& getSprite() const { return mpSprite; }
137 : :
138 : : // #i61843# need to return by value here, to be used safely from bind
139 : 0 : ::basegfx::B2DRange getUpdateArea() const { return maTrueUpdateArea; }
140 : 0 : bool needsUpdate() const { return mbNeedsUpdate; }
141 : 0 : bool isPureMove() const { return mbIsPureMove; }
142 : :
143 : : private:
144 : : Sprite::Reference mpSprite;
145 : : ::basegfx::B2DRange maTrueUpdateArea;
146 : : bool mbNeedsUpdate;
147 : : bool mbIsPureMove;
148 : : };
149 : :
150 : :
151 : : /** Helper struct for SpriteTracer template
152 : :
153 : : This struct stores change information to a sprite's visual
154 : : appearance (move, content updated, and the like).
155 : : */
156 : 0 : struct SpriteChangeRecord
157 : : {
158 : : typedef enum{ none=0, move, update } ChangeType;
159 : :
160 : : SpriteChangeRecord() :
161 : : meChangeType( none ),
162 : : mpAffectedSprite(),
163 : : maOldPos(),
164 : : maUpdateArea()
165 : : {
166 : : }
167 : :
168 : 0 : SpriteChangeRecord( const Sprite::Reference& rSprite,
169 : : const ::basegfx::B2DPoint& rOldPos,
170 : : const ::basegfx::B2DPoint& rNewPos,
171 : : const ::basegfx::B2DVector& rSpriteSize ) :
172 : : meChangeType( move ),
173 : : mpAffectedSprite( rSprite ),
174 : : maOldPos( rOldPos ),
175 : : maUpdateArea( rNewPos.getX(),
176 : : rNewPos.getY(),
177 : 0 : rNewPos.getX() + rSpriteSize.getX(),
178 [ # # ]: 0 : rNewPos.getY() + rSpriteSize.getY() )
179 : : {
180 : 0 : }
181 : :
182 : 0 : SpriteChangeRecord( const Sprite::Reference& rSprite,
183 : : const ::basegfx::B2DPoint& rPos,
184 : : const ::basegfx::B2DRange& rUpdateArea ) :
185 : : meChangeType( update ),
186 : : mpAffectedSprite( rSprite ),
187 : : maOldPos( rPos ),
188 : 0 : maUpdateArea( rUpdateArea )
189 : : {
190 : 0 : }
191 : :
192 : 0 : Sprite::Reference getSprite() const { return mpAffectedSprite; }
193 : :
194 : : ChangeType meChangeType;
195 : : Sprite::Reference mpAffectedSprite;
196 : : ::basegfx::B2DPoint maOldPos;
197 : : ::basegfx::B2DRange maUpdateArea;
198 : : };
199 : :
200 : : typedef ::std::vector< SpriteChangeRecord > VectorOfChangeRecords;
201 : : typedef ::std::list< Sprite::Reference > ListOfSprites;
202 : : typedef ::basegfx::B2DConnectedRanges< SpriteInfo > SpriteConnectedRanges;
203 : : typedef SpriteConnectedRanges::ComponentType AreaComponent;
204 : : typedef SpriteConnectedRanges::ConnectedComponents UpdateArea;
205 : : typedef ::std::vector< Sprite::Reference > VectorOfSprites;
206 : :
207 : : SpriteRedrawManager();
208 : :
209 : : /** Must be called when user of this object gets
210 : : disposed. Frees all internal references.
211 : : */
212 : : void disposing();
213 : :
214 : : /** Functor, to be used from forEachSpriteArea
215 : : */
216 : : template< typename Functor > struct AreaUpdateCaller
217 : : {
218 : 0 : AreaUpdateCaller( Functor& rFunc,
219 : : const SpriteRedrawManager& rManager ) :
220 : : mrFunc( rFunc ),
221 : 0 : mrManager( rManager )
222 : : {
223 : 0 : }
224 : :
225 : 0 : void operator()( const UpdateArea& rUpdateArea )
226 : : {
227 : 0 : mrManager.handleArea( mrFunc, rUpdateArea );
228 : 0 : }
229 : :
230 : : Functor& mrFunc;
231 : : const SpriteRedrawManager& mrManager;
232 : : };
233 : :
234 : : /** Call given functor for each sprite area that needs an
235 : : update.
236 : :
237 : : This method calls the given functor for each update area
238 : : (calculated from the sprite change records).
239 : :
240 : : @tpl Functor
241 : : Must provide the following four methods:
242 : : <pre>
243 : : void backgroundPaint( ::basegfx::B2DRange aUpdateRect );
244 : : void scrollUpdate( ::basegfx::B2DRange& o_rMoveStart,
245 : : ::basegfx::B2DRange& o_rMoveEnd,
246 : : UpdateArea aUpdateArea );
247 : : void opaqueUpdate( const ::basegfx::B2DRange& rTotalArea,
248 : : const ::std::vector< ::canvas::Sprite::Reference >& rSortedUpdateSprites );
249 : : void genericUpdate( const ::basegfx::B2DRange& rTotalArea,
250 : : const ::std::vector< ::canvas::Sprite::Reference >& rSortedUpdateSprites );
251 : : </pre>
252 : : The backgroundPaint() method is called to simply repaint
253 : : background content, the scrollUpdate() method is used to
254 : : scroll a given area, and paint background in the uncovered
255 : : areas, the opaqueUpdate() method is called when a sprite
256 : : can be painted in the given area without taking background
257 : : content into account, and finally, genericUpdate() is
258 : : called for complex updates, where first the background and
259 : : then all sprites consecutively have to be repainted.
260 : : */
261 : 0 : template< typename Functor > void forEachSpriteArea( Functor& rFunc ) const
262 : : {
263 : 0 : SpriteConnectedRanges aUpdateAreas;
264 : :
265 : 0 : setupUpdateAreas( aUpdateAreas );
266 : :
267 : 0 : aUpdateAreas.forEachAggregate(
268 : : AreaUpdateCaller< Functor >( rFunc, *this ) );
269 : 0 : }
270 : :
271 : : /** Call given functor for each active sprite.
272 : :
273 : : This method calls the given functor for each active
274 : : sprite, in the order of sprite priority.
275 : :
276 : : @tpl Functor
277 : : Must provide a Functor::operator( Sprite::Reference& )
278 : : method.
279 : : */
280 : 0 : template< typename Functor > void forEachSprite( const Functor& rFunc ) const
281 : : {
282 : 0 : ::std::for_each( maSprites.begin(),
283 : : maSprites.end(),
284 : : rFunc );
285 : 0 : }
286 : :
287 : : /// Clear sprite change records (typically directly after a screen update)
288 : : void clearChangeRecords();
289 : :
290 : : // SpriteSurface interface, is delegated to e.g. from SpriteCanvas
291 : : void showSprite( const Sprite::Reference& rSprite );
292 : : void hideSprite( const Sprite::Reference& rSprite );
293 : : void moveSprite( const Sprite::Reference& rSprite,
294 : : const ::basegfx::B2DPoint& rOldPos,
295 : : const ::basegfx::B2DPoint& rNewPos,
296 : : const ::basegfx::B2DVector& rSpriteSize );
297 : : void updateSprite( const Sprite::Reference& rSprite,
298 : : const ::basegfx::B2DPoint& rPos,
299 : : const ::basegfx::B2DRange& rUpdateArea );
300 : :
301 : : /** Internal, handles each distinct component for forEachAggregate()
302 : :
303 : : The reason why this must be public is that it needs to be
304 : : accessible from the AreaUpdateCaller functor.
305 : :
306 : : @internal
307 : : */
308 : 0 : template< typename Functor > void handleArea( Functor& rFunc,
309 : : const UpdateArea& rUpdateArea ) const
310 : : {
311 : : // check whether this area contains changed sprites at all
312 : : // (if not, just ignore it)
313 : 0 : if( areSpritesChanged( rUpdateArea ) )
314 : : {
315 : : // at least one of the sprites actually needs an
316 : : // update - process whole area.
317 : :
318 : : // check whether this area could be handled special
319 : : // (background paint, direct update, scroll, etc.)
320 : 0 : ::basegfx::B2DRange aMoveStart;
321 : 0 : ::basegfx::B2DRange aMoveEnd;
322 : 0 : if( rUpdateArea.maComponentList.empty() )
323 : : {
324 : 0 : rFunc.backgroundPaint( rUpdateArea.maTotalBounds );
325 : : }
326 : : else
327 : : {
328 : : // cache number of sprites in this area (it's a
329 : : // list, and both isAreaUpdateScroll() and
330 : : // isAreaUpdateOpaque() need it).
331 : : const ::std::size_t nNumSprites(
332 : 0 : rUpdateArea.maComponentList.size() );
333 : :
334 : 0 : if( isAreaUpdateScroll( aMoveStart,
335 : : aMoveEnd,
336 : : rUpdateArea,
337 : : nNumSprites ) )
338 : : {
339 : 0 : rFunc.scrollUpdate( aMoveStart,
340 : : aMoveEnd,
341 : : rUpdateArea );
342 : : }
343 : : else
344 : : {
345 : : // potentially, more than a single sprite
346 : : // involved. Have to sort component lists for
347 : : // sprite prio.
348 : 0 : VectorOfSprites aSortedUpdateSprites;
349 : : SpriteConnectedRanges::ComponentListType::const_iterator aCurr(
350 : 0 : rUpdateArea.maComponentList.begin() );
351 : : const SpriteConnectedRanges::ComponentListType::const_iterator aEnd(
352 : 0 : rUpdateArea.maComponentList.end() );
353 : 0 : while( aCurr != aEnd )
354 : : {
355 : 0 : const Sprite::Reference& rSprite( aCurr->second.getSprite() );
356 : 0 : if( rSprite.is() )
357 : 0 : aSortedUpdateSprites.push_back( rSprite );
358 : :
359 : 0 : ++aCurr;
360 : : }
361 : :
362 : : ::std::sort( aSortedUpdateSprites.begin(),
363 : : aSortedUpdateSprites.end(),
364 : 0 : SpriteWeakOrder() );
365 : :
366 : 0 : if( isAreaUpdateOpaque( rUpdateArea,
367 : : nNumSprites ) )
368 : : {
369 : 0 : rFunc.opaqueUpdate( rUpdateArea.maTotalBounds,
370 : : aSortedUpdateSprites );
371 : : }
372 : : else
373 : : {
374 : 0 : rFunc.genericUpdate( rUpdateArea.maTotalBounds,
375 : : aSortedUpdateSprites );
376 : : }
377 : : }
378 : : }
379 : : }
380 : 0 : }
381 : :
382 : : private:
383 : : /** Central method of this class. Calculates the set of
384 : : disjunct components that need an update.
385 : : */
386 : : void setupUpdateAreas( SpriteConnectedRanges& rUpdateAreas ) const;
387 : :
388 : : bool areSpritesChanged( const UpdateArea& rUpdateArea ) const;
389 : :
390 : : bool isAreaUpdateNotOpaque( const ::basegfx::B2DRange& rUpdateRect,
391 : : const AreaComponent& rComponent ) const;
392 : :
393 : : bool isAreaUpdateOpaque( const UpdateArea& rUpdateArea,
394 : : ::std::size_t nNumSprites ) const;
395 : :
396 : : /** Check whether given update area can be handled by a simple
397 : : scroll
398 : :
399 : : @param o_rMoveStart
400 : : Start rect of the move
401 : :
402 : : @param o_rMoveEnd
403 : : End rect of the move. The content must be moved from start
404 : : to end rect
405 : :
406 : : @param rUpdateArea
407 : : Area to check for scroll update optimization
408 : : */
409 : : bool isAreaUpdateScroll( ::basegfx::B2DRange& o_rMoveStart,
410 : : ::basegfx::B2DRange& o_rMoveEnd,
411 : : const UpdateArea& rUpdateArea,
412 : : ::std::size_t nNumSprites ) const;
413 : :
414 : :
415 : : ListOfSprites maSprites; // list of active
416 : : // sprite
417 : : // objects. this
418 : : // list is only
419 : : // used for full
420 : : // repaints,
421 : : // otherwise, we
422 : : // rely on the
423 : : // active sprites
424 : : // itself to notify
425 : : // us.
426 : :
427 : : VectorOfChangeRecords maChangeRecords; // vector of
428 : : // sprites
429 : : // changes
430 : : // since last
431 : : // updateScreen()
432 : : // call
433 : : };
434 : : }
435 : :
436 : : #endif /* INCLUDED_CANVAS_SPRITEREDRAWMANAGER_HXX */
437 : :
438 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|