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

Generated by: LCOV version 1.10