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