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

Generated by: LCOV version 1.10