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