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 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_svtools.hxx" 30 31 #include <vos/timer.hxx> 32 #include <tools/debug.hxx> 33 #include <vcl/outdev.hxx> 34 #include <tools/poly.hxx> 35 #include "grfcache.hxx" 36 37 #include <memory> 38 39 // ----------- 40 // - Defines - 41 // ----------- 42 43 #define RELEASE_TIMEOUT 10000 44 #define MAX_BMP_EXTENT 4096 45 46 // ----------- 47 // - statics - 48 // ----------- 49 50 static const char aHexData[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; 51 52 // ------------- 53 // - GraphicID - 54 // ------------- 55 56 class GraphicID 57 { 58 private: 59 60 sal_uInt32 mnID1; 61 sal_uInt32 mnID2; 62 sal_uInt32 mnID3; 63 sal_uInt32 mnID4; 64 65 GraphicID(); 66 67 public: 68 69 70 GraphicID( const GraphicObject& rObj ); 71 ~GraphicID() {} 72 73 sal_Bool operator==( const GraphicID& rID ) const 74 { 75 return( rID.mnID1 == mnID1 && rID.mnID2 == mnID2 && 76 rID.mnID3 == mnID3 && rID.mnID4 == mnID4 ); 77 } 78 79 ByteString GetIDString() const; 80 sal_Bool IsEmpty() const { return( 0 == mnID4 ); } 81 }; 82 83 // ----------------------------------------------------------------------------- 84 85 GraphicID::GraphicID( const GraphicObject& rObj ) 86 { 87 const Graphic& rGraphic = rObj.GetGraphic(); 88 89 mnID1 = ( (sal_uLong) rGraphic.GetType() ) << 28; 90 91 switch( rGraphic.GetType() ) 92 { 93 case( GRAPHIC_BITMAP ): 94 { 95 if( rGraphic.IsAnimated() ) 96 { 97 const Animation aAnimation( rGraphic.GetAnimation() ); 98 99 mnID1 |= ( aAnimation.Count() & 0x0fffffff ); 100 mnID2 = aAnimation.GetDisplaySizePixel().Width(); 101 mnID3 = aAnimation.GetDisplaySizePixel().Height(); 102 mnID4 = rGraphic.GetChecksum(); 103 } 104 else 105 { 106 const BitmapEx aBmpEx( rGraphic.GetBitmapEx() ); 107 108 mnID1 |= ( ( ( (sal_uLong) aBmpEx.GetTransparentType() << 8 ) | ( aBmpEx.IsAlpha() ? 1 : 0 ) ) & 0x0fffffff ); 109 mnID2 = aBmpEx.GetSizePixel().Width(); 110 mnID3 = aBmpEx.GetSizePixel().Height(); 111 mnID4 = rGraphic.GetChecksum(); 112 } 113 } 114 break; 115 116 case( GRAPHIC_GDIMETAFILE ): 117 { 118 const GDIMetaFile aMtf( rGraphic.GetGDIMetaFile() ); 119 120 mnID1 |= ( aMtf.GetActionCount() & 0x0fffffff ); 121 mnID2 = aMtf.GetPrefSize().Width(); 122 mnID3 = aMtf.GetPrefSize().Height(); 123 mnID4 = rGraphic.GetChecksum(); 124 } 125 break; 126 127 default: 128 mnID2 = mnID3 = mnID4 = 0; 129 break; 130 } 131 } 132 133 // ----------------------------------------------------------------------------- 134 135 ByteString GraphicID::GetIDString() const 136 { 137 ByteString aHexStr; 138 sal_Char* pStr = aHexStr.AllocBuffer( 32 ); 139 sal_Int32 nShift; 140 141 for( nShift = 28; nShift >= 0; nShift -= 4 ) 142 *pStr++ = aHexData[ ( mnID1 >> (sal_uInt32) nShift ) & 0xf ]; 143 144 for( nShift = 28; nShift >= 0; nShift -= 4 ) 145 *pStr++ = aHexData[ ( mnID2 >> (sal_uInt32) nShift ) & 0xf ]; 146 147 for( nShift = 28; nShift >= 0; nShift -= 4 ) 148 *pStr++ = aHexData[ ( mnID3 >> (sal_uInt32) nShift ) & 0xf ]; 149 150 for( nShift = 28; nShift >= 0; nShift -= 4 ) 151 *pStr++ = aHexData[ ( mnID4 >> (sal_uInt32) nShift ) & 0xf ]; 152 153 return aHexStr; 154 } 155 156 // --------------------- 157 // - GraphicCacheEntry - 158 // --------------------- 159 160 class GraphicCacheEntry 161 { 162 private: 163 164 List maGraphicObjectList; 165 GraphicID maID; 166 GfxLink maGfxLink; 167 BitmapEx* mpBmpEx; 168 GDIMetaFile* mpMtf; 169 Animation* mpAnimation; 170 sal_Bool mbSwappedAll; 171 172 sal_Bool ImplInit( const GraphicObject& rObj ); 173 sal_Bool ImplMatches( const GraphicObject& rObj ) const { return( GraphicID( rObj ) == maID ); } 174 void ImplFillSubstitute( Graphic& rSubstitute ); 175 176 public: 177 178 GraphicCacheEntry( const GraphicObject& rObj ); 179 ~GraphicCacheEntry(); 180 181 const GraphicID& GetID() const { return maID; } 182 183 void AddGraphicObjectReference( const GraphicObject& rObj, Graphic& rSubstitute ); 184 sal_Bool ReleaseGraphicObjectReference( const GraphicObject& rObj ); 185 sal_uLong GetGraphicObjectReferenceCount() { return maGraphicObjectList.Count(); } 186 sal_Bool HasGraphicObjectReference( const GraphicObject& rObj ); 187 188 void TryToSwapIn(); 189 void GraphicObjectWasSwappedOut( const GraphicObject& rObj ); 190 sal_Bool FillSwappedGraphicObject( const GraphicObject& rObj, Graphic& rSubstitute ); 191 void GraphicObjectWasSwappedIn( const GraphicObject& rObj ); 192 }; 193 194 // ----------------------------------------------------------------------------- 195 196 GraphicCacheEntry::GraphicCacheEntry( const GraphicObject& rObj ) : 197 maID ( rObj ), 198 mpBmpEx ( NULL ), 199 mpMtf ( NULL ), 200 mpAnimation ( NULL ), 201 mbSwappedAll ( !ImplInit( rObj ) ) 202 { 203 maGraphicObjectList.Insert( (void*) &rObj, LIST_APPEND ); 204 } 205 206 // ----------------------------------------------------------------------------- 207 208 GraphicCacheEntry::~GraphicCacheEntry() 209 { 210 DBG_ASSERT( !maGraphicObjectList.Count(), "GraphicCacheEntry::~GraphicCacheEntry(): Not all GraphicObjects are removed from this entry" ); 211 212 delete mpBmpEx; 213 delete mpMtf; 214 delete mpAnimation; 215 } 216 217 // ----------------------------------------------------------------------------- 218 219 sal_Bool GraphicCacheEntry::ImplInit( const GraphicObject& rObj ) 220 { 221 sal_Bool bRet; 222 223 if( !rObj.IsSwappedOut() ) 224 { 225 const Graphic& rGraphic = rObj.GetGraphic(); 226 227 if( mpBmpEx ) 228 delete mpBmpEx, mpBmpEx = NULL; 229 230 if( mpMtf ) 231 delete mpMtf, mpMtf = NULL; 232 233 if( mpAnimation ) 234 delete mpAnimation, mpAnimation = NULL; 235 236 switch( rGraphic.GetType() ) 237 { 238 case( GRAPHIC_BITMAP ): 239 { 240 if( rGraphic.IsAnimated() ) 241 mpAnimation = new Animation( rGraphic.GetAnimation() ); 242 else 243 mpBmpEx = new BitmapEx( rGraphic.GetBitmapEx() ); 244 } 245 break; 246 247 case( GRAPHIC_GDIMETAFILE ): 248 { 249 mpMtf = new GDIMetaFile( rGraphic.GetGDIMetaFile() ); 250 } 251 break; 252 253 default: 254 DBG_ASSERT( GetID().IsEmpty(), "GraphicCacheEntry::ImplInit: Could not initialize graphic! (=>KA)" ); 255 break; 256 } 257 258 if( rGraphic.IsLink() ) 259 maGfxLink = ( (Graphic&) rGraphic ).GetLink(); 260 else 261 maGfxLink = GfxLink(); 262 263 bRet = sal_True; 264 } 265 else 266 bRet = sal_False; 267 268 return bRet; 269 } 270 271 // ----------------------------------------------------------------------------- 272 273 void GraphicCacheEntry::ImplFillSubstitute( Graphic& rSubstitute ) 274 { 275 // create substitute for graphic; 276 const Size aPrefSize( rSubstitute.GetPrefSize() ); 277 const MapMode aPrefMapMode( rSubstitute.GetPrefMapMode() ); 278 const Link aAnimationNotifyHdl( rSubstitute.GetAnimationNotifyHdl() ); 279 const String aDocFileName( rSubstitute.GetDocFileName() ); 280 const sal_uLong nDocFilePos = rSubstitute.GetDocFilePos(); 281 const GraphicType eOldType = rSubstitute.GetType(); 282 const sal_Bool bDefaultType = ( rSubstitute.GetType() == GRAPHIC_DEFAULT ); 283 284 if( rSubstitute.IsLink() && ( GFX_LINK_TYPE_NONE == maGfxLink.GetType() ) ) 285 maGfxLink = rSubstitute.GetLink(); 286 287 if( mpBmpEx ) 288 rSubstitute = *mpBmpEx; 289 else if( mpAnimation ) 290 rSubstitute = *mpAnimation; 291 else if( mpMtf ) 292 rSubstitute = *mpMtf; 293 else 294 rSubstitute.Clear(); 295 296 if( eOldType != GRAPHIC_NONE ) 297 { 298 rSubstitute.SetPrefSize( aPrefSize ); 299 rSubstitute.SetPrefMapMode( aPrefMapMode ); 300 rSubstitute.SetAnimationNotifyHdl( aAnimationNotifyHdl ); 301 rSubstitute.SetDocFileName( aDocFileName, nDocFilePos ); 302 } 303 304 if( GFX_LINK_TYPE_NONE != maGfxLink.GetType() ) 305 rSubstitute.SetLink( maGfxLink ); 306 307 if( bDefaultType ) 308 rSubstitute.SetDefaultType(); 309 } 310 311 // ----------------------------------------------------------------------------- 312 313 void GraphicCacheEntry::AddGraphicObjectReference( const GraphicObject& rObj, Graphic& rSubstitute ) 314 { 315 if( mbSwappedAll ) 316 mbSwappedAll = !ImplInit( rObj ); 317 318 ImplFillSubstitute( rSubstitute ); 319 maGraphicObjectList.Insert( (void*) &rObj, LIST_APPEND ); 320 } 321 322 // ----------------------------------------------------------------------------- 323 324 sal_Bool GraphicCacheEntry::ReleaseGraphicObjectReference( const GraphicObject& rObj ) 325 { 326 sal_Bool bRet = sal_False; 327 328 for( void* pObj = maGraphicObjectList.First(); !bRet && pObj; pObj = maGraphicObjectList.Next() ) 329 { 330 if( &rObj == (GraphicObject*) pObj ) 331 { 332 maGraphicObjectList.Remove( pObj ); 333 bRet = sal_True; 334 } 335 } 336 337 return bRet; 338 } 339 340 // ----------------------------------------------------------------------------- 341 342 sal_Bool GraphicCacheEntry::HasGraphicObjectReference( const GraphicObject& rObj ) 343 { 344 sal_Bool bRet = sal_False; 345 346 for( void* pObj = maGraphicObjectList.First(); !bRet && pObj; pObj = maGraphicObjectList.Next() ) 347 if( &rObj == (GraphicObject*) pObj ) 348 bRet = sal_True; 349 350 return bRet; 351 } 352 353 // ----------------------------------------------------------------------------- 354 355 void GraphicCacheEntry::TryToSwapIn() 356 { 357 if( mbSwappedAll && maGraphicObjectList.Count() ) 358 ( (GraphicObject*) maGraphicObjectList.First() )->FireSwapInRequest(); 359 } 360 361 // ----------------------------------------------------------------------------- 362 363 void GraphicCacheEntry::GraphicObjectWasSwappedOut( const GraphicObject& /*rObj*/ ) 364 { 365 mbSwappedAll = sal_True; 366 367 for( void* pObj = maGraphicObjectList.First(); mbSwappedAll && pObj; pObj = maGraphicObjectList.Next() ) 368 if( !( (GraphicObject*) pObj )->IsSwappedOut() ) 369 mbSwappedAll = sal_False; 370 371 if( mbSwappedAll ) 372 { 373 delete mpBmpEx, mpBmpEx = NULL; 374 delete mpMtf, mpMtf = NULL; 375 delete mpAnimation, mpAnimation = NULL; 376 } 377 } 378 379 // ----------------------------------------------------------------------------- 380 381 sal_Bool GraphicCacheEntry::FillSwappedGraphicObject( const GraphicObject& rObj, Graphic& rSubstitute ) 382 { 383 sal_Bool bRet; 384 385 if( !mbSwappedAll && rObj.IsSwappedOut() ) 386 { 387 ImplFillSubstitute( rSubstitute ); 388 bRet = sal_True; 389 } 390 else 391 bRet = sal_False; 392 393 return bRet; 394 } 395 396 // ----------------------------------------------------------------------------- 397 398 void GraphicCacheEntry::GraphicObjectWasSwappedIn( const GraphicObject& rObj ) 399 { 400 if( mbSwappedAll ) 401 mbSwappedAll = !ImplInit( rObj ); 402 } 403 404 // ---------------------------- 405 // - GraphicDisplayCacheEntry - 406 // ---------------------------- 407 408 class GraphicDisplayCacheEntry 409 { 410 private: 411 412 ::vos::TTimeValue maReleaseTime; 413 const GraphicCacheEntry* mpRefCacheEntry; 414 GDIMetaFile* mpMtf; 415 BitmapEx* mpBmpEx; 416 GraphicAttr maAttr; 417 Size maOutSizePix; 418 sal_uLong mnCacheSize; 419 sal_uLong mnOutDevDrawMode; 420 sal_uInt16 mnOutDevBitCount; 421 422 public: 423 424 static sal_uLong GetNeededSize( OutputDevice* pOut, const Point& rPt, const Size& rSz, 425 const GraphicObject& rObj, const GraphicAttr& rAttr ); 426 427 public: 428 429 GraphicDisplayCacheEntry( const GraphicCacheEntry* pRefCacheEntry, 430 OutputDevice* pOut, const Point& rPt, const Size& rSz, 431 const GraphicObject& rObj, const GraphicAttr& rAttr, 432 const BitmapEx& rBmpEx ) : 433 mpRefCacheEntry( pRefCacheEntry ), 434 mpMtf( NULL ), mpBmpEx( new BitmapEx( rBmpEx ) ), 435 maAttr( rAttr ), maOutSizePix( pOut->LogicToPixel( rSz ) ), 436 mnCacheSize( GetNeededSize( pOut, rPt, rSz, rObj, rAttr ) ), 437 mnOutDevDrawMode( pOut->GetDrawMode() ), 438 mnOutDevBitCount( pOut->GetBitCount() ) 439 { 440 } 441 442 GraphicDisplayCacheEntry( const GraphicCacheEntry* pRefCacheEntry, 443 OutputDevice* pOut, const Point& rPt, const Size& rSz, 444 const GraphicObject& rObj, const GraphicAttr& rAttr, 445 const GDIMetaFile& rMtf ) : 446 mpRefCacheEntry( pRefCacheEntry ), 447 mpMtf( new GDIMetaFile( rMtf ) ), mpBmpEx( NULL ), 448 maAttr( rAttr ), maOutSizePix( pOut->LogicToPixel( rSz ) ), 449 mnCacheSize( GetNeededSize( pOut, rPt, rSz, rObj, rAttr ) ), 450 mnOutDevDrawMode( pOut->GetDrawMode() ), 451 mnOutDevBitCount( pOut->GetBitCount() ) 452 { 453 } 454 455 456 ~GraphicDisplayCacheEntry(); 457 458 const GraphicAttr& GetAttr() const { return maAttr; } 459 const Size& GetOutputSizePixel() const { return maOutSizePix; } 460 sal_uLong GetCacheSize() const { return mnCacheSize; } 461 const GraphicCacheEntry* GetReferencedCacheEntry() const { return mpRefCacheEntry; } 462 sal_uLong GetOutDevDrawMode() const { return mnOutDevDrawMode; } 463 sal_uInt16 GetOutDevBitCount() const { return mnOutDevBitCount; } 464 465 void SetReleaseTime( const ::vos::TTimeValue& rReleaseTime ) { maReleaseTime = rReleaseTime; } 466 const ::vos::TTimeValue& GetReleaseTime() const { return maReleaseTime; } 467 468 sal_Bool Matches( OutputDevice* pOut, const Point& /*rPtPixel*/, const Size& rSzPixel, 469 const GraphicCacheEntry* pCacheEntry, const GraphicAttr& rAttr ) const 470 { 471 // #i46805# Additional match 472 // criteria: outdev draw mode and 473 // bit count. One cannot reuse 474 // this cache object, if it's 475 // e.g. generated for 476 // DRAWMODE_GRAYBITMAP. 477 return( ( pCacheEntry == mpRefCacheEntry ) && 478 ( maAttr == rAttr ) && 479 ( ( maOutSizePix == rSzPixel ) || ( !maOutSizePix.Width() && !maOutSizePix.Height() ) ) && 480 ( pOut->GetBitCount() == mnOutDevBitCount ) && 481 ( pOut->GetDrawMode() == mnOutDevDrawMode ) ); 482 } 483 484 void Draw( OutputDevice* pOut, const Point& rPt, const Size& rSz ) const; 485 }; 486 487 // ----------------------------------------------------------------------------- 488 489 sal_uLong GraphicDisplayCacheEntry::GetNeededSize( OutputDevice* pOut, const Point& /*rPt*/, const Size& rSz, 490 const GraphicObject& rObj, const GraphicAttr& rAttr ) 491 { 492 const Graphic& rGraphic = rObj.GetGraphic(); 493 const GraphicType eType = rGraphic.GetType(); 494 sal_uLong nNeededSize; 495 496 if( GRAPHIC_BITMAP == eType ) 497 { 498 const Size aOutSizePix( pOut->LogicToPixel( rSz ) ); 499 const long nBitCount = pOut->GetBitCount(); 500 501 if( ( aOutSizePix.Width() > MAX_BMP_EXTENT ) || 502 ( aOutSizePix.Height() > MAX_BMP_EXTENT ) ) 503 { 504 nNeededSize = ULONG_MAX; 505 } 506 else if( nBitCount ) 507 { 508 nNeededSize = aOutSizePix.Width() * aOutSizePix.Height() * nBitCount / 8; 509 510 if( rObj.IsTransparent() || ( rAttr.GetRotation() % 3600 ) ) 511 nNeededSize += nNeededSize / nBitCount; 512 } 513 else 514 { 515 DBG_ERROR( "GraphicDisplayCacheEntry::GetNeededSize(): pOut->GetBitCount() == 0" ); 516 nNeededSize = 256000; 517 } 518 } 519 else if( GRAPHIC_GDIMETAFILE == eType ) 520 nNeededSize = rGraphic.GetSizeBytes(); 521 else 522 nNeededSize = 0; 523 524 return nNeededSize; 525 } 526 527 // ----------------------------------------------------------------------------- 528 529 GraphicDisplayCacheEntry::~GraphicDisplayCacheEntry() 530 { 531 if( mpMtf ) 532 delete mpMtf; 533 534 if( mpBmpEx ) 535 delete mpBmpEx; 536 } 537 538 // ----------------------------------------------------------------------------- 539 540 void GraphicDisplayCacheEntry::Draw( OutputDevice* pOut, const Point& rPt, const Size& rSz ) const 541 { 542 if( mpMtf ) 543 GraphicManager::ImplDraw( pOut, rPt, rSz, *mpMtf, maAttr ); 544 else if( mpBmpEx ) 545 { 546 if( maAttr.IsRotated() ) 547 { 548 Polygon aPoly( Rectangle( rPt, rSz ) ); 549 550 aPoly.Rotate( rPt, maAttr.GetRotation() % 3600 ); 551 const Rectangle aRotBoundRect( aPoly.GetBoundRect() ); 552 pOut->DrawBitmapEx( aRotBoundRect.TopLeft(), aRotBoundRect.GetSize(), *mpBmpEx ); 553 } 554 else 555 pOut->DrawBitmapEx( rPt, rSz, *mpBmpEx ); 556 } 557 } 558 559 // ----------------------- 560 // - GraphicCache - 561 // ----------------------- 562 563 GraphicCache::GraphicCache( GraphicManager& rMgr, sal_uLong nDisplayCacheSize, sal_uLong nMaxObjDisplayCacheSize ) : 564 mrMgr ( rMgr ), 565 mnReleaseTimeoutSeconds ( 0UL ), 566 mnMaxDisplaySize ( nDisplayCacheSize ), 567 mnMaxObjDisplaySize ( nMaxObjDisplayCacheSize ), 568 mnUsedDisplaySize ( 0UL ) 569 { 570 maReleaseTimer.SetTimeoutHdl( LINK( this, GraphicCache, ReleaseTimeoutHdl ) ); 571 maReleaseTimer.SetTimeout( RELEASE_TIMEOUT ); 572 maReleaseTimer.Start(); 573 } 574 575 // ----------------------------------------------------------------------------- 576 577 GraphicCache::~GraphicCache() 578 { 579 DBG_ASSERT( !maGraphicCache.Count(), "GraphicCache::~GraphicCache(): there are some GraphicObjects in cache" ); 580 DBG_ASSERT( !maDisplayCache.Count(), "GraphicCache::~GraphicCache(): there are some GraphicObjects in display cache" ); 581 } 582 583 // ----------------------------------------------------------------------------- 584 585 void GraphicCache::AddGraphicObject( const GraphicObject& rObj, Graphic& rSubstitute, 586 const ByteString* pID, const GraphicObject* pCopyObj ) 587 { 588 sal_Bool bInserted = sal_False; 589 590 if( !rObj.IsSwappedOut() && 591 ( pID || ( pCopyObj && ( pCopyObj->GetType() != GRAPHIC_NONE ) ) || ( rObj.GetType() != GRAPHIC_NONE ) ) ) 592 { 593 if( pCopyObj ) 594 { 595 GraphicCacheEntry* pEntry = static_cast< GraphicCacheEntry* >( maGraphicCache.First() ); 596 597 while( !bInserted && pEntry ) 598 { 599 if( pEntry->HasGraphicObjectReference( *pCopyObj ) ) 600 { 601 pEntry->AddGraphicObjectReference( rObj, rSubstitute ); 602 bInserted = sal_True; 603 } 604 else 605 { 606 pEntry = static_cast< GraphicCacheEntry* >( maGraphicCache.Next() ); 607 } 608 } 609 } 610 611 if( !bInserted ) 612 { 613 GraphicCacheEntry* pEntry = static_cast< GraphicCacheEntry* >( maGraphicCache.First() ); 614 ::std::auto_ptr< GraphicID > apID; 615 616 if( !pID ) 617 { 618 apID.reset( new GraphicID( rObj ) ); 619 } 620 621 while( !bInserted && pEntry ) 622 { 623 const GraphicID& rEntryID = pEntry->GetID(); 624 625 if( pID ) 626 { 627 if( rEntryID.GetIDString() == *pID ) 628 { 629 pEntry->TryToSwapIn(); 630 631 // since pEntry->TryToSwapIn can modify our current list, we have to 632 // iterate from beginning to add a reference to the appropriate 633 // CacheEntry object; after this, quickly jump out of the outer iteration 634 for( pEntry = static_cast< GraphicCacheEntry* >( maGraphicCache.First() ); 635 !bInserted && pEntry; 636 pEntry = static_cast< GraphicCacheEntry* >( maGraphicCache.Next() ) ) 637 { 638 const GraphicID& rID = pEntry->GetID(); 639 640 if( rID.GetIDString() == *pID ) 641 { 642 pEntry->AddGraphicObjectReference( rObj, rSubstitute ); 643 bInserted = sal_True; 644 } 645 } 646 647 if( !bInserted ) 648 { 649 maGraphicCache.Insert( new GraphicCacheEntry( rObj ), LIST_APPEND ); 650 bInserted = sal_True; 651 } 652 } 653 } 654 else 655 { 656 if( rEntryID == *apID ) 657 { 658 pEntry->AddGraphicObjectReference( rObj, rSubstitute ); 659 bInserted = sal_True; 660 } 661 } 662 663 if( !bInserted ) 664 pEntry = static_cast< GraphicCacheEntry* >( maGraphicCache.Next() ); 665 } 666 } 667 } 668 669 if( !bInserted ) 670 maGraphicCache.Insert( new GraphicCacheEntry( rObj ), LIST_APPEND ); 671 } 672 673 // ----------------------------------------------------------------------------- 674 675 void GraphicCache::ReleaseGraphicObject( const GraphicObject& rObj ) 676 { 677 // Release cached object 678 GraphicCacheEntry* pEntry = (GraphicCacheEntry*) maGraphicCache.First(); 679 sal_Bool bRemoved = sal_False; 680 681 while( !bRemoved && pEntry ) 682 { 683 bRemoved = pEntry->ReleaseGraphicObjectReference( rObj ); 684 685 if( bRemoved ) 686 { 687 if( 0 == pEntry->GetGraphicObjectReferenceCount() ) 688 { 689 // if graphic cache entry has no more references, 690 // the corresponding display cache object can be removed 691 GraphicDisplayCacheEntry* pDisplayEntry = (GraphicDisplayCacheEntry*) maDisplayCache.First(); 692 693 while( pDisplayEntry ) 694 { 695 if( pDisplayEntry->GetReferencedCacheEntry() == pEntry ) 696 { 697 mnUsedDisplaySize -= pDisplayEntry->GetCacheSize(); 698 maDisplayCache.Remove( pDisplayEntry ); 699 delete pDisplayEntry; 700 pDisplayEntry = (GraphicDisplayCacheEntry*) maDisplayCache.GetCurObject(); 701 } 702 else 703 pDisplayEntry = (GraphicDisplayCacheEntry*) maDisplayCache.Next(); 704 } 705 706 // delete graphic cache entry 707 maGraphicCache.Remove( (void*) pEntry ); 708 delete pEntry; 709 } 710 } 711 else 712 pEntry = (GraphicCacheEntry*) maGraphicCache.Next(); 713 } 714 715 DBG_ASSERT( bRemoved, "GraphicCache::ReleaseGraphicObject(...): GraphicObject not found in cache" ); 716 } 717 718 // ----------------------------------------------------------------------------- 719 720 void GraphicCache::GraphicObjectWasSwappedOut( const GraphicObject& rObj ) 721 { 722 // notify cache that rObj is swapped out (and can thus be pruned 723 // from the cache) 724 GraphicCacheEntry* pEntry = ImplGetCacheEntry( rObj ); 725 726 if( pEntry ) 727 pEntry->GraphicObjectWasSwappedOut( rObj ); 728 } 729 730 // ----------------------------------------------------------------------------- 731 732 sal_Bool GraphicCache::FillSwappedGraphicObject( const GraphicObject& rObj, Graphic& rSubstitute ) 733 { 734 GraphicCacheEntry* pEntry = ImplGetCacheEntry( rObj ); 735 736 if( !pEntry ) 737 return sal_False; 738 739 return pEntry->FillSwappedGraphicObject( rObj, rSubstitute ); 740 } 741 742 // ----------------------------------------------------------------------------- 743 744 void GraphicCache::GraphicObjectWasSwappedIn( const GraphicObject& rObj ) 745 { 746 GraphicCacheEntry* pEntry = ImplGetCacheEntry( rObj ); 747 748 if( pEntry ) 749 { 750 if( pEntry->GetID().IsEmpty() ) 751 { 752 ReleaseGraphicObject( rObj ); 753 AddGraphicObject( rObj, (Graphic&) rObj.GetGraphic(), NULL, NULL ); 754 } 755 else 756 pEntry->GraphicObjectWasSwappedIn( rObj ); 757 } 758 } 759 760 // ----------------------------------------------------------------------------- 761 762 void GraphicCache::SetMaxDisplayCacheSize( sal_uLong nNewCacheSize ) 763 { 764 mnMaxDisplaySize = nNewCacheSize; 765 766 if( GetMaxDisplayCacheSize() < GetUsedDisplayCacheSize() ) 767 ImplFreeDisplayCacheSpace( GetUsedDisplayCacheSize() - GetMaxDisplayCacheSize() ); 768 } 769 770 // ----------------------------------------------------------------------------- 771 772 void GraphicCache::SetMaxObjDisplayCacheSize( sal_uLong nNewMaxObjSize, sal_Bool bDestroyGreaterCached ) 773 { 774 const sal_Bool bDestroy = ( bDestroyGreaterCached && ( nNewMaxObjSize < mnMaxObjDisplaySize ) ); 775 776 mnMaxObjDisplaySize = Min( nNewMaxObjSize, mnMaxDisplaySize ); 777 778 if( bDestroy ) 779 { 780 GraphicDisplayCacheEntry* pCacheObj = (GraphicDisplayCacheEntry*) maDisplayCache.First(); 781 782 while( pCacheObj ) 783 { 784 if( pCacheObj->GetCacheSize() > mnMaxObjDisplaySize ) 785 { 786 mnUsedDisplaySize -= pCacheObj->GetCacheSize(); 787 maDisplayCache.Remove( pCacheObj ); 788 delete pCacheObj; 789 pCacheObj = (GraphicDisplayCacheEntry*) maDisplayCache.GetCurObject(); 790 } 791 else 792 pCacheObj = (GraphicDisplayCacheEntry*) maDisplayCache.Next(); 793 } 794 } 795 } 796 797 // ----------------------------------------------------------------------------- 798 799 void GraphicCache::SetCacheTimeout( sal_uLong nTimeoutSeconds ) 800 { 801 if( mnReleaseTimeoutSeconds != nTimeoutSeconds ) 802 { 803 GraphicDisplayCacheEntry* pDisplayEntry = (GraphicDisplayCacheEntry*) maDisplayCache.First(); 804 ::vos::TTimeValue aReleaseTime; 805 806 if( ( mnReleaseTimeoutSeconds = nTimeoutSeconds ) != 0 ) 807 { 808 osl_getSystemTime( &aReleaseTime ); 809 aReleaseTime.addTime( ::vos::TTimeValue( nTimeoutSeconds, 0 ) ); 810 } 811 812 while( pDisplayEntry ) 813 { 814 pDisplayEntry->SetReleaseTime( aReleaseTime ); 815 pDisplayEntry = (GraphicDisplayCacheEntry*) maDisplayCache.Next(); 816 } 817 } 818 } 819 820 // ----------------------------------------------------------------------------- 821 822 void GraphicCache::ClearDisplayCache() 823 { 824 for( void* pObj = maDisplayCache.First(); pObj; pObj = maDisplayCache.Next() ) 825 delete (GraphicDisplayCacheEntry*) pObj; 826 827 maDisplayCache.Clear(); 828 mnUsedDisplaySize = 0UL; 829 } 830 831 // ----------------------------------------------------------------------------- 832 833 sal_Bool GraphicCache::IsDisplayCacheable( OutputDevice* pOut, const Point& rPt, const Size& rSz, 834 const GraphicObject& rObj, const GraphicAttr& rAttr ) const 835 { 836 return( GraphicDisplayCacheEntry::GetNeededSize( pOut, rPt, rSz, rObj, rAttr ) <= 837 GetMaxObjDisplayCacheSize() ); 838 } 839 840 // ----------------------------------------------------------------------------- 841 842 sal_Bool GraphicCache::IsInDisplayCache( OutputDevice* pOut, const Point& rPt, const Size& rSz, 843 const GraphicObject& rObj, const GraphicAttr& rAttr ) const 844 { 845 const Point aPtPixel( pOut->LogicToPixel( rPt ) ); 846 const Size aSzPixel( pOut->LogicToPixel( rSz ) ); 847 const GraphicCacheEntry* pCacheEntry = ( (GraphicCache*) this )->ImplGetCacheEntry( rObj ); 848 //GraphicDisplayCacheEntry* pDisplayEntry = (GraphicDisplayCacheEntry*) ( (GraphicCache*) this )->maDisplayCache.First(); // -Wall removed .... 849 sal_Bool bFound = sal_False; 850 851 if( pCacheEntry ) 852 { 853 for( long i = 0, nCount = maDisplayCache.Count(); !bFound && ( i < nCount ); i++ ) 854 if( ( (GraphicDisplayCacheEntry*) maDisplayCache.GetObject( i ) )->Matches( pOut, aPtPixel, aSzPixel, pCacheEntry, rAttr ) ) 855 bFound = sal_True; 856 } 857 858 return bFound; 859 } 860 861 // ----------------------------------------------------------------------------- 862 863 ByteString GraphicCache::GetUniqueID( const GraphicObject& rObj ) const 864 { 865 ByteString aRet; 866 GraphicCacheEntry* pEntry = ( (GraphicCache*) this )->ImplGetCacheEntry( rObj ); 867 868 // ensure that the entry is correctly initialized (it has to be read at least once) 869 if( pEntry && pEntry->GetID().IsEmpty() ) 870 pEntry->TryToSwapIn(); 871 872 // do another call to ImplGetCacheEntry in case of modified entry list 873 pEntry = ( (GraphicCache*) this )->ImplGetCacheEntry( rObj ); 874 875 if( pEntry ) 876 aRet = pEntry->GetID().GetIDString(); 877 878 return aRet; 879 } 880 881 // ----------------------------------------------------------------------------- 882 883 sal_Bool GraphicCache::CreateDisplayCacheObj( OutputDevice* pOut, const Point& rPt, const Size& rSz, 884 const GraphicObject& rObj, const GraphicAttr& rAttr, 885 const BitmapEx& rBmpEx ) 886 { 887 const sal_uLong nNeededSize = GraphicDisplayCacheEntry::GetNeededSize( pOut, rPt, rSz, rObj, rAttr ); 888 sal_Bool bRet = sal_False; 889 890 if( nNeededSize <= GetMaxObjDisplayCacheSize() ) 891 { 892 if( nNeededSize > GetFreeDisplayCacheSize() ) 893 ImplFreeDisplayCacheSpace( nNeededSize - GetFreeDisplayCacheSize() ); 894 895 GraphicDisplayCacheEntry* pNewEntry = new GraphicDisplayCacheEntry( ImplGetCacheEntry( rObj ), 896 pOut, rPt, rSz, rObj, rAttr, rBmpEx ); 897 898 if( GetCacheTimeout() ) 899 { 900 ::vos::TTimeValue aReleaseTime; 901 902 osl_getSystemTime( &aReleaseTime ); 903 aReleaseTime.addTime( ::vos::TTimeValue( GetCacheTimeout(), 0 ) ); 904 pNewEntry->SetReleaseTime( aReleaseTime ); 905 } 906 907 maDisplayCache.Insert( pNewEntry, LIST_APPEND ); 908 mnUsedDisplaySize += pNewEntry->GetCacheSize(); 909 bRet = sal_True; 910 } 911 912 return bRet; 913 } 914 915 // ----------------------------------------------------------------------------- 916 917 sal_Bool GraphicCache::CreateDisplayCacheObj( OutputDevice* pOut, const Point& rPt, const Size& rSz, 918 const GraphicObject& rObj, const GraphicAttr& rAttr, 919 const GDIMetaFile& rMtf ) 920 { 921 const sal_uLong nNeededSize = GraphicDisplayCacheEntry::GetNeededSize( pOut, rPt, rSz, rObj, rAttr ); 922 sal_Bool bRet = sal_False; 923 924 if( nNeededSize <= GetMaxObjDisplayCacheSize() ) 925 { 926 if( nNeededSize > GetFreeDisplayCacheSize() ) 927 ImplFreeDisplayCacheSpace( nNeededSize - GetFreeDisplayCacheSize() ); 928 929 GraphicDisplayCacheEntry* pNewEntry = new GraphicDisplayCacheEntry( ImplGetCacheEntry( rObj ), 930 pOut, rPt, rSz, rObj, rAttr, rMtf ); 931 932 if( GetCacheTimeout() ) 933 { 934 ::vos::TTimeValue aReleaseTime; 935 936 osl_getSystemTime( &aReleaseTime ); 937 aReleaseTime.addTime( ::vos::TTimeValue( GetCacheTimeout(), 0 ) ); 938 pNewEntry->SetReleaseTime( aReleaseTime ); 939 } 940 941 maDisplayCache.Insert( pNewEntry, LIST_APPEND ); 942 mnUsedDisplaySize += pNewEntry->GetCacheSize(); 943 bRet = sal_True; 944 } 945 946 return bRet; 947 } 948 949 // ----------------------------------------------------------------------------- 950 951 sal_Bool GraphicCache::DrawDisplayCacheObj( OutputDevice* pOut, const Point& rPt, const Size& rSz, 952 const GraphicObject& rObj, const GraphicAttr& rAttr ) 953 { 954 const Point aPtPixel( pOut->LogicToPixel( rPt ) ); 955 const Size aSzPixel( pOut->LogicToPixel( rSz ) ); 956 const GraphicCacheEntry* pCacheEntry = ImplGetCacheEntry( rObj ); 957 GraphicDisplayCacheEntry* pDisplayCacheEntry = (GraphicDisplayCacheEntry*) maDisplayCache.First(); 958 sal_Bool bRet = sal_False; 959 960 while( !bRet && pDisplayCacheEntry ) 961 { 962 if( pDisplayCacheEntry->Matches( pOut, aPtPixel, aSzPixel, pCacheEntry, rAttr ) ) 963 { 964 ::vos::TTimeValue aReleaseTime; 965 966 // put found object at last used position 967 maDisplayCache.Insert( maDisplayCache.Remove( pDisplayCacheEntry ), LIST_APPEND ); 968 969 if( GetCacheTimeout() ) 970 { 971 osl_getSystemTime( &aReleaseTime ); 972 aReleaseTime.addTime( ::vos::TTimeValue( GetCacheTimeout(), 0 ) ); 973 } 974 975 pDisplayCacheEntry->SetReleaseTime( aReleaseTime ); 976 bRet = sal_True; 977 } 978 else 979 pDisplayCacheEntry = (GraphicDisplayCacheEntry*) maDisplayCache.Next(); 980 } 981 982 if( bRet ) 983 pDisplayCacheEntry->Draw( pOut, rPt, rSz ); 984 985 return bRet; 986 } 987 988 // ----------------------------------------------------------------------------- 989 990 sal_Bool GraphicCache::ImplFreeDisplayCacheSpace( sal_uLong nSizeToFree ) 991 { 992 sal_uLong nFreedSize = 0UL; 993 994 if( nSizeToFree ) 995 { 996 void* pObj = maDisplayCache.First(); 997 998 if( nSizeToFree > mnUsedDisplaySize ) 999 nSizeToFree = mnUsedDisplaySize; 1000 1001 while( pObj ) 1002 { 1003 GraphicDisplayCacheEntry* pCacheObj = (GraphicDisplayCacheEntry*) pObj; 1004 1005 nFreedSize += pCacheObj->GetCacheSize(); 1006 mnUsedDisplaySize -= pCacheObj->GetCacheSize(); 1007 maDisplayCache.Remove( pObj ); 1008 delete pCacheObj; 1009 1010 if( nFreedSize >= nSizeToFree ) 1011 break; 1012 else 1013 pObj = maDisplayCache.GetCurObject(); 1014 } 1015 } 1016 1017 return( nFreedSize >= nSizeToFree ); 1018 } 1019 1020 // ----------------------------------------------------------------------------- 1021 1022 GraphicCacheEntry* GraphicCache::ImplGetCacheEntry( const GraphicObject& rObj ) 1023 { 1024 GraphicCacheEntry* pRet = NULL; 1025 1026 for( void* pObj = maGraphicCache.First(); !pRet && pObj; pObj = maGraphicCache.Next() ) 1027 if( ( (GraphicCacheEntry*) pObj )->HasGraphicObjectReference( rObj ) ) 1028 pRet = (GraphicCacheEntry*) pObj; 1029 1030 return pRet; 1031 } 1032 1033 // ----------------------------------------------------------------------------- 1034 1035 IMPL_LINK( GraphicCache, ReleaseTimeoutHdl, Timer*, pTimer ) 1036 { 1037 pTimer->Stop(); 1038 1039 ::vos::TTimeValue aCurTime; 1040 GraphicDisplayCacheEntry* pDisplayEntry = (GraphicDisplayCacheEntry*) maDisplayCache.First(); 1041 1042 osl_getSystemTime( &aCurTime ); 1043 1044 while( pDisplayEntry ) 1045 { 1046 const ::vos::TTimeValue& rReleaseTime = pDisplayEntry->GetReleaseTime(); 1047 1048 if( !rReleaseTime.isEmpty() && ( rReleaseTime < aCurTime ) ) 1049 { 1050 mnUsedDisplaySize -= pDisplayEntry->GetCacheSize(); 1051 maDisplayCache.Remove( pDisplayEntry ); 1052 delete pDisplayEntry; 1053 pDisplayEntry = (GraphicDisplayCacheEntry*) maDisplayCache.GetCurObject(); 1054 } 1055 else 1056 pDisplayEntry = (GraphicDisplayCacheEntry*) maDisplayCache.Next(); 1057 } 1058 1059 pTimer->Start(); 1060 1061 return 0; 1062 } 1063