LCOV - code coverage report
Current view: top level - libreoffice/svtools/source/graphic - grfcache.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 367 533 68.9 %
Date: 2012-12-27 Functions: 41 50 82.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include <salhelper/timer.hxx>
      21             : #include <svtools/grfmgr.hxx>
      22             : #include <tools/debug.hxx>
      23             : #include <vcl/metaact.hxx>
      24             : #include <vcl/outdev.hxx>
      25             : #include <tools/poly.hxx>
      26             : #include <rtl/strbuf.hxx>
      27             : #include "grfcache.hxx"
      28             : #include <rtl/crc.h>
      29             : #include <memory>
      30             : 
      31             : // -----------
      32             : // - Defines -
      33             : // -----------
      34             : 
      35             : #define RELEASE_TIMEOUT 10000
      36             : #define MAX_BMP_EXTENT  4096
      37             : 
      38             : // -----------
      39             : // - statics -
      40             : // -----------
      41             : 
      42             : static const char aHexData[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
      43             : 
      44             : // -------------
      45             : // - GraphicID -
      46             : // -------------
      47             : 
      48             : class GraphicID
      49             : {
      50             : private:
      51             : 
      52             :     sal_uInt32  mnID1;
      53             :     sal_uInt32  mnID2;
      54             :     sal_uInt32  mnID3;
      55             :     sal_uInt32  mnID4;
      56             : 
      57             :                 GraphicID();
      58             : 
      59             : public:
      60             : 
      61             : 
      62             :                 GraphicID( const GraphicObject& rObj );
      63        1544 :                 ~GraphicID() {}
      64             : 
      65        2157 :     sal_Bool        operator==( const GraphicID& rID ) const
      66             :                 {
      67             :                     return( rID.mnID1 == mnID1 && rID.mnID2 == mnID2 &&
      68        2157 :                             rID.mnID3 == mnID3 && rID.mnID4 == mnID4 );
      69             :                 }
      70             : 
      71             :     rtl::OString GetIDString() const;
      72         132 :     sal_Bool        IsEmpty() const { return( 0 == mnID4 ); }
      73             : };
      74             : 
      75             : // -----------------------------------------------------------------------------
      76             : 
      77        1774 : GraphicID::GraphicID( const GraphicObject& rObj )
      78             : {
      79        1774 :     const Graphic& rGraphic = rObj.GetGraphic();
      80             : 
      81        1774 :     mnID1 = ( (sal_uLong) rGraphic.GetType() ) << 28;
      82             : 
      83        1774 :     switch( rGraphic.GetType() )
      84             :     {
      85             :         case( GRAPHIC_BITMAP ):
      86             :         {
      87         100 :             if(rGraphic.getSvgData().get())
      88             :             {
      89           0 :                 const SvgDataPtr& rSvgDataPtr = rGraphic.getSvgData();
      90           0 :                 const basegfx::B2DRange& rRange = rSvgDataPtr->getRange();
      91             : 
      92           0 :                 mnID1 |= rSvgDataPtr->getSvgDataArrayLength();
      93           0 :                 mnID2 = basegfx::fround(rRange.getWidth());
      94           0 :                 mnID3 = basegfx::fround(rRange.getHeight());
      95           0 :                 mnID4 = rtl_crc32(0, rSvgDataPtr->getSvgDataArray().get(), rSvgDataPtr->getSvgDataArrayLength());
      96             :             }
      97         100 :             else if( rGraphic.IsAnimated() )
      98             :             {
      99           0 :                 const Animation aAnimation( rGraphic.GetAnimation() );
     100             : 
     101           0 :                 mnID1 |= ( aAnimation.Count() & 0x0fffffff );
     102           0 :                 mnID2 = aAnimation.GetDisplaySizePixel().Width();
     103           0 :                 mnID3 = aAnimation.GetDisplaySizePixel().Height();
     104           0 :                 mnID4 = rGraphic.GetChecksum();
     105             :             }
     106             :             else
     107             :             {
     108         100 :                 const BitmapEx aBmpEx( rGraphic.GetBitmapEx() );
     109             : 
     110         100 :                 mnID1 |= ( ( ( (sal_uLong) aBmpEx.GetTransparentType() << 8 ) | ( aBmpEx.IsAlpha() ? 1 : 0 ) ) & 0x0fffffff );
     111         100 :                 mnID2 = aBmpEx.GetSizePixel().Width();
     112         100 :                 mnID3 = aBmpEx.GetSizePixel().Height();
     113         100 :                 mnID4 = rGraphic.GetChecksum();
     114             :             }
     115             :         }
     116         100 :         break;
     117             : 
     118             :         case( GRAPHIC_GDIMETAFILE ):
     119             :         {
     120          26 :             const GDIMetaFile& rMtf = rGraphic.GetGDIMetaFile();
     121             : 
     122          26 :             mnID1 |= ( rMtf.GetActionSize() & 0x0fffffff );
     123          26 :             mnID2 = rMtf.GetPrefSize().Width();
     124          26 :             mnID3 = rMtf.GetPrefSize().Height();
     125          26 :             mnID4 = rGraphic.GetChecksum();
     126             :         }
     127          26 :         break;
     128             : 
     129             :         default:
     130        1648 :             mnID2 = mnID3 = mnID4 = 0;
     131        1648 :         break;
     132             :     }
     133        1774 : }
     134             : 
     135             : // -----------------------------------------------------------------------------
     136             : 
     137        3800 : rtl::OString GraphicID::GetIDString() const
     138             : {
     139        3800 :     rtl::OStringBuffer aHexStr;
     140        3800 :     sal_Int32 nShift, nIndex = 0;
     141        3800 :     aHexStr.setLength(32);
     142             : 
     143       34200 :     for( nShift = 28; nShift >= 0; nShift -= 4 )
     144       30400 :         aHexStr[nIndex++] = aHexData[ ( mnID1 >> (sal_uInt32) nShift ) & 0xf ];
     145             : 
     146       34200 :     for( nShift = 28; nShift >= 0; nShift -= 4 )
     147       30400 :         aHexStr[nIndex++] = aHexData[ ( mnID2 >> (sal_uInt32) nShift ) & 0xf ];
     148             : 
     149       34200 :     for( nShift = 28; nShift >= 0; nShift -= 4 )
     150       30400 :         aHexStr[nIndex++] = aHexData[ ( mnID3 >> (sal_uInt32) nShift ) & 0xf ];
     151             : 
     152       34200 :     for( nShift = 28; nShift >= 0; nShift -= 4 )
     153       30400 :         aHexStr[nIndex++] = aHexData[ ( mnID4 >> (sal_uInt32) nShift ) & 0xf ];
     154             : 
     155        3800 :     return aHexStr.makeStringAndClear();
     156             : }
     157             : 
     158             : // ---------------------
     159             : // - GraphicCacheEntry -
     160             : // ---------------------
     161             : 
     162             : class GraphicCacheEntry
     163             : {
     164             : private:
     165             : 
     166             :     GraphicObjectList_impl  maGraphicObjectList;
     167             : 
     168             :     GraphicID           maID;
     169             :     GfxLink             maGfxLink;
     170             :     BitmapEx*           mpBmpEx;
     171             :     GDIMetaFile*        mpMtf;
     172             :     Animation*          mpAnimation;
     173             :     bool                mbSwappedAll;
     174             : 
     175             :     // SvgData support
     176             :     SvgDataPtr          maSvgData;
     177             : 
     178             :     bool                ImplInit( const GraphicObject& rObj );
     179             :     bool                ImplMatches( const GraphicObject& rObj ) const { return( GraphicID( rObj ) == maID ); }
     180             :     void                ImplFillSubstitute( Graphic& rSubstitute );
     181             : 
     182             : public:
     183             : 
     184             :                         GraphicCacheEntry( const GraphicObject& rObj );
     185             :                         ~GraphicCacheEntry();
     186             : 
     187        6089 :     const GraphicID&    GetID() const { return maID; }
     188             : 
     189             :     void                AddGraphicObjectReference( const GraphicObject& rObj, Graphic& rSubstitute );
     190             :     bool                ReleaseGraphicObjectReference( const GraphicObject& rObj );
     191        1768 :     size_t              GetGraphicObjectReferenceCount() { return maGraphicObjectList.size(); }
     192             :     bool                HasGraphicObjectReference( const GraphicObject& rObj );
     193             : 
     194             :     void                TryToSwapIn();
     195             :     void                GraphicObjectWasSwappedOut( const GraphicObject& rObj );
     196             :     bool                FillSwappedGraphicObject( const GraphicObject& rObj, Graphic& rSubstitute );
     197             :     void                GraphicObjectWasSwappedIn( const GraphicObject& rObj );
     198             : };
     199             : 
     200             : // -----------------------------------------------------------------------------
     201             : 
     202        1649 : GraphicCacheEntry::GraphicCacheEntry( const GraphicObject& rObj ) :
     203             :     maID            ( rObj ),
     204             :     mpBmpEx         ( NULL ),
     205             :     mpMtf           ( NULL ),
     206             :     mpAnimation     ( NULL ),
     207        1649 :     mbSwappedAll    ( true )
     208             : {
     209        1649 :     mbSwappedAll = !ImplInit( rObj );
     210        1649 :     maGraphicObjectList.push_back( (GraphicObject*)&rObj );
     211        1649 : }
     212             : 
     213             : // -----------------------------------------------------------------------------
     214             : 
     215        2838 : GraphicCacheEntry::~GraphicCacheEntry()
     216             : {
     217             :     DBG_ASSERT(
     218             :         maGraphicObjectList.empty(),
     219             :         "GraphicCacheEntry::~GraphicCacheEntry(): Not all GraphicObjects are removed from this entry"
     220             :     );
     221             : 
     222        1419 :     delete mpBmpEx;
     223        1419 :     delete mpMtf;
     224        1419 :     delete mpAnimation;
     225        1419 : }
     226             : 
     227             : // -----------------------------------------------------------------------------
     228             : 
     229        1652 : bool GraphicCacheEntry::ImplInit( const GraphicObject& rObj )
     230             : {
     231        1652 :     bool bRet = false;
     232             : 
     233        1652 :     if( !rObj.IsSwappedOut() )
     234             :     {
     235        1652 :         const Graphic& rGraphic = rObj.GetGraphic();
     236             : 
     237        1652 :         if( mpBmpEx )
     238           0 :             delete mpBmpEx, mpBmpEx = NULL;
     239             : 
     240        1652 :         if( mpMtf )
     241           0 :             delete mpMtf, mpMtf = NULL;
     242             : 
     243        1652 :         if( mpAnimation )
     244           0 :             delete mpAnimation, mpAnimation = NULL;
     245             : 
     246        1652 :         switch( rGraphic.GetType() )
     247             :         {
     248             :             case( GRAPHIC_BITMAP ):
     249             :             {
     250          29 :                 if(rGraphic.getSvgData().get())
     251             :                 {
     252           0 :                     maSvgData = rGraphic.getSvgData();
     253             :                 }
     254          29 :                 else if( rGraphic.IsAnimated() )
     255             :                 {
     256           0 :                     mpAnimation = new Animation( rGraphic.GetAnimation() );
     257             :                 }
     258             :                 else
     259             :                 {
     260          29 :                     mpBmpEx = new BitmapEx( rGraphic.GetBitmapEx() );
     261             :                 }
     262             :             }
     263          29 :             break;
     264             : 
     265             :             case( GRAPHIC_GDIMETAFILE ):
     266             :             {
     267          12 :                 mpMtf = new GDIMetaFile( rGraphic.GetGDIMetaFile() );
     268             :             }
     269          12 :             break;
     270             : 
     271             :             default:
     272             :                 DBG_ASSERT( GetID().IsEmpty(), "GraphicCacheEntry::ImplInit: Could not initialize graphic! (=>KA)" );
     273        1611 :             break;
     274             :         }
     275             : 
     276        1652 :         if( rGraphic.IsLink() )
     277          36 :             maGfxLink = ( (Graphic&) rGraphic ).GetLink();
     278             :         else
     279        1616 :             maGfxLink = GfxLink();
     280             : 
     281        1652 :         bRet = true;
     282             :     }
     283             : 
     284        1652 :     return bRet;
     285             : }
     286             : 
     287             : // -----------------------------------------------------------------------------
     288             : 
     289         370 : void GraphicCacheEntry::ImplFillSubstitute( Graphic& rSubstitute )
     290             : {
     291             :     // create substitute for graphic;
     292         370 :     const Size          aPrefSize( rSubstitute.GetPrefSize() );
     293         370 :     const MapMode       aPrefMapMode( rSubstitute.GetPrefMapMode() );
     294         370 :     const Link          aAnimationNotifyHdl( rSubstitute.GetAnimationNotifyHdl() );
     295         370 :     const String        aDocFileName( rSubstitute.GetDocFileName() );
     296         370 :     const sal_uLong     nDocFilePos = rSubstitute.GetDocFilePos();
     297         370 :     const GraphicType   eOldType = rSubstitute.GetType();
     298         370 :     const bool          bDefaultType = ( rSubstitute.GetType() == GRAPHIC_DEFAULT );
     299             : 
     300         370 :     if( rSubstitute.IsLink() && ( GFX_LINK_TYPE_NONE == maGfxLink.GetType() ) )
     301           0 :         maGfxLink = rSubstitute.GetLink();
     302             : 
     303         370 :     if(maSvgData.get())
     304             :     {
     305           0 :         rSubstitute = maSvgData;
     306             :     }
     307         370 :     else if( mpBmpEx )
     308             :     {
     309         323 :         rSubstitute = *mpBmpEx;
     310             :     }
     311          47 :     else if( mpAnimation )
     312             :     {
     313           0 :         rSubstitute = *mpAnimation;
     314             :     }
     315          47 :     else if( mpMtf )
     316             :     {
     317          16 :         rSubstitute = *mpMtf;
     318             :     }
     319             :     else
     320             :     {
     321          31 :         rSubstitute.Clear();
     322             :     }
     323             : 
     324         370 :     if( eOldType != GRAPHIC_NONE )
     325             :     {
     326         313 :         rSubstitute.SetPrefSize( aPrefSize );
     327         313 :         rSubstitute.SetPrefMapMode( aPrefMapMode );
     328         313 :         rSubstitute.SetAnimationNotifyHdl( aAnimationNotifyHdl );
     329         313 :         rSubstitute.SetDocFileName( aDocFileName, nDocFilePos );
     330             :     }
     331             : 
     332         370 :     if( GFX_LINK_TYPE_NONE != maGfxLink.GetType() )
     333             :     {
     334         161 :         rSubstitute.SetLink( maGfxLink );
     335             :     }
     336             : 
     337         370 :     if( bDefaultType )
     338             :     {
     339          31 :         rSubstitute.SetDefaultType();
     340         370 :     }
     341         370 : }
     342             : 
     343             : // -----------------------------------------------------------------------------
     344             : 
     345         370 : void GraphicCacheEntry::AddGraphicObjectReference( const GraphicObject& rObj, Graphic& rSubstitute )
     346             : {
     347         370 :     if( mbSwappedAll )
     348           3 :         mbSwappedAll = !ImplInit( rObj );
     349             : 
     350         370 :     ImplFillSubstitute( rSubstitute );
     351         370 :     maGraphicObjectList.push_back( (GraphicObject*) &rObj );
     352         370 : }
     353             : 
     354             : // -----------------------------------------------------------------------------
     355             : 
     356       28979 : bool GraphicCacheEntry::ReleaseGraphicObjectReference( const GraphicObject& rObj )
     357             : {
     358      179751 :     for(
     359       28979 :         GraphicObjectList_impl::iterator it = maGraphicObjectList.begin();
     360      119834 :         it != maGraphicObjectList.end();
     361             :         ++it
     362             :     ) {
     363       32706 :         if( &rObj == *it )
     364             :         {
     365        1768 :             maGraphicObjectList.erase( it );
     366        1768 :             return true;
     367             :         }
     368             :     }
     369             : 
     370       27211 :     return false;
     371             : }
     372             : 
     373             : // -----------------------------------------------------------------------------
     374             : 
     375        8179 : bool GraphicCacheEntry::HasGraphicObjectReference( const GraphicObject& rObj )
     376             : {
     377        8179 :     bool bRet = false;
     378             : 
     379       17880 :     for( size_t i = 0, n = maGraphicObjectList.size(); ( i < n ) && !bRet; ++i )
     380        9701 :         if( &rObj == maGraphicObjectList[ i ] )
     381         549 :             bRet = true;
     382             : 
     383        8179 :     return bRet;
     384             : }
     385             : 
     386             : // -----------------------------------------------------------------------------
     387             : 
     388          57 : void GraphicCacheEntry::TryToSwapIn()
     389             : {
     390          57 :     if( mbSwappedAll && !maGraphicObjectList.empty() )
     391           0 :         maGraphicObjectList.front()->FireSwapInRequest();
     392          57 : }
     393             : 
     394             : // -----------------------------------------------------------------------------
     395             : 
     396          13 : void GraphicCacheEntry::GraphicObjectWasSwappedOut( const GraphicObject& /*rObj*/ )
     397             : {
     398          13 :     mbSwappedAll = true;
     399             : 
     400          30 :     for( size_t i = 0, n = maGraphicObjectList.size(); ( i < n ) && mbSwappedAll; ++i )
     401          17 :         if( !maGraphicObjectList[ i ]->IsSwappedOut() )
     402           0 :             mbSwappedAll = false;
     403             : 
     404          13 :     if( mbSwappedAll )
     405             :     {
     406          13 :         delete mpBmpEx, mpBmpEx = NULL;
     407          13 :         mpMtf = NULL; // No need to delete it as it has already been dereferenced
     408          13 :         delete mpAnimation, mpAnimation = NULL;
     409             : 
     410             :         // #119176# also reset SvgData
     411          13 :         maSvgData.reset();
     412             :     }
     413          13 : }
     414             : 
     415             : // -----------------------------------------------------------------------------
     416             : 
     417           0 : bool GraphicCacheEntry::FillSwappedGraphicObject( const GraphicObject& rObj, Graphic& rSubstitute )
     418             : {
     419           0 :     bool bRet = false;
     420             : 
     421           0 :     if( !mbSwappedAll && rObj.IsSwappedOut() )
     422             :     {
     423           0 :         ImplFillSubstitute( rSubstitute );
     424           0 :         bRet = true;
     425             :     }
     426             : 
     427           0 :     return bRet;
     428             : }
     429             : 
     430             : // -----------------------------------------------------------------------------
     431             : 
     432           0 : void GraphicCacheEntry::GraphicObjectWasSwappedIn( const GraphicObject& rObj )
     433             : {
     434           0 :     if( mbSwappedAll )
     435           0 :         mbSwappedAll = !ImplInit( rObj );
     436           0 : }
     437             : 
     438             : // ----------------------------
     439             : // - GraphicDisplayCacheEntry -
     440             : // ----------------------------
     441             : 
     442             : class GraphicDisplayCacheEntry
     443             : {
     444             : private:
     445             : 
     446             :     ::salhelper::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             :     static bool IsCacheableAsBitmap( const GDIMetaFile& rMtf, OutputDevice* pOut, const Size& rSz );
     457             : 
     458             : public:
     459             : 
     460             :     static sal_uLong                GetNeededSize( OutputDevice* pOut, const Point& rPt, const Size& rSz,
     461             :                                                const GraphicObject& rObj, const GraphicAttr& rAttr );
     462             : 
     463             : public:
     464             : 
     465           7 :                                 GraphicDisplayCacheEntry( const GraphicCacheEntry* pRefCacheEntry,
     466             :                                                           OutputDevice* pOut, const Point& rPt, const Size& rSz,
     467             :                                                           const GraphicObject& rObj, const GraphicAttr& rAttr,
     468             :                                                           const BitmapEx& rBmpEx ) :
     469             :                                     mpRefCacheEntry( pRefCacheEntry ),
     470           7 :                                     mpMtf( NULL ), mpBmpEx( new BitmapEx( rBmpEx ) ),
     471             :                                     maAttr( rAttr ), maOutSizePix( pOut->LogicToPixel( rSz ) ),
     472           7 :                                     mnCacheSize( GetNeededSize( pOut, rPt, rSz, rObj, rAttr ) ),
     473           7 :                                     mnOutDevDrawMode( pOut->GetDrawMode() ),
     474          28 :                                     mnOutDevBitCount( pOut->GetBitCount() )
     475             :                                     {
     476           7 :                                     }
     477             : 
     478           1 :                                 GraphicDisplayCacheEntry( const GraphicCacheEntry* pRefCacheEntry,
     479             :                                                           OutputDevice* pOut, const Point& rPt, const Size& rSz,
     480             :                                                           const GraphicObject& rObj, const GraphicAttr& rAttr,
     481             :                                                           const GDIMetaFile& rMtf ) :
     482             :                                     mpRefCacheEntry( pRefCacheEntry ),
     483           1 :                                     mpMtf( new GDIMetaFile( rMtf ) ), mpBmpEx( NULL ),
     484             :                                     maAttr( rAttr ), maOutSizePix( pOut->LogicToPixel( rSz ) ),
     485           1 :                                     mnCacheSize( GetNeededSize( pOut, rPt, rSz, rObj, rAttr ) ),
     486           1 :                                     mnOutDevDrawMode( pOut->GetDrawMode() ),
     487           4 :                                     mnOutDevBitCount( pOut->GetBitCount() )
     488             :                                     {
     489           1 :                                     }
     490             : 
     491             : 
     492             :                                 ~GraphicDisplayCacheEntry();
     493             : 
     494             :     const GraphicAttr&          GetAttr() const { return maAttr; }
     495             :     const Size&                 GetOutputSizePixel() const { return maOutSizePix; }
     496           8 :     sal_uLong                   GetCacheSize() const { return mnCacheSize; }
     497         645 :     const GraphicCacheEntry*    GetReferencedCacheEntry() const { return mpRefCacheEntry; }
     498             :     sal_uLong                   GetOutDevDrawMode() const { return mnOutDevDrawMode; }
     499             :     sal_uInt16              GetOutDevBitCount() const { return mnOutDevBitCount; }
     500             : 
     501          16 :     void                        SetReleaseTime( const ::salhelper::TTimeValue& rReleaseTime ) { maReleaseTime = rReleaseTime; }
     502          26 :     const ::salhelper::TTimeValue&    GetReleaseTime() const { return maReleaseTime; }
     503             : 
     504         128 :     sal_Bool                        Matches( OutputDevice* pOut, const Point& /*rPtPixel*/, const Size& rSzPixel,
     505             :                                          const GraphicCacheEntry* pCacheEntry, const GraphicAttr& rAttr ) const
     506             :                                 {
     507             :                                     // #i46805# Additional match
     508             :                                     // criteria: outdev draw mode and
     509             :                                     // bit count. One cannot reuse
     510             :                                     // this cache object, if it's
     511             :                                     // e.g. generated for
     512             :                                     // DRAWMODE_GRAYBITMAP.
     513             :                                     return( ( pCacheEntry == mpRefCacheEntry ) &&
     514          32 :                                             ( maAttr == rAttr ) &&
     515          48 :                                             ( ( maOutSizePix == rSzPixel ) || ( !maOutSizePix.Width() && !maOutSizePix.Height() ) ) &&
     516          16 :                                             ( pOut->GetBitCount() == mnOutDevBitCount ) &&
     517         224 :                                             ( pOut->GetDrawMode() == mnOutDevDrawMode ) );
     518             :                                 }
     519             : 
     520             :     void                        Draw( OutputDevice* pOut, const Point& rPt, const Size& rSz ) const;
     521             : };
     522             : 
     523             : // -----------------------------------------------------------------------------
     524             : 
     525             : // This whole function is based on checkMetadataBitmap() from grfmgr2.cxx, see that one for details.
     526             : // If you do changes here, change the original function too.
     527           0 : static void checkMetadataBitmap( const BitmapEx& rBmpEx,
     528             :                                  Point    /*rSrcPoint*/,
     529             :                                  Size     rSrcSize,
     530             :                                  const Point&    rDestPoint,
     531             :                                  const Size&     rDestSize,
     532             :                                  const Size&     rRefSize,
     533             :                                  bool&           o_rbNonBitmapActionEncountered )
     534             : {
     535           0 :     if( rSrcSize == Size())
     536           0 :         rSrcSize = rBmpEx.GetSizePixel();
     537             : 
     538           0 :     if( rDestPoint != Point( 0, 0 ))
     539             :     {
     540           0 :         o_rbNonBitmapActionEncountered = true;
     541           0 :         return;
     542             :     }
     543           0 :     if( rDestSize != rRefSize )
     544           0 :     {    if( rBmpEx.GetSizePixel().Width() > 100 && rBmpEx.GetSizePixel().Height() > 100
     545           0 :             && abs( rDestSize.Width() - rRefSize.Width()) < 5
     546           0 :             && abs( rDestSize.Height() - rRefSize.Height()) < 5 )
     547             :             ; // ok, assume it's close enough
     548             :         else
     549             :         {  // fall back to mtf rendering
     550           0 :             o_rbNonBitmapActionEncountered = true;
     551           0 :             return;
     552             :         }
     553             :     }
     554             : }
     555             : 
     556             : // This function is based on GraphicManager::ImplCreateOutput(), in fact it mostly copies
     557             : // it, the difference is that this one does not create anything, it only checks if
     558             : // ImplCreateOutput() would use the optimization of using the single bitmap.
     559             : // If you do changes here, change the original function too.
     560           3 : bool GraphicDisplayCacheEntry::IsCacheableAsBitmap( const GDIMetaFile& rMtf,
     561             :     OutputDevice* pOut, const Size& rSz )
     562             : {
     563           3 :     const Size aNewSize( rMtf.GetPrefSize() );
     564           3 :     GDIMetaFile rOutMtf = rMtf;
     565             : 
     566             :     // Count bitmap actions, and flag actions that paint, but
     567             :     // are no bitmaps.
     568           3 :     sal_Int32   nNumBitmaps(0);
     569           3 :     bool        bNonBitmapActionEncountered(false);
     570           3 :     if( aNewSize.Width() && aNewSize.Height() && rSz.Width() && rSz.Height() )
     571             :     {
     572           3 :         const MapMode rPrefMapMode( rMtf.GetPrefMapMode() );
     573           3 :         const Size rSizePix( pOut->LogicToPixel( aNewSize, rPrefMapMode ) );
     574             : 
     575             :         sal_uInt32  nCurPos;
     576             :         MetaAction* pAct;
     577         105 :         for( nCurPos = 0, pAct = (MetaAction*)rOutMtf.FirstAction(); pAct;
     578             :              pAct = (MetaAction*)rOutMtf.NextAction(), nCurPos++ )
     579             :         {
     580         102 :             switch( pAct->GetType() )
     581             :             {
     582             :                 case META_FONT_ACTION:
     583             :                     // FALLTHROUGH intended
     584             :                 case META_NULL_ACTION:
     585             :                     // FALLTHROUGH intended
     586             : 
     587             :                     // OutDev state changes (which don't affect bitmap
     588             :                     // output)
     589             :                 case META_LINECOLOR_ACTION:
     590             :                     // FALLTHROUGH intended
     591             :                 case META_FILLCOLOR_ACTION:
     592             :                     // FALLTHROUGH intended
     593             :                 case META_TEXTCOLOR_ACTION:
     594             :                     // FALLTHROUGH intended
     595             :                 case META_TEXTFILLCOLOR_ACTION:
     596             :                     // FALLTHROUGH intended
     597             :                 case META_TEXTALIGN_ACTION:
     598             :                     // FALLTHROUGH intended
     599             :                 case META_TEXTLINECOLOR_ACTION:
     600             :                     // FALLTHROUGH intended
     601             :                 case META_TEXTLINE_ACTION:
     602             :                     // FALLTHROUGH intended
     603             :                 case META_PUSH_ACTION:
     604             :                     // FALLTHROUGH intended
     605             :                 case META_POP_ACTION:
     606             :                     // FALLTHROUGH intended
     607             :                 case META_LAYOUTMODE_ACTION:
     608             :                     // FALLTHROUGH intended
     609             :                 case META_TEXTLANGUAGE_ACTION:
     610             :                     // FALLTHROUGH intended
     611             :                 case META_COMMENT_ACTION:
     612          90 :                     break;
     613             : 
     614             :                     // bitmap output methods
     615             :                 case META_BMP_ACTION:
     616           0 :                     if( !nNumBitmaps && !bNonBitmapActionEncountered )
     617             :                     {
     618           0 :                         MetaBmpAction* pAction = (MetaBmpAction*)pAct;
     619             : 
     620             :                         checkMetadataBitmap(
     621           0 :                             BitmapEx( pAction->GetBitmap()),
     622             :                             Point(), Size(),
     623           0 :                             pOut->LogicToPixel( pAction->GetPoint(),
     624             :                                                 rPrefMapMode ),
     625           0 :                             pAction->GetBitmap().GetSizePixel(),
     626             :                             rSizePix,
     627           0 :                             bNonBitmapActionEncountered );
     628             :                     }
     629           0 :                     ++nNumBitmaps;
     630           0 :                     break;
     631             : 
     632             :                 case META_BMPSCALE_ACTION:
     633           0 :                     if( !nNumBitmaps && !bNonBitmapActionEncountered )
     634             :                     {
     635           0 :                         MetaBmpScaleAction* pAction = (MetaBmpScaleAction*)pAct;
     636             : 
     637             :                         checkMetadataBitmap(
     638           0 :                             BitmapEx( pAction->GetBitmap()),
     639             :                             Point(), Size(),
     640           0 :                             pOut->LogicToPixel( pAction->GetPoint(),
     641             :                                                 rPrefMapMode ),
     642           0 :                             pOut->LogicToPixel( pAction->GetSize(),
     643             :                                                 rPrefMapMode ),
     644             :                             rSizePix,
     645           0 :                             bNonBitmapActionEncountered );
     646             :                     }
     647           0 :                     ++nNumBitmaps;
     648           0 :                     break;
     649             : 
     650             :                 case META_BMPSCALEPART_ACTION:
     651           0 :                     if( !nNumBitmaps && !bNonBitmapActionEncountered )
     652             :                     {
     653           0 :                         MetaBmpScalePartAction* pAction = (MetaBmpScalePartAction*)pAct;
     654             : 
     655           0 :                         checkMetadataBitmap(        BitmapEx( pAction->GetBitmap() ),
     656           0 :                                                     pAction->GetSrcPoint(),
     657           0 :                                                     pAction->GetSrcSize(),
     658           0 :                                                     pOut->LogicToPixel( pAction->GetDestPoint(),
     659             :                                                                         rPrefMapMode ),
     660           0 :                                                     pOut->LogicToPixel( pAction->GetDestSize(),
     661             :                                                                         rPrefMapMode ),
     662             :                                                     rSizePix,
     663           0 :                                                     bNonBitmapActionEncountered );
     664             :                     }
     665           0 :                     ++nNumBitmaps;
     666           0 :                     break;
     667             : 
     668             :                 case META_BMPEX_ACTION:
     669           0 :                     if( !nNumBitmaps && !bNonBitmapActionEncountered )
     670             :                     {
     671           0 :                         MetaBmpExAction* pAction = (MetaBmpExAction*)pAct;
     672             : 
     673             :                         checkMetadataBitmap(
     674           0 :                             pAction->GetBitmapEx(),
     675             :                             Point(), Size(),
     676           0 :                             pOut->LogicToPixel( pAction->GetPoint(),
     677             :                                                 rPrefMapMode ),
     678           0 :                             pAction->GetBitmapEx().GetSizePixel(),
     679             :                             rSizePix,
     680           0 :                             bNonBitmapActionEncountered );
     681             :                     }
     682           0 :                     ++nNumBitmaps;
     683           0 :                     break;
     684             : 
     685             :                 case META_BMPEXSCALE_ACTION:
     686           0 :                     if( !nNumBitmaps && !bNonBitmapActionEncountered )
     687             :                     {
     688           0 :                         MetaBmpExScaleAction* pAction = (MetaBmpExScaleAction*)pAct;
     689             : 
     690             :                         checkMetadataBitmap(
     691           0 :                             pAction->GetBitmapEx(),
     692             :                             Point(), Size(),
     693           0 :                             pOut->LogicToPixel( pAction->GetPoint(),
     694             :                                                 rPrefMapMode ),
     695           0 :                             pOut->LogicToPixel( pAction->GetSize(),
     696             :                                                 rPrefMapMode ),
     697             :                             rSizePix,
     698           0 :                             bNonBitmapActionEncountered );
     699             :                     }
     700           0 :                     ++nNumBitmaps;
     701           0 :                     break;
     702             : 
     703             :                 case META_BMPEXSCALEPART_ACTION:
     704           0 :                     if( !nNumBitmaps && !bNonBitmapActionEncountered )
     705             :                     {
     706           0 :                         MetaBmpExScalePartAction* pAction = (MetaBmpExScalePartAction*)pAct;
     707             : 
     708           0 :                         checkMetadataBitmap( pAction->GetBitmapEx(),
     709           0 :                                                     pAction->GetSrcPoint(),
     710           0 :                                                     pAction->GetSrcSize(),
     711           0 :                                                     pOut->LogicToPixel( pAction->GetDestPoint(),
     712             :                                                                         rPrefMapMode ),
     713           0 :                                                     pOut->LogicToPixel( pAction->GetDestSize(),
     714             :                                                                         rPrefMapMode ),
     715             :                                                     rSizePix,
     716           0 :                                                     bNonBitmapActionEncountered );
     717             :                     }
     718           0 :                     ++nNumBitmaps;
     719           0 :                     break;
     720             : 
     721             :                     // these actions actually output something (that's
     722             :                     // different from a bitmap)
     723             :                 case META_RASTEROP_ACTION:
     724           3 :                     if( ((MetaRasterOpAction*)pAct)->GetRasterOp() == ROP_OVERPAINT )
     725           3 :                         break;
     726             :                     // FALLTHROUGH intended
     727             :                 case META_PIXEL_ACTION:
     728             :                     // FALLTHROUGH intended
     729             :                 case META_POINT_ACTION:
     730             :                     // FALLTHROUGH intended
     731             :                 case META_LINE_ACTION:
     732             :                     // FALLTHROUGH intended
     733             :                 case META_RECT_ACTION:
     734             :                     // FALLTHROUGH intended
     735             :                 case META_ROUNDRECT_ACTION:
     736             :                     // FALLTHROUGH intended
     737             :                 case META_ELLIPSE_ACTION:
     738             :                     // FALLTHROUGH intended
     739             :                 case META_ARC_ACTION:
     740             :                     // FALLTHROUGH intended
     741             :                 case META_PIE_ACTION:
     742             :                     // FALLTHROUGH intended
     743             :                 case META_CHORD_ACTION:
     744             :                     // FALLTHROUGH intended
     745             :                 case META_POLYLINE_ACTION:
     746             :                     // FALLTHROUGH intended
     747             :                 case META_POLYGON_ACTION:
     748             :                     // FALLTHROUGH intended
     749             :                 case META_POLYPOLYGON_ACTION:
     750             :                     // FALLTHROUGH intended
     751             : 
     752             :                 case META_TEXT_ACTION:
     753             :                     // FALLTHROUGH intended
     754             :                 case META_TEXTARRAY_ACTION:
     755             :                     // FALLTHROUGH intended
     756             :                 case META_STRETCHTEXT_ACTION:
     757             :                     // FALLTHROUGH intended
     758             :                 case META_TEXTRECT_ACTION:
     759             :                     // FALLTHROUGH intended
     760             : 
     761             :                 case META_MASK_ACTION:
     762             :                     // FALLTHROUGH intended
     763             :                 case META_MASKSCALE_ACTION:
     764             :                     // FALLTHROUGH intended
     765             :                 case META_MASKSCALEPART_ACTION:
     766             :                     // FALLTHROUGH intended
     767             : 
     768             :                 case META_GRADIENT_ACTION:
     769             :                     // FALLTHROUGH intended
     770             :                 case META_HATCH_ACTION:
     771             :                     // FALLTHROUGH intended
     772             :                 case META_WALLPAPER_ACTION:
     773             :                     // FALLTHROUGH intended
     774             : 
     775             :                 case META_TRANSPARENT_ACTION:
     776             :                     // FALLTHROUGH intended
     777             :                 case META_EPS_ACTION:
     778             :                     // FALLTHROUGH intended
     779             :                 case META_FLOATTRANSPARENT_ACTION:
     780             :                     // FALLTHROUGH intended
     781             :                 case META_GRADIENTEX_ACTION:
     782             :                     // FALLTHROUGH intended
     783             : 
     784             :                     // OutDev state changes that _do_ affect bitmap
     785             :                     // output
     786             :                 case META_CLIPREGION_ACTION:
     787             :                     // FALLTHROUGH intended
     788             :                 case META_ISECTRECTCLIPREGION_ACTION:
     789             :                     // FALLTHROUGH intended
     790             :                 case META_ISECTREGIONCLIPREGION_ACTION:
     791             :                     // FALLTHROUGH intended
     792             :                 case META_MOVECLIPREGION_ACTION:
     793             :                     // FALLTHROUGH intended
     794             : 
     795             :                 case META_MAPMODE_ACTION:
     796             :                     // FALLTHROUGH intended
     797             :                 case META_REFPOINT_ACTION:
     798             :                     // FALLTHROUGH intended
     799             :                 default:
     800           9 :                     bNonBitmapActionEncountered = true;
     801           9 :                     break;
     802             :             }
     803           3 :         }
     804             :     }
     805           3 :     return nNumBitmaps == 1 && !bNonBitmapActionEncountered;
     806             : }
     807             : 
     808          24 : sal_uLong GraphicDisplayCacheEntry::GetNeededSize( OutputDevice* pOut, const Point& /*rPt*/, const Size& rSz,
     809             :                                                const GraphicObject& rObj, const GraphicAttr& rAttr )
     810             : {
     811          24 :     const Graphic&      rGraphic = rObj.GetGraphic();
     812          24 :     const GraphicType   eType = rGraphic.GetType();
     813             : 
     814          24 :     bool canCacheAsBitmap = false;
     815          24 :     if( GRAPHIC_BITMAP == eType )
     816          21 :         canCacheAsBitmap = true;
     817           3 :     else if( GRAPHIC_GDIMETAFILE == eType )
     818           3 :         canCacheAsBitmap = IsCacheableAsBitmap( rGraphic.GetGDIMetaFile(), pOut, rSz );
     819             :     else
     820           0 :         return 0;
     821          24 :     if( canCacheAsBitmap )
     822             :     {
     823          21 :         const Size aOutSizePix( pOut->LogicToPixel( rSz ) );
     824          21 :         const long nBitCount = pOut->GetBitCount();
     825             : 
     826          42 :         if( ( aOutSizePix.Width() > MAX_BMP_EXTENT ) ||
     827          21 :             ( aOutSizePix.Height() > MAX_BMP_EXTENT ) )
     828             :         {
     829           0 :             return ULONG_MAX;
     830             :         }
     831          21 :         else if( nBitCount )
     832             :         {
     833          21 :             sal_uLong nNeededSize = aOutSizePix.Width() * aOutSizePix.Height() * nBitCount / 8;
     834          21 :             if( rObj.IsTransparent() || ( rAttr.GetRotation() % 3600 ) )
     835           9 :                 nNeededSize += nNeededSize / nBitCount;
     836          21 :             return nNeededSize;
     837             :         }
     838             :         else
     839             :         {
     840             :             OSL_FAIL( "GraphicDisplayCacheEntry::GetNeededSize(): pOut->GetBitCount() == 0" );
     841           0 :             return 256000;
     842             :         }
     843             :     }
     844             :     else
     845           3 :         return rGraphic.GetSizeBytes();
     846             : }
     847             : 
     848             : // -----------------------------------------------------------------------------
     849             : 
     850           0 : GraphicDisplayCacheEntry::~GraphicDisplayCacheEntry()
     851             : {
     852           0 :     if( mpMtf )
     853           0 :         delete mpMtf;
     854             : 
     855           0 :     if( mpBmpEx )
     856           0 :         delete mpBmpEx;
     857           0 : }
     858             : 
     859             : // -----------------------------------------------------------------------------
     860             : 
     861           8 : void GraphicDisplayCacheEntry::Draw( OutputDevice* pOut, const Point& rPt, const Size& rSz ) const
     862             : {
     863           8 :     if( mpMtf )
     864           1 :         GraphicManager::ImplDraw( pOut, rPt, rSz, *mpMtf, maAttr );
     865           7 :     else if( mpBmpEx )
     866             :     {
     867           7 :         if( maAttr.IsRotated() )
     868             :         {
     869           0 :             Polygon aPoly( Rectangle( rPt, rSz ) );
     870             : 
     871           0 :             aPoly.Rotate( rPt, maAttr.GetRotation() % 3600 );
     872           0 :             const Rectangle aRotBoundRect( aPoly.GetBoundRect() );
     873           0 :             pOut->DrawBitmapEx( aRotBoundRect.TopLeft(), aRotBoundRect.GetSize(), *mpBmpEx );
     874             :         }
     875             :         else
     876           7 :             pOut->DrawBitmapEx( rPt, rSz, *mpBmpEx );
     877             :     }
     878           8 : }
     879             : 
     880             : // -----------------------
     881             : // - GraphicCache -
     882             : // -----------------------
     883             : 
     884          18 : GraphicCache::GraphicCache( sal_uLong nDisplayCacheSize, sal_uLong nMaxObjDisplayCacheSize ) :
     885             :     mnReleaseTimeoutSeconds ( 0UL ),
     886             :     mnMaxDisplaySize        ( nDisplayCacheSize ),
     887             :     mnMaxObjDisplaySize     ( nMaxObjDisplayCacheSize ),
     888          18 :     mnUsedDisplaySize       ( 0UL )
     889             : {
     890          18 :     maReleaseTimer.SetTimeoutHdl( LINK( this, GraphicCache, ReleaseTimeoutHdl ) );
     891          18 :     maReleaseTimer.SetTimeout( RELEASE_TIMEOUT );
     892          18 :     maReleaseTimer.Start();
     893          18 : }
     894             : 
     895             : // -----------------------------------------------------------------------------
     896             : 
     897           2 : GraphicCache::~GraphicCache()
     898             : {
     899             :     DBG_ASSERT( !maGraphicCache.size(), "GraphicCache::~GraphicCache(): there are some GraphicObjects in cache" );
     900             :     DBG_ASSERT( maDisplayCache.empty(), "GraphicCache::~GraphicCache(): there are some GraphicObjects in display cache" );
     901           2 : }
     902             : 
     903             : // -----------------------------------------------------------------------------
     904             : 
     905        2019 : void GraphicCache::AddGraphicObject(
     906             :     const GraphicObject& rObj,
     907             :     Graphic& rSubstitute,
     908             :     const rtl::OString* pID,
     909             :     const GraphicObject* pCopyObj
     910             : )
     911             : {
     912        2019 :     sal_Bool bInserted = sal_False;
     913             : 
     914        4439 :     if(  !rObj.IsSwappedOut()
     915             :       && (  pID
     916             :          || (    pCopyObj
     917         690 :             && ( pCopyObj->GetType() != GRAPHIC_NONE )
     918             :             )
     919        1730 :          || ( rObj.GetType() != GRAPHIC_NONE )
     920             :          )
     921             :       )
     922             :     {
     923         646 :         if( pCopyObj
     924         232 :           && !maGraphicCache.empty()
     925             :         )
     926             :         {
     927         232 :             GraphicCacheEntryList::iterator it = maGraphicCache.begin();
     928       11160 :             while(  !bInserted
     929        8080 :                  && ( it != maGraphicCache.end() )
     930             :                  )
     931             :             {
     932        2616 :                 if( (*it)->HasGraphicObjectReference( *pCopyObj ) )
     933             :                 {
     934         232 :                     (*it)->AddGraphicObjectReference( rObj, rSubstitute );
     935         232 :                     bInserted = sal_True;
     936             :                 }
     937             :                 else
     938             :                 {
     939        2384 :                     ++it;
     940             :                 }
     941             :             }
     942             :         }
     943             : 
     944         414 :         if( !bInserted )
     945             :         {
     946         182 :             GraphicCacheEntryList::iterator it = maGraphicCache.begin();
     947         182 :             ::std::auto_ptr< GraphicID > apID;
     948             : 
     949         182 :             if( !pID )
     950             :             {
     951         125 :                 apID.reset( new GraphicID( rObj ) );
     952             :             }
     953             : 
     954       16598 :             while(  !bInserted
     955       12243 :                  && ( it != maGraphicCache.end() )
     956             :                  )
     957             :             {
     958        3991 :                 const GraphicID& rEntryID = (*it)->GetID();
     959             : 
     960        3991 :                 if( pID )
     961             :                 {
     962        1834 :                     if( rEntryID.GetIDString() == *pID )
     963             :                     {
     964          57 :                         (*it)->TryToSwapIn();
     965             : 
     966             :                         // since pEntry->TryToSwapIn can modify our current list, we have to
     967             :                         // iterate from beginning to add a reference to the appropriate
     968             :                         // CacheEntry object; after this, quickly jump out of the outer iteration
     969        7450 :                         for( GraphicCacheEntryList::iterator jt = maGraphicCache.begin();
     970        5559 :                              !bInserted && jt != maGraphicCache.end();
     971             :                              ++jt
     972             :                         )
     973             :                         {
     974        1834 :                             const GraphicID& rID = (*jt)->GetID();
     975             : 
     976        1834 :                             if( rID.GetIDString() == *pID )
     977             :                             {
     978          57 :                                 (*jt)->AddGraphicObjectReference( rObj, rSubstitute );
     979          57 :                                 bInserted = sal_True;
     980             :                             }
     981             :                         }
     982             : 
     983          57 :                         if( !bInserted )
     984             :                         {
     985           0 :                             maGraphicCache.push_back( new GraphicCacheEntry( rObj ) );
     986           0 :                             bInserted = sal_True;
     987             :                         }
     988             :                     }
     989             :                 }
     990             :                 else
     991             :                 {
     992        2157 :                     if( rEntryID == *apID )
     993             :                     {
     994          81 :                         (*it)->AddGraphicObjectReference( rObj, rSubstitute );
     995          81 :                         bInserted = sal_True;
     996             :                     }
     997             :                 }
     998             : 
     999        3991 :                 if( !bInserted )
    1000        3853 :                     ++it;
    1001         182 :             }
    1002             :         }
    1003             :     }
    1004             : 
    1005        2019 :     if( !bInserted )
    1006        1649 :         maGraphicCache.push_back( new GraphicCacheEntry( rObj ) );
    1007        2019 : }
    1008             : 
    1009             : // -----------------------------------------------------------------------------
    1010             : 
    1011        1768 : void GraphicCache::ReleaseGraphicObject( const GraphicObject& rObj )
    1012             : {
    1013             :     // Release cached object
    1014        1768 :     bool    bRemoved = false;
    1015        1768 :     GraphicCacheEntryList::iterator it = maGraphicCache.begin();
    1016       32515 :     while (!bRemoved && it != maGraphicCache.end())
    1017             :     {
    1018       28979 :         bRemoved = (*it)->ReleaseGraphicObjectReference( rObj );
    1019             : 
    1020       28979 :         if( bRemoved )
    1021             :         {
    1022        1768 :             if( 0 == (*it)->GetGraphicObjectReferenceCount() )
    1023             :             {
    1024             :                 // if graphic cache entry has no more references,
    1025             :                 // the corresponding display cache object can be removed
    1026        1419 :                 GraphicDisplayCacheEntryList::iterator it2 = maDisplayCache.begin();
    1027        3483 :                 while( it2 != maDisplayCache.end() )
    1028             :                 {
    1029         645 :                     GraphicDisplayCacheEntry* pDisplayEntry = *it2;
    1030         645 :                     if( pDisplayEntry->GetReferencedCacheEntry() == *it )
    1031             :                     {
    1032           0 :                         mnUsedDisplaySize -= pDisplayEntry->GetCacheSize();
    1033           0 :                         it2 = maDisplayCache.erase( it2 );
    1034           0 :                         delete pDisplayEntry;
    1035             :                     }
    1036             :                     else
    1037         645 :                         ++it2;
    1038             :                 }
    1039             : 
    1040             :                 // delete graphic cache entry
    1041        1419 :                 delete *it;
    1042        1419 :                 it = maGraphicCache.erase( it );
    1043             :             }
    1044             :         }
    1045             :         else
    1046       27211 :             ++it;
    1047             :     }
    1048             : 
    1049             :     DBG_ASSERT( bRemoved, "GraphicCache::ReleaseGraphicObject(...): GraphicObject not found in cache" );
    1050        1768 : }
    1051             : 
    1052             : // -----------------------------------------------------------------------------
    1053             : 
    1054          13 : void GraphicCache::GraphicObjectWasSwappedOut( const GraphicObject& rObj )
    1055             : {
    1056             :     // notify cache that rObj is swapped out (and can thus be pruned
    1057             :     // from the cache)
    1058          13 :     GraphicCacheEntry* pEntry = ImplGetCacheEntry( rObj );
    1059             : 
    1060          13 :     if( pEntry )
    1061          13 :         pEntry->GraphicObjectWasSwappedOut( rObj );
    1062          13 : }
    1063             : 
    1064             : // -----------------------------------------------------------------------------
    1065             : 
    1066           0 : sal_Bool GraphicCache::FillSwappedGraphicObject( const GraphicObject& rObj, Graphic& rSubstitute )
    1067             : {
    1068           0 :     GraphicCacheEntry* pEntry = ImplGetCacheEntry( rObj );
    1069             : 
    1070           0 :     if( !pEntry )
    1071           0 :         return sal_False;
    1072             : 
    1073           0 :     return pEntry->FillSwappedGraphicObject( rObj, rSubstitute );
    1074             : }
    1075             : 
    1076             : // -----------------------------------------------------------------------------
    1077             : 
    1078           0 : void GraphicCache::GraphicObjectWasSwappedIn( const GraphicObject& rObj )
    1079             : {
    1080           0 :     GraphicCacheEntry* pEntry = ImplGetCacheEntry( rObj );
    1081             : 
    1082           0 :     if( pEntry )
    1083             :     {
    1084           0 :         if( pEntry->GetID().IsEmpty() )
    1085             :         {
    1086           0 :             ReleaseGraphicObject( rObj );
    1087           0 :             AddGraphicObject( rObj, (Graphic&) rObj.GetGraphic(), NULL, NULL );
    1088             :         }
    1089             :         else
    1090           0 :             pEntry->GraphicObjectWasSwappedIn( rObj );
    1091             :     }
    1092           0 : }
    1093             : 
    1094             : // -----------------------------------------------------------------------------
    1095             : 
    1096           0 : void GraphicCache::SetMaxDisplayCacheSize( sal_uLong nNewCacheSize )
    1097             : {
    1098           0 :     mnMaxDisplaySize = nNewCacheSize;
    1099             : 
    1100           0 :     if( GetMaxDisplayCacheSize() < GetUsedDisplayCacheSize() )
    1101           0 :         ImplFreeDisplayCacheSpace( GetUsedDisplayCacheSize() - GetMaxDisplayCacheSize() );
    1102           0 : }
    1103             : 
    1104             : // -----------------------------------------------------------------------------
    1105             : 
    1106           0 : void GraphicCache::SetMaxObjDisplayCacheSize( sal_uLong nNewMaxObjSize, sal_Bool bDestroyGreaterCached )
    1107             : {
    1108           0 :     const sal_Bool bDestroy = ( bDestroyGreaterCached && ( nNewMaxObjSize < mnMaxObjDisplaySize ) );
    1109             : 
    1110           0 :     mnMaxObjDisplaySize = Min( nNewMaxObjSize, mnMaxDisplaySize );
    1111             : 
    1112           0 :     if( bDestroy )
    1113             :     {
    1114           0 :         GraphicDisplayCacheEntryList::iterator it = maDisplayCache.begin();
    1115           0 :         while( it != maDisplayCache.end() )
    1116             :         {
    1117           0 :             GraphicDisplayCacheEntry* pCacheObj = *it;
    1118           0 :             if( pCacheObj->GetCacheSize() > mnMaxObjDisplaySize )
    1119             :             {
    1120           0 :                 mnUsedDisplaySize -= pCacheObj->GetCacheSize();
    1121           0 :                 it = maDisplayCache.erase( it );
    1122           0 :                 delete pCacheObj;
    1123             :             }
    1124             :             else
    1125           0 :                 ++it;
    1126             :         }
    1127             :     }
    1128           0 : }
    1129             : 
    1130             : // -----------------------------------------------------------------------------
    1131             : 
    1132          18 : void GraphicCache::SetCacheTimeout( sal_uLong nTimeoutSeconds )
    1133             : {
    1134          18 :     if( mnReleaseTimeoutSeconds != nTimeoutSeconds )
    1135             :     {
    1136          18 :         ::salhelper::TTimeValue           aReleaseTime;
    1137             : 
    1138          18 :         if( ( mnReleaseTimeoutSeconds = nTimeoutSeconds ) != 0 )
    1139             :         {
    1140          18 :             osl_getSystemTime( &aReleaseTime );
    1141          18 :             aReleaseTime.addTime( ::salhelper::TTimeValue( nTimeoutSeconds, 0 ) );
    1142             :         }
    1143             : 
    1144          54 :         for( GraphicDisplayCacheEntryList::const_iterator it = maDisplayCache.begin();
    1145          36 :              it != maDisplayCache.end(); ++it )
    1146             :         {
    1147           0 :             (*it)->SetReleaseTime( aReleaseTime );
    1148             :         }
    1149             :     }
    1150          18 : }
    1151             : 
    1152             : // -----------------------------------------------------------------------------
    1153             : 
    1154           8 : sal_Bool GraphicCache::IsDisplayCacheable( OutputDevice* pOut, const Point& rPt, const Size& rSz,
    1155             :                                        const GraphicObject& rObj, const GraphicAttr& rAttr ) const
    1156             : {
    1157           8 :     return( GraphicDisplayCacheEntry::GetNeededSize( pOut, rPt, rSz, rObj, rAttr ) <=
    1158           8 :             GetMaxObjDisplayCacheSize() );
    1159             : }
    1160             : 
    1161             : // -----------------------------------------------------------------------------
    1162             : 
    1163          16 : sal_Bool GraphicCache::IsInDisplayCache( OutputDevice* pOut, const Point& rPt, const Size& rSz,
    1164             :                                      const GraphicObject& rObj, const GraphicAttr& rAttr ) const
    1165             : {
    1166          16 :     const Point                 aPtPixel( pOut->LogicToPixel( rPt ) );
    1167          16 :     const Size                  aSzPixel( pOut->LogicToPixel( rSz ) );
    1168          16 :     const GraphicCacheEntry*    pCacheEntry = ( (GraphicCache*) this )->ImplGetCacheEntry( rObj );
    1169          16 :     sal_Bool                        bFound = sal_False;
    1170             : 
    1171          16 :     if( pCacheEntry )
    1172             :     {
    1173         304 :         for( GraphicDisplayCacheEntryList::const_iterator it = maDisplayCache.begin();
    1174         224 :              !bFound && ( it != maDisplayCache.end() ); ++it )
    1175             :         {
    1176          64 :             if( (*it)->Matches( pOut, aPtPixel, aSzPixel, pCacheEntry, rAttr ) )
    1177           8 :                 bFound = sal_True;
    1178             :         }
    1179             :     }
    1180             : 
    1181          16 :     return bFound;
    1182             : }
    1183             : 
    1184             : // -----------------------------------------------------------------------------
    1185             : 
    1186         132 : rtl::OString GraphicCache::GetUniqueID( const GraphicObject& rObj ) const
    1187             : {
    1188         132 :     rtl::OString aRet;
    1189         132 :     GraphicCacheEntry*  pEntry = ( (GraphicCache*) this )->ImplGetCacheEntry( rObj );
    1190             : 
    1191             :     // ensure that the entry is correctly initialized (it has to be read at least once)
    1192         132 :     if( pEntry && pEntry->GetID().IsEmpty() )
    1193           0 :         pEntry->TryToSwapIn();
    1194             : 
    1195             :     // do another call to ImplGetCacheEntry in case of modified entry list
    1196         132 :     pEntry = ( (GraphicCache*) this )->ImplGetCacheEntry( rObj );
    1197             : 
    1198         132 :     if( pEntry )
    1199         132 :         aRet = pEntry->GetID().GetIDString();
    1200             : 
    1201         132 :     return aRet;
    1202             : }
    1203             : 
    1204             : // -----------------------------------------------------------------------------
    1205             : 
    1206           7 : sal_Bool GraphicCache::CreateDisplayCacheObj( OutputDevice* pOut, const Point& rPt, const Size& rSz,
    1207             :                                           const GraphicObject& rObj, const GraphicAttr& rAttr,
    1208             :                                           const BitmapEx& rBmpEx )
    1209             : {
    1210           7 :     const sal_uLong nNeededSize = GraphicDisplayCacheEntry::GetNeededSize( pOut, rPt, rSz, rObj, rAttr );
    1211           7 :     sal_Bool        bRet = sal_False;
    1212             : 
    1213           7 :     if( nNeededSize <= GetMaxObjDisplayCacheSize() )
    1214             :     {
    1215           7 :         if( nNeededSize > GetFreeDisplayCacheSize() )
    1216           0 :             ImplFreeDisplayCacheSpace( nNeededSize - GetFreeDisplayCacheSize() );
    1217             : 
    1218             :         GraphicDisplayCacheEntry* pNewEntry = new GraphicDisplayCacheEntry( ImplGetCacheEntry( rObj ),
    1219           7 :                                                                             pOut, rPt, rSz, rObj, rAttr, rBmpEx );
    1220             : 
    1221           7 :         if( GetCacheTimeout() )
    1222             :         {
    1223           7 :             ::salhelper::TTimeValue aReleaseTime;
    1224             : 
    1225           7 :             osl_getSystemTime( &aReleaseTime );
    1226           7 :             aReleaseTime.addTime( ::salhelper::TTimeValue( GetCacheTimeout(), 0 ) );
    1227           7 :             pNewEntry->SetReleaseTime( aReleaseTime );
    1228             :         }
    1229             : 
    1230           7 :         maDisplayCache.push_back( pNewEntry );
    1231           7 :         mnUsedDisplaySize += pNewEntry->GetCacheSize();
    1232           7 :         bRet = sal_True;
    1233             :     }
    1234             : 
    1235           7 :     return bRet;
    1236             : }
    1237             : 
    1238             : // -----------------------------------------------------------------------------
    1239             : 
    1240           1 : sal_Bool GraphicCache::CreateDisplayCacheObj( OutputDevice* pOut, const Point& rPt, const Size& rSz,
    1241             :                                           const GraphicObject& rObj, const GraphicAttr& rAttr,
    1242             :                                           const GDIMetaFile& rMtf )
    1243             : {
    1244           1 :     const sal_uLong nNeededSize = GraphicDisplayCacheEntry::GetNeededSize( pOut, rPt, rSz, rObj, rAttr );
    1245           1 :     sal_Bool        bRet = sal_False;
    1246             : 
    1247           1 :     if( nNeededSize <= GetMaxObjDisplayCacheSize() )
    1248             :     {
    1249           1 :         if( nNeededSize > GetFreeDisplayCacheSize() )
    1250           0 :             ImplFreeDisplayCacheSpace( nNeededSize - GetFreeDisplayCacheSize() );
    1251             : 
    1252             :         GraphicDisplayCacheEntry* pNewEntry = new GraphicDisplayCacheEntry( ImplGetCacheEntry( rObj ),
    1253           1 :                                                                             pOut, rPt, rSz, rObj, rAttr, rMtf );
    1254             : 
    1255           1 :         if( GetCacheTimeout() )
    1256             :         {
    1257           1 :             ::salhelper::TTimeValue aReleaseTime;
    1258             : 
    1259           1 :             osl_getSystemTime( &aReleaseTime );
    1260           1 :             aReleaseTime.addTime( ::salhelper::TTimeValue( GetCacheTimeout(), 0 ) );
    1261           1 :             pNewEntry->SetReleaseTime( aReleaseTime );
    1262             :         }
    1263             : 
    1264           1 :         maDisplayCache.push_back( pNewEntry );
    1265           1 :         mnUsedDisplaySize += pNewEntry->GetCacheSize();
    1266           1 :         bRet = sal_True;
    1267             :     }
    1268             : 
    1269           1 :     return bRet;
    1270             : }
    1271             : 
    1272             : // -----------------------------------------------------------------------------
    1273             : 
    1274          16 : sal_Bool GraphicCache::DrawDisplayCacheObj( OutputDevice* pOut, const Point& rPt, const Size& rSz,
    1275             :                                         const GraphicObject& rObj, const GraphicAttr& rAttr )
    1276             : {
    1277          16 :     const Point                 aPtPixel( pOut->LogicToPixel( rPt ) );
    1278          16 :     const Size                  aSzPixel( pOut->LogicToPixel( rSz ) );
    1279          16 :     const GraphicCacheEntry*    pCacheEntry = ImplGetCacheEntry( rObj );
    1280          16 :     GraphicDisplayCacheEntry*   pDisplayCacheEntry = NULL;
    1281          16 :     GraphicDisplayCacheEntryList::iterator it = maDisplayCache.begin();
    1282          16 :     sal_Bool                    bRet = sal_False;
    1283             : 
    1284          96 :     while( !bRet && it != maDisplayCache.end() )
    1285             :     {
    1286          64 :         pDisplayCacheEntry = *it;
    1287          64 :         if( pDisplayCacheEntry->Matches( pOut, aPtPixel, aSzPixel, pCacheEntry, rAttr ) )
    1288             :         {
    1289           8 :             ::salhelper::TTimeValue aReleaseTime;
    1290             : 
    1291             :             // put found object at last used position
    1292           8 :             it = maDisplayCache.erase( it );
    1293           8 :             maDisplayCache.push_back( pDisplayCacheEntry );
    1294             : 
    1295           8 :             if( GetCacheTimeout() )
    1296             :             {
    1297           8 :                 osl_getSystemTime( &aReleaseTime );
    1298           8 :                 aReleaseTime.addTime( ::salhelper::TTimeValue( GetCacheTimeout(), 0 ) );
    1299             :             }
    1300             : 
    1301           8 :             pDisplayCacheEntry->SetReleaseTime( aReleaseTime );
    1302           8 :             bRet = sal_True;
    1303             :         }
    1304             :         else
    1305          56 :             ++it;
    1306             :     }
    1307             : 
    1308          16 :     if( bRet )
    1309           8 :         pDisplayCacheEntry->Draw( pOut, rPt, rSz );
    1310             : 
    1311          16 :     return bRet;
    1312             : }
    1313             : 
    1314             : // -----------------------------------------------------------------------------
    1315             : 
    1316           0 : sal_Bool GraphicCache::ImplFreeDisplayCacheSpace( sal_uLong nSizeToFree )
    1317             : {
    1318           0 :     sal_uLong nFreedSize = 0UL;
    1319             : 
    1320           0 :     if( nSizeToFree )
    1321             :     {
    1322           0 :         GraphicDisplayCacheEntryList::iterator it = maDisplayCache.begin();
    1323             : 
    1324           0 :         if( nSizeToFree > mnUsedDisplaySize )
    1325           0 :             nSizeToFree = mnUsedDisplaySize;
    1326             : 
    1327           0 :         while( it != maDisplayCache.end() )
    1328             :         {
    1329           0 :             GraphicDisplayCacheEntry* pCacheObj = *it;
    1330             : 
    1331           0 :             nFreedSize += pCacheObj->GetCacheSize();
    1332           0 :             mnUsedDisplaySize -= pCacheObj->GetCacheSize();
    1333           0 :             it = maDisplayCache.erase( it );
    1334           0 :             delete pCacheObj;
    1335             : 
    1336           0 :             if( nFreedSize >= nSizeToFree )
    1337           0 :                 break;
    1338             :         }
    1339             :     }
    1340             : 
    1341           0 :     return( nFreedSize >= nSizeToFree );
    1342             : }
    1343             : 
    1344             : // -----------------------------------------------------------------------------
    1345             : 
    1346         317 : GraphicCacheEntry* GraphicCache::ImplGetCacheEntry( const GraphicObject& rObj )
    1347             : {
    1348         317 :     GraphicCacheEntry* pRet = NULL;
    1349             : 
    1350       22886 :     for(
    1351         317 :         GraphicCacheEntryList::iterator it = maGraphicCache.begin();
    1352       17006 :         !pRet && it != maGraphicCache.end();
    1353             :         ++it
    1354             :     ) {
    1355        5563 :         if( (*it)->HasGraphicObjectReference( rObj ) ) {
    1356         317 :             pRet = *it;
    1357             :         }
    1358             :     }
    1359             : 
    1360         317 :     return pRet;
    1361             : }
    1362             : 
    1363             : // -----------------------------------------------------------------------------
    1364             : 
    1365          22 : IMPL_LINK( GraphicCache, ReleaseTimeoutHdl, Timer*, pTimer )
    1366             : {
    1367          11 :     pTimer->Stop();
    1368             : 
    1369          11 :     ::salhelper::TTimeValue           aCurTime;
    1370          11 :     GraphicDisplayCacheEntryList::iterator it = maDisplayCache.begin();
    1371             : 
    1372          11 :     osl_getSystemTime( &aCurTime );
    1373             : 
    1374          48 :     while( it != maDisplayCache.end() )
    1375             :     {
    1376          26 :         GraphicDisplayCacheEntry*   pDisplayEntry = *it;
    1377          26 :         const ::salhelper::TTimeValue& rReleaseTime = pDisplayEntry->GetReleaseTime();
    1378             : 
    1379          26 :         if( !rReleaseTime.isEmpty() && ( rReleaseTime < aCurTime ) )
    1380             :         {
    1381           0 :             mnUsedDisplaySize -= pDisplayEntry->GetCacheSize();
    1382           0 :             it = maDisplayCache.erase( it );
    1383           0 :             delete pDisplayEntry;
    1384             :         }
    1385             :         else
    1386          26 :             ++it;
    1387             :     }
    1388             : 
    1389          11 :     pTimer->Start();
    1390             : 
    1391          11 :     return 0;
    1392             : }
    1393             : 
    1394             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10