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 // #119176# also reset SvgData 412 maSvgData.reset(); 413 } 414 } 415 416 // ----------------------------------------------------------------------------- 417 418 sal_Bool GraphicCacheEntry::FillSwappedGraphicObject( const GraphicObject& rObj, Graphic& rSubstitute ) 419 { 420 sal_Bool bRet; 421 422 if( !mbSwappedAll && rObj.IsSwappedOut() ) 423 { 424 ImplFillSubstitute( rSubstitute ); 425 bRet = sal_True; 426 } 427 else 428 bRet = sal_False; 429 430 return bRet; 431 } 432 433 // ----------------------------------------------------------------------------- 434 435 void GraphicCacheEntry::GraphicObjectWasSwappedIn( const GraphicObject& rObj ) 436 { 437 if( mbSwappedAll ) 438 mbSwappedAll = !ImplInit( rObj ); 439 } 440 441 // ---------------------------- 442 // - GraphicDisplayCacheEntry - 443 // ---------------------------- 444 445 class GraphicDisplayCacheEntry 446 { 447 private: 448 449 ::vos::TTimeValue maReleaseTime; 450 const GraphicCacheEntry* mpRefCacheEntry; 451 GDIMetaFile* mpMtf; 452 BitmapEx* mpBmpEx; 453 GraphicAttr maAttr; 454 Size maOutSizePix; 455 sal_uLong mnCacheSize; 456 sal_uLong mnOutDevDrawMode; 457 sal_uInt16 mnOutDevBitCount; 458 459 public: 460 461 static sal_uLong GetNeededSize( OutputDevice* pOut, const Point& rPt, const Size& rSz, 462 const GraphicObject& rObj, const GraphicAttr& rAttr ); 463 464 public: 465 466 GraphicDisplayCacheEntry( const GraphicCacheEntry* pRefCacheEntry, 467 OutputDevice* pOut, const Point& rPt, const Size& rSz, 468 const GraphicObject& rObj, const GraphicAttr& rAttr, 469 const BitmapEx& rBmpEx ) : 470 mpRefCacheEntry( pRefCacheEntry ), 471 mpMtf( NULL ), mpBmpEx( new BitmapEx( rBmpEx ) ), 472 maAttr( rAttr ), maOutSizePix( pOut->LogicToPixel( rSz ) ), 473 mnCacheSize( GetNeededSize( pOut, rPt, rSz, rObj, rAttr ) ), 474 mnOutDevDrawMode( pOut->GetDrawMode() ), 475 mnOutDevBitCount( pOut->GetBitCount() ) 476 { 477 } 478 479 GraphicDisplayCacheEntry( const GraphicCacheEntry* pRefCacheEntry, 480 OutputDevice* pOut, const Point& rPt, const Size& rSz, 481 const GraphicObject& rObj, const GraphicAttr& rAttr, 482 const GDIMetaFile& rMtf ) : 483 mpRefCacheEntry( pRefCacheEntry ), 484 mpMtf( new GDIMetaFile( rMtf ) ), mpBmpEx( NULL ), 485 maAttr( rAttr ), maOutSizePix( pOut->LogicToPixel( rSz ) ), 486 mnCacheSize( GetNeededSize( pOut, rPt, rSz, rObj, rAttr ) ), 487 mnOutDevDrawMode( pOut->GetDrawMode() ), 488 mnOutDevBitCount( pOut->GetBitCount() ) 489 { 490 } 491 492 493 ~GraphicDisplayCacheEntry(); 494 495 const GraphicAttr& GetAttr() const { return maAttr; } 496 const Size& GetOutputSizePixel() const { return maOutSizePix; } 497 sal_uLong GetCacheSize() const { return mnCacheSize; } 498 const GraphicCacheEntry* GetReferencedCacheEntry() const { return mpRefCacheEntry; } 499 sal_uLong GetOutDevDrawMode() const { return mnOutDevDrawMode; } 500 sal_uInt16 GetOutDevBitCount() const { return mnOutDevBitCount; } 501 502 void SetReleaseTime( const ::vos::TTimeValue& rReleaseTime ) { maReleaseTime = rReleaseTime; } 503 const ::vos::TTimeValue& GetReleaseTime() const { return maReleaseTime; } 504 505 sal_Bool Matches( OutputDevice* pOut, const Point& /*rPtPixel*/, const Size& rSzPixel, 506 const GraphicCacheEntry* pCacheEntry, const GraphicAttr& rAttr ) const 507 { 508 // #i46805# Additional match 509 // criteria: outdev draw mode and 510 // bit count. One cannot reuse 511 // this cache object, if it's 512 // e.g. generated for 513 // DRAWMODE_GRAYBITMAP. 514 return( ( pCacheEntry == mpRefCacheEntry ) && 515 ( maAttr == rAttr ) && 516 ( ( maOutSizePix == rSzPixel ) || ( !maOutSizePix.Width() && !maOutSizePix.Height() ) ) && 517 ( pOut->GetBitCount() == mnOutDevBitCount ) && 518 ( pOut->GetDrawMode() == mnOutDevDrawMode ) ); 519 } 520 521 void Draw( OutputDevice* pOut, const Point& rPt, const Size& rSz ) const; 522 }; 523 524 // ----------------------------------------------------------------------------- 525 526 sal_uLong GraphicDisplayCacheEntry::GetNeededSize( OutputDevice* pOut, const Point& /*rPt*/, const Size& rSz, 527 const GraphicObject& rObj, const GraphicAttr& rAttr ) 528 { 529 const Graphic& rGraphic = rObj.GetGraphic(); 530 const GraphicType eType = rGraphic.GetType(); 531 sal_uLong nNeededSize; 532 533 if( GRAPHIC_BITMAP == eType ) 534 { 535 const Size aOutSizePix( pOut->LogicToPixel( rSz ) ); 536 const long nBitCount = pOut->GetBitCount(); 537 538 if( ( aOutSizePix.Width() > MAX_BMP_EXTENT ) || 539 ( aOutSizePix.Height() > MAX_BMP_EXTENT ) ) 540 { 541 nNeededSize = ULONG_MAX; 542 } 543 else if( nBitCount ) 544 { 545 nNeededSize = aOutSizePix.Width() * aOutSizePix.Height() * nBitCount / 8; 546 547 if( rObj.IsTransparent() || ( rAttr.GetRotation() % 3600 ) ) 548 nNeededSize += nNeededSize / nBitCount; 549 } 550 else 551 { 552 DBG_ERROR( "GraphicDisplayCacheEntry::GetNeededSize(): pOut->GetBitCount() == 0" ); 553 nNeededSize = 256000; 554 } 555 } 556 else if( GRAPHIC_GDIMETAFILE == eType ) 557 nNeededSize = rGraphic.GetSizeBytes(); 558 else 559 nNeededSize = 0; 560 561 return nNeededSize; 562 } 563 564 // ----------------------------------------------------------------------------- 565 566 GraphicDisplayCacheEntry::~GraphicDisplayCacheEntry() 567 { 568 if( mpMtf ) 569 delete mpMtf; 570 571 if( mpBmpEx ) 572 delete mpBmpEx; 573 } 574 575 // ----------------------------------------------------------------------------- 576 577 void GraphicDisplayCacheEntry::Draw( OutputDevice* pOut, const Point& rPt, const Size& rSz ) const 578 { 579 if( mpMtf ) 580 GraphicManager::ImplDraw( pOut, rPt, rSz, *mpMtf, maAttr ); 581 else if( mpBmpEx ) 582 { 583 if( maAttr.IsRotated() ) 584 { 585 Polygon aPoly( Rectangle( rPt, rSz ) ); 586 587 aPoly.Rotate( rPt, maAttr.GetRotation() % 3600 ); 588 const Rectangle aRotBoundRect( aPoly.GetBoundRect() ); 589 pOut->DrawBitmapEx( aRotBoundRect.TopLeft(), aRotBoundRect.GetSize(), *mpBmpEx ); 590 } 591 else 592 pOut->DrawBitmapEx( rPt, rSz, *mpBmpEx ); 593 } 594 } 595 596 // ----------------------- 597 // - GraphicCache - 598 // ----------------------- 599 600 GraphicCache::GraphicCache( GraphicManager& rMgr, sal_uLong nDisplayCacheSize, sal_uLong nMaxObjDisplayCacheSize ) : 601 mrMgr ( rMgr ), 602 mnReleaseTimeoutSeconds ( 0UL ), 603 mnMaxDisplaySize ( nDisplayCacheSize ), 604 mnMaxObjDisplaySize ( nMaxObjDisplayCacheSize ), 605 mnUsedDisplaySize ( 0UL ) 606 { 607 maReleaseTimer.SetTimeoutHdl( LINK( this, GraphicCache, ReleaseTimeoutHdl ) ); 608 maReleaseTimer.SetTimeout( RELEASE_TIMEOUT ); 609 maReleaseTimer.Start(); 610 } 611 612 // ----------------------------------------------------------------------------- 613 614 GraphicCache::~GraphicCache() 615 { 616 DBG_ASSERT( !maGraphicCache.Count(), "GraphicCache::~GraphicCache(): there are some GraphicObjects in cache" ); 617 DBG_ASSERT( !maDisplayCache.Count(), "GraphicCache::~GraphicCache(): there are some GraphicObjects in display cache" ); 618 } 619 620 // ----------------------------------------------------------------------------- 621 622 void GraphicCache::AddGraphicObject( const GraphicObject& rObj, Graphic& rSubstitute, 623 const ByteString* pID, const GraphicObject* pCopyObj ) 624 { 625 sal_Bool bInserted = sal_False; 626 627 if( !rObj.IsSwappedOut() && 628 ( pID || ( pCopyObj && ( pCopyObj->GetType() != GRAPHIC_NONE ) ) || ( rObj.GetType() != GRAPHIC_NONE ) ) ) 629 { 630 if( pCopyObj ) 631 { 632 GraphicCacheEntry* pEntry = static_cast< GraphicCacheEntry* >( maGraphicCache.First() ); 633 634 while( !bInserted && pEntry ) 635 { 636 if( pEntry->HasGraphicObjectReference( *pCopyObj ) ) 637 { 638 pEntry->AddGraphicObjectReference( rObj, rSubstitute ); 639 bInserted = sal_True; 640 } 641 else 642 { 643 pEntry = static_cast< GraphicCacheEntry* >( maGraphicCache.Next() ); 644 } 645 } 646 } 647 648 if( !bInserted ) 649 { 650 GraphicCacheEntry* pEntry = static_cast< GraphicCacheEntry* >( maGraphicCache.First() ); 651 ::std::auto_ptr< GraphicID > apID; 652 653 if( !pID ) 654 { 655 apID.reset( new GraphicID( rObj ) ); 656 } 657 658 while( !bInserted && pEntry ) 659 { 660 const GraphicID& rEntryID = pEntry->GetID(); 661 662 if( pID ) 663 { 664 if( rEntryID.GetIDString() == *pID ) 665 { 666 pEntry->TryToSwapIn(); 667 668 // since pEntry->TryToSwapIn can modify our current list, we have to 669 // iterate from beginning to add a reference to the appropriate 670 // CacheEntry object; after this, quickly jump out of the outer iteration 671 for( pEntry = static_cast< GraphicCacheEntry* >( maGraphicCache.First() ); 672 !bInserted && pEntry; 673 pEntry = static_cast< GraphicCacheEntry* >( maGraphicCache.Next() ) ) 674 { 675 const GraphicID& rID = pEntry->GetID(); 676 677 if( rID.GetIDString() == *pID ) 678 { 679 pEntry->AddGraphicObjectReference( rObj, rSubstitute ); 680 bInserted = sal_True; 681 } 682 } 683 684 if( !bInserted ) 685 { 686 maGraphicCache.Insert( new GraphicCacheEntry( rObj ), LIST_APPEND ); 687 bInserted = sal_True; 688 } 689 } 690 } 691 else 692 { 693 if( rEntryID == *apID ) 694 { 695 pEntry->AddGraphicObjectReference( rObj, rSubstitute ); 696 bInserted = sal_True; 697 } 698 } 699 700 if( !bInserted ) 701 pEntry = static_cast< GraphicCacheEntry* >( maGraphicCache.Next() ); 702 } 703 } 704 } 705 706 if( !bInserted ) 707 maGraphicCache.Insert( new GraphicCacheEntry( rObj ), LIST_APPEND ); 708 } 709 710 // ----------------------------------------------------------------------------- 711 712 void GraphicCache::ReleaseGraphicObject( const GraphicObject& rObj ) 713 { 714 // Release cached object 715 GraphicCacheEntry* pEntry = (GraphicCacheEntry*) maGraphicCache.First(); 716 sal_Bool bRemoved = sal_False; 717 718 while( !bRemoved && pEntry ) 719 { 720 bRemoved = pEntry->ReleaseGraphicObjectReference( rObj ); 721 722 if( bRemoved ) 723 { 724 if( 0 == pEntry->GetGraphicObjectReferenceCount() ) 725 { 726 // if graphic cache entry has no more references, 727 // the corresponding display cache object can be removed 728 GraphicDisplayCacheEntry* pDisplayEntry = (GraphicDisplayCacheEntry*) maDisplayCache.First(); 729 730 while( pDisplayEntry ) 731 { 732 if( pDisplayEntry->GetReferencedCacheEntry() == pEntry ) 733 { 734 mnUsedDisplaySize -= pDisplayEntry->GetCacheSize(); 735 maDisplayCache.Remove( pDisplayEntry ); 736 delete pDisplayEntry; 737 pDisplayEntry = (GraphicDisplayCacheEntry*) maDisplayCache.GetCurObject(); 738 } 739 else 740 pDisplayEntry = (GraphicDisplayCacheEntry*) maDisplayCache.Next(); 741 } 742 743 // delete graphic cache entry 744 maGraphicCache.Remove( (void*) pEntry ); 745 delete pEntry; 746 } 747 } 748 else 749 pEntry = (GraphicCacheEntry*) maGraphicCache.Next(); 750 } 751 752 DBG_ASSERT( bRemoved, "GraphicCache::ReleaseGraphicObject(...): GraphicObject not found in cache" ); 753 } 754 755 // ----------------------------------------------------------------------------- 756 757 void GraphicCache::GraphicObjectWasSwappedOut( const GraphicObject& rObj ) 758 { 759 // notify cache that rObj is swapped out (and can thus be pruned 760 // from the cache) 761 GraphicCacheEntry* pEntry = ImplGetCacheEntry( rObj ); 762 763 if( pEntry ) 764 pEntry->GraphicObjectWasSwappedOut( rObj ); 765 } 766 767 // ----------------------------------------------------------------------------- 768 769 sal_Bool GraphicCache::FillSwappedGraphicObject( const GraphicObject& rObj, Graphic& rSubstitute ) 770 { 771 GraphicCacheEntry* pEntry = ImplGetCacheEntry( rObj ); 772 773 if( !pEntry ) 774 return sal_False; 775 776 return pEntry->FillSwappedGraphicObject( rObj, rSubstitute ); 777 } 778 779 // ----------------------------------------------------------------------------- 780 781 void GraphicCache::GraphicObjectWasSwappedIn( const GraphicObject& rObj ) 782 { 783 GraphicCacheEntry* pEntry = ImplGetCacheEntry( rObj ); 784 785 if( pEntry ) 786 { 787 if( pEntry->GetID().IsEmpty() ) 788 { 789 ReleaseGraphicObject( rObj ); 790 AddGraphicObject( rObj, (Graphic&) rObj.GetGraphic(), NULL, NULL ); 791 } 792 else 793 pEntry->GraphicObjectWasSwappedIn( rObj ); 794 } 795 } 796 797 // ----------------------------------------------------------------------------- 798 799 void GraphicCache::SetMaxDisplayCacheSize( sal_uLong nNewCacheSize ) 800 { 801 mnMaxDisplaySize = nNewCacheSize; 802 803 if( GetMaxDisplayCacheSize() < GetUsedDisplayCacheSize() ) 804 ImplFreeDisplayCacheSpace( GetUsedDisplayCacheSize() - GetMaxDisplayCacheSize() ); 805 } 806 807 // ----------------------------------------------------------------------------- 808 809 void GraphicCache::SetMaxObjDisplayCacheSize( sal_uLong nNewMaxObjSize, sal_Bool bDestroyGreaterCached ) 810 { 811 const sal_Bool bDestroy = ( bDestroyGreaterCached && ( nNewMaxObjSize < mnMaxObjDisplaySize ) ); 812 813 mnMaxObjDisplaySize = Min( nNewMaxObjSize, mnMaxDisplaySize ); 814 815 if( bDestroy ) 816 { 817 GraphicDisplayCacheEntry* pCacheObj = (GraphicDisplayCacheEntry*) maDisplayCache.First(); 818 819 while( pCacheObj ) 820 { 821 if( pCacheObj->GetCacheSize() > mnMaxObjDisplaySize ) 822 { 823 mnUsedDisplaySize -= pCacheObj->GetCacheSize(); 824 maDisplayCache.Remove( pCacheObj ); 825 delete pCacheObj; 826 pCacheObj = (GraphicDisplayCacheEntry*) maDisplayCache.GetCurObject(); 827 } 828 else 829 pCacheObj = (GraphicDisplayCacheEntry*) maDisplayCache.Next(); 830 } 831 } 832 } 833 834 // ----------------------------------------------------------------------------- 835 836 void GraphicCache::SetCacheTimeout( sal_uLong nTimeoutSeconds ) 837 { 838 if( mnReleaseTimeoutSeconds != nTimeoutSeconds ) 839 { 840 GraphicDisplayCacheEntry* pDisplayEntry = (GraphicDisplayCacheEntry*) maDisplayCache.First(); 841 ::vos::TTimeValue aReleaseTime; 842 843 if( ( mnReleaseTimeoutSeconds = nTimeoutSeconds ) != 0 ) 844 { 845 osl_getSystemTime( &aReleaseTime ); 846 aReleaseTime.addTime( ::vos::TTimeValue( nTimeoutSeconds, 0 ) ); 847 } 848 849 while( pDisplayEntry ) 850 { 851 pDisplayEntry->SetReleaseTime( aReleaseTime ); 852 pDisplayEntry = (GraphicDisplayCacheEntry*) maDisplayCache.Next(); 853 } 854 } 855 } 856 857 // ----------------------------------------------------------------------------- 858 859 void GraphicCache::ClearDisplayCache() 860 { 861 for( void* pObj = maDisplayCache.First(); pObj; pObj = maDisplayCache.Next() ) 862 delete (GraphicDisplayCacheEntry*) pObj; 863 864 maDisplayCache.Clear(); 865 mnUsedDisplaySize = 0UL; 866 } 867 868 // ----------------------------------------------------------------------------- 869 870 sal_Bool GraphicCache::IsDisplayCacheable( OutputDevice* pOut, const Point& rPt, const Size& rSz, 871 const GraphicObject& rObj, const GraphicAttr& rAttr ) const 872 { 873 return( GraphicDisplayCacheEntry::GetNeededSize( pOut, rPt, rSz, rObj, rAttr ) <= 874 GetMaxObjDisplayCacheSize() ); 875 } 876 877 // ----------------------------------------------------------------------------- 878 879 sal_Bool GraphicCache::IsInDisplayCache( OutputDevice* pOut, const Point& rPt, const Size& rSz, 880 const GraphicObject& rObj, const GraphicAttr& rAttr ) const 881 { 882 const Point aPtPixel( pOut->LogicToPixel( rPt ) ); 883 const Size aSzPixel( pOut->LogicToPixel( rSz ) ); 884 const GraphicCacheEntry* pCacheEntry = ( (GraphicCache*) this )->ImplGetCacheEntry( rObj ); 885 //GraphicDisplayCacheEntry* pDisplayEntry = (GraphicDisplayCacheEntry*) ( (GraphicCache*) this )->maDisplayCache.First(); // -Wall removed .... 886 sal_Bool bFound = sal_False; 887 888 if( pCacheEntry ) 889 { 890 for( long i = 0, nCount = maDisplayCache.Count(); !bFound && ( i < nCount ); i++ ) 891 if( ( (GraphicDisplayCacheEntry*) maDisplayCache.GetObject( i ) )->Matches( pOut, aPtPixel, aSzPixel, pCacheEntry, rAttr ) ) 892 bFound = sal_True; 893 } 894 895 return bFound; 896 } 897 898 // ----------------------------------------------------------------------------- 899 900 ByteString GraphicCache::GetUniqueID( const GraphicObject& rObj ) const 901 { 902 ByteString aRet; 903 GraphicCacheEntry* pEntry = ( (GraphicCache*) this )->ImplGetCacheEntry( rObj ); 904 905 // ensure that the entry is correctly initialized (it has to be read at least once) 906 if( pEntry && pEntry->GetID().IsEmpty() ) 907 pEntry->TryToSwapIn(); 908 909 // do another call to ImplGetCacheEntry in case of modified entry list 910 pEntry = ( (GraphicCache*) this )->ImplGetCacheEntry( rObj ); 911 912 if( pEntry ) 913 aRet = pEntry->GetID().GetIDString(); 914 915 return aRet; 916 } 917 918 // ----------------------------------------------------------------------------- 919 920 sal_Bool GraphicCache::CreateDisplayCacheObj( OutputDevice* pOut, const Point& rPt, const Size& rSz, 921 const GraphicObject& rObj, const GraphicAttr& rAttr, 922 const BitmapEx& rBmpEx ) 923 { 924 const sal_uLong nNeededSize = GraphicDisplayCacheEntry::GetNeededSize( pOut, rPt, rSz, rObj, rAttr ); 925 sal_Bool bRet = sal_False; 926 927 if( nNeededSize <= GetMaxObjDisplayCacheSize() ) 928 { 929 if( nNeededSize > GetFreeDisplayCacheSize() ) 930 ImplFreeDisplayCacheSpace( nNeededSize - GetFreeDisplayCacheSize() ); 931 932 GraphicDisplayCacheEntry* pNewEntry = new GraphicDisplayCacheEntry( ImplGetCacheEntry( rObj ), 933 pOut, rPt, rSz, rObj, rAttr, rBmpEx ); 934 935 if( GetCacheTimeout() ) 936 { 937 ::vos::TTimeValue aReleaseTime; 938 939 osl_getSystemTime( &aReleaseTime ); 940 aReleaseTime.addTime( ::vos::TTimeValue( GetCacheTimeout(), 0 ) ); 941 pNewEntry->SetReleaseTime( aReleaseTime ); 942 } 943 944 maDisplayCache.Insert( pNewEntry, LIST_APPEND ); 945 mnUsedDisplaySize += pNewEntry->GetCacheSize(); 946 bRet = sal_True; 947 } 948 949 return bRet; 950 } 951 952 // ----------------------------------------------------------------------------- 953 954 sal_Bool GraphicCache::CreateDisplayCacheObj( OutputDevice* pOut, const Point& rPt, const Size& rSz, 955 const GraphicObject& rObj, const GraphicAttr& rAttr, 956 const GDIMetaFile& rMtf ) 957 { 958 const sal_uLong nNeededSize = GraphicDisplayCacheEntry::GetNeededSize( pOut, rPt, rSz, rObj, rAttr ); 959 sal_Bool bRet = sal_False; 960 961 if( nNeededSize <= GetMaxObjDisplayCacheSize() ) 962 { 963 if( nNeededSize > GetFreeDisplayCacheSize() ) 964 ImplFreeDisplayCacheSpace( nNeededSize - GetFreeDisplayCacheSize() ); 965 966 GraphicDisplayCacheEntry* pNewEntry = new GraphicDisplayCacheEntry( ImplGetCacheEntry( rObj ), 967 pOut, rPt, rSz, rObj, rAttr, rMtf ); 968 969 if( GetCacheTimeout() ) 970 { 971 ::vos::TTimeValue aReleaseTime; 972 973 osl_getSystemTime( &aReleaseTime ); 974 aReleaseTime.addTime( ::vos::TTimeValue( GetCacheTimeout(), 0 ) ); 975 pNewEntry->SetReleaseTime( aReleaseTime ); 976 } 977 978 maDisplayCache.Insert( pNewEntry, LIST_APPEND ); 979 mnUsedDisplaySize += pNewEntry->GetCacheSize(); 980 bRet = sal_True; 981 } 982 983 return bRet; 984 } 985 986 // ----------------------------------------------------------------------------- 987 988 sal_Bool GraphicCache::DrawDisplayCacheObj( OutputDevice* pOut, const Point& rPt, const Size& rSz, 989 const GraphicObject& rObj, const GraphicAttr& rAttr ) 990 { 991 const Point aPtPixel( pOut->LogicToPixel( rPt ) ); 992 const Size aSzPixel( pOut->LogicToPixel( rSz ) ); 993 const GraphicCacheEntry* pCacheEntry = ImplGetCacheEntry( rObj ); 994 GraphicDisplayCacheEntry* pDisplayCacheEntry = (GraphicDisplayCacheEntry*) maDisplayCache.First(); 995 sal_Bool bRet = sal_False; 996 997 while( !bRet && pDisplayCacheEntry ) 998 { 999 if( pDisplayCacheEntry->Matches( pOut, aPtPixel, aSzPixel, pCacheEntry, rAttr ) ) 1000 { 1001 ::vos::TTimeValue aReleaseTime; 1002 1003 // put found object at last used position 1004 maDisplayCache.Insert( maDisplayCache.Remove( pDisplayCacheEntry ), LIST_APPEND ); 1005 1006 if( GetCacheTimeout() ) 1007 { 1008 osl_getSystemTime( &aReleaseTime ); 1009 aReleaseTime.addTime( ::vos::TTimeValue( GetCacheTimeout(), 0 ) ); 1010 } 1011 1012 pDisplayCacheEntry->SetReleaseTime( aReleaseTime ); 1013 bRet = sal_True; 1014 } 1015 else 1016 pDisplayCacheEntry = (GraphicDisplayCacheEntry*) maDisplayCache.Next(); 1017 } 1018 1019 if( bRet ) 1020 pDisplayCacheEntry->Draw( pOut, rPt, rSz ); 1021 1022 return bRet; 1023 } 1024 1025 // ----------------------------------------------------------------------------- 1026 1027 sal_Bool GraphicCache::ImplFreeDisplayCacheSpace( sal_uLong nSizeToFree ) 1028 { 1029 sal_uLong nFreedSize = 0UL; 1030 1031 if( nSizeToFree ) 1032 { 1033 void* pObj = maDisplayCache.First(); 1034 1035 if( nSizeToFree > mnUsedDisplaySize ) 1036 nSizeToFree = mnUsedDisplaySize; 1037 1038 while( pObj ) 1039 { 1040 GraphicDisplayCacheEntry* pCacheObj = (GraphicDisplayCacheEntry*) pObj; 1041 1042 nFreedSize += pCacheObj->GetCacheSize(); 1043 mnUsedDisplaySize -= pCacheObj->GetCacheSize(); 1044 maDisplayCache.Remove( pObj ); 1045 delete pCacheObj; 1046 1047 if( nFreedSize >= nSizeToFree ) 1048 break; 1049 else 1050 pObj = maDisplayCache.GetCurObject(); 1051 } 1052 } 1053 1054 return( nFreedSize >= nSizeToFree ); 1055 } 1056 1057 // ----------------------------------------------------------------------------- 1058 1059 GraphicCacheEntry* GraphicCache::ImplGetCacheEntry( const GraphicObject& rObj ) 1060 { 1061 GraphicCacheEntry* pRet = NULL; 1062 1063 for( void* pObj = maGraphicCache.First(); !pRet && pObj; pObj = maGraphicCache.Next() ) 1064 if( ( (GraphicCacheEntry*) pObj )->HasGraphicObjectReference( rObj ) ) 1065 pRet = (GraphicCacheEntry*) pObj; 1066 1067 return pRet; 1068 } 1069 1070 // ----------------------------------------------------------------------------- 1071 1072 IMPL_LINK( GraphicCache, ReleaseTimeoutHdl, Timer*, pTimer ) 1073 { 1074 pTimer->Stop(); 1075 1076 ::vos::TTimeValue aCurTime; 1077 GraphicDisplayCacheEntry* pDisplayEntry = (GraphicDisplayCacheEntry*) maDisplayCache.First(); 1078 1079 osl_getSystemTime( &aCurTime ); 1080 1081 while( pDisplayEntry ) 1082 { 1083 const ::vos::TTimeValue& rReleaseTime = pDisplayEntry->GetReleaseTime(); 1084 1085 if( !rReleaseTime.isEmpty() && ( rReleaseTime < aCurTime ) ) 1086 { 1087 mnUsedDisplaySize -= pDisplayEntry->GetCacheSize(); 1088 maDisplayCache.Remove( pDisplayEntry ); 1089 delete pDisplayEntry; 1090 pDisplayEntry = (GraphicDisplayCacheEntry*) maDisplayCache.GetCurObject(); 1091 } 1092 else 1093 pDisplayEntry = (GraphicDisplayCacheEntry*) maDisplayCache.Next(); 1094 } 1095 1096 pTimer->Start(); 1097 1098 return 0; 1099 } 1100