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