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