| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_svtools.hxx" |
| |
| #include <vos/timer.hxx> |
| #include <tools/debug.hxx> |
| #include <vcl/outdev.hxx> |
| #include <tools/poly.hxx> |
| #include "grfcache.hxx" |
| #include <rtl/crc.h> |
| #include <memory> |
| |
| // ----------- |
| // - Defines - |
| // ----------- |
| |
| #define RELEASE_TIMEOUT 10000 |
| #define MAX_BMP_EXTENT 4096 |
| |
| // ----------- |
| // - statics - |
| // ----------- |
| |
| static const char aHexData[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; |
| |
| // ------------- |
| // - GraphicID - |
| // ------------- |
| |
| class GraphicID |
| { |
| private: |
| |
| sal_uInt32 mnID1; |
| sal_uInt32 mnID2; |
| sal_uInt32 mnID3; |
| sal_uInt32 mnID4; |
| |
| GraphicID(); |
| |
| public: |
| |
| |
| GraphicID( const GraphicObject& rObj ); |
| ~GraphicID() {} |
| |
| sal_Bool operator==( const GraphicID& rID ) const |
| { |
| return( rID.mnID1 == mnID1 && rID.mnID2 == mnID2 && |
| rID.mnID3 == mnID3 && rID.mnID4 == mnID4 ); |
| } |
| |
| ByteString GetIDString() const; |
| sal_Bool IsEmpty() const { return( 0 == mnID4 ); } |
| }; |
| |
| // ----------------------------------------------------------------------------- |
| |
| GraphicID::GraphicID( const GraphicObject& rObj ) |
| { |
| const Graphic& rGraphic = rObj.GetGraphic(); |
| |
| mnID1 = ( (sal_uLong) rGraphic.GetType() ) << 28; |
| |
| switch( rGraphic.GetType() ) |
| { |
| case( GRAPHIC_BITMAP ): |
| { |
| if(rGraphic.getSvgData().get()) |
| { |
| const SvgDataPtr& rSvgDataPtr = rGraphic.getSvgData(); |
| const basegfx::B2DRange& rRange = rSvgDataPtr->getRange(); |
| |
| mnID1 |= rSvgDataPtr->getSvgDataArrayLength(); |
| mnID2 = basegfx::fround(rRange.getWidth()); |
| mnID3 = basegfx::fround(rRange.getHeight()); |
| mnID4 = rtl_crc32(0, rSvgDataPtr->getSvgDataArray().get(), rSvgDataPtr->getSvgDataArrayLength()); |
| } |
| else if( rGraphic.IsAnimated() ) |
| { |
| const Animation aAnimation( rGraphic.GetAnimation() ); |
| |
| mnID1 |= ( aAnimation.Count() & 0x0fffffff ); |
| mnID2 = aAnimation.GetDisplaySizePixel().Width(); |
| mnID3 = aAnimation.GetDisplaySizePixel().Height(); |
| mnID4 = rGraphic.GetChecksum(); |
| } |
| else |
| { |
| const BitmapEx aBmpEx( rGraphic.GetBitmapEx() ); |
| |
| mnID1 |= ( ( ( (sal_uLong) aBmpEx.GetTransparentType() << 8 ) | ( aBmpEx.IsAlpha() ? 1 : 0 ) ) & 0x0fffffff ); |
| mnID2 = aBmpEx.GetSizePixel().Width(); |
| mnID3 = aBmpEx.GetSizePixel().Height(); |
| mnID4 = rGraphic.GetChecksum(); |
| } |
| } |
| break; |
| |
| case( GRAPHIC_GDIMETAFILE ): |
| { |
| const GDIMetaFile aMtf( rGraphic.GetGDIMetaFile() ); |
| |
| mnID1 |= ( aMtf.GetActionCount() & 0x0fffffff ); |
| mnID2 = aMtf.GetPrefSize().Width(); |
| mnID3 = aMtf.GetPrefSize().Height(); |
| mnID4 = rGraphic.GetChecksum(); |
| } |
| break; |
| |
| default: |
| mnID2 = mnID3 = mnID4 = 0; |
| break; |
| } |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| ByteString GraphicID::GetIDString() const |
| { |
| ByteString aHexStr; |
| sal_Char* pStr = aHexStr.AllocBuffer( 32 ); |
| sal_Int32 nShift; |
| |
| for( nShift = 28; nShift >= 0; nShift -= 4 ) |
| *pStr++ = aHexData[ ( mnID1 >> (sal_uInt32) nShift ) & 0xf ]; |
| |
| for( nShift = 28; nShift >= 0; nShift -= 4 ) |
| *pStr++ = aHexData[ ( mnID2 >> (sal_uInt32) nShift ) & 0xf ]; |
| |
| for( nShift = 28; nShift >= 0; nShift -= 4 ) |
| *pStr++ = aHexData[ ( mnID3 >> (sal_uInt32) nShift ) & 0xf ]; |
| |
| for( nShift = 28; nShift >= 0; nShift -= 4 ) |
| *pStr++ = aHexData[ ( mnID4 >> (sal_uInt32) nShift ) & 0xf ]; |
| |
| return aHexStr; |
| } |
| |
| // --------------------- |
| // - GraphicCacheEntry - |
| // --------------------- |
| |
| class GraphicCacheEntry |
| { |
| private: |
| |
| List maGraphicObjectList; |
| GraphicID maID; |
| GfxLink maGfxLink; |
| BitmapEx* mpBmpEx; |
| GDIMetaFile* mpMtf; |
| Animation* mpAnimation; |
| sal_Bool mbSwappedAll; |
| |
| // SvgData support |
| SvgDataPtr maSvgData; |
| |
| sal_Bool ImplInit( const GraphicObject& rObj ); |
| sal_Bool ImplMatches( const GraphicObject& rObj ) const { return( GraphicID( rObj ) == maID ); } |
| void ImplFillSubstitute( Graphic& rSubstitute ); |
| |
| public: |
| |
| GraphicCacheEntry( const GraphicObject& rObj ); |
| ~GraphicCacheEntry(); |
| |
| const GraphicID& GetID() const { return maID; } |
| |
| void AddGraphicObjectReference( const GraphicObject& rObj, Graphic& rSubstitute ); |
| sal_Bool ReleaseGraphicObjectReference( const GraphicObject& rObj ); |
| sal_uLong GetGraphicObjectReferenceCount() { return maGraphicObjectList.Count(); } |
| sal_Bool HasGraphicObjectReference( const GraphicObject& rObj ); |
| |
| void TryToSwapIn(); |
| void GraphicObjectWasSwappedOut( const GraphicObject& rObj ); |
| sal_Bool FillSwappedGraphicObject( const GraphicObject& rObj, Graphic& rSubstitute ); |
| void GraphicObjectWasSwappedIn( const GraphicObject& rObj ); |
| }; |
| |
| // ----------------------------------------------------------------------------- |
| |
| GraphicCacheEntry::GraphicCacheEntry( const GraphicObject& rObj ) : |
| maID ( rObj ), |
| mpBmpEx ( NULL ), |
| mpMtf ( NULL ), |
| mpAnimation ( NULL ), |
| mbSwappedAll ( true ) |
| { |
| mbSwappedAll = !ImplInit(rObj); |
| maGraphicObjectList.Insert( (void*) &rObj, LIST_APPEND ); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| GraphicCacheEntry::~GraphicCacheEntry() |
| { |
| DBG_ASSERT( !maGraphicObjectList.Count(), "GraphicCacheEntry::~GraphicCacheEntry(): Not all GraphicObjects are removed from this entry" ); |
| |
| delete mpBmpEx; |
| delete mpMtf; |
| delete mpAnimation; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| sal_Bool GraphicCacheEntry::ImplInit( const GraphicObject& rObj ) |
| { |
| sal_Bool bRet; |
| |
| if( !rObj.IsSwappedOut() ) |
| { |
| const Graphic& rGraphic = rObj.GetGraphic(); |
| |
| if( mpBmpEx ) |
| delete mpBmpEx, mpBmpEx = NULL; |
| |
| if( mpMtf ) |
| delete mpMtf, mpMtf = NULL; |
| |
| if( mpAnimation ) |
| delete mpAnimation, mpAnimation = NULL; |
| |
| switch( rGraphic.GetType() ) |
| { |
| case( GRAPHIC_BITMAP ): |
| { |
| if(rGraphic.getSvgData().get()) |
| { |
| maSvgData = rGraphic.getSvgData(); |
| } |
| else if( rGraphic.IsAnimated() ) |
| { |
| mpAnimation = new Animation( rGraphic.GetAnimation() ); |
| } |
| else |
| { |
| mpBmpEx = new BitmapEx( rGraphic.GetBitmapEx() ); |
| } |
| } |
| break; |
| |
| case( GRAPHIC_GDIMETAFILE ): |
| { |
| mpMtf = new GDIMetaFile( rGraphic.GetGDIMetaFile() ); |
| } |
| break; |
| |
| default: |
| DBG_ASSERT( GetID().IsEmpty(), "GraphicCacheEntry::ImplInit: Could not initialize graphic! (=>KA)" ); |
| break; |
| } |
| |
| if( rGraphic.IsLink() ) |
| maGfxLink = ( (Graphic&) rGraphic ).GetLink(); |
| else |
| maGfxLink = GfxLink(); |
| |
| bRet = sal_True; |
| } |
| else |
| bRet = sal_False; |
| |
| return bRet; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void GraphicCacheEntry::ImplFillSubstitute( Graphic& rSubstitute ) |
| { |
| // create substitute for graphic; |
| const Size aPrefSize( rSubstitute.GetPrefSize() ); |
| const MapMode aPrefMapMode( rSubstitute.GetPrefMapMode() ); |
| const Link aAnimationNotifyHdl( rSubstitute.GetAnimationNotifyHdl() ); |
| const String aDocFileName( rSubstitute.GetDocFileName() ); |
| const sal_uLong nDocFilePos = rSubstitute.GetDocFilePos(); |
| const GraphicType eOldType = rSubstitute.GetType(); |
| const sal_Bool bDefaultType = ( rSubstitute.GetType() == GRAPHIC_DEFAULT ); |
| |
| if( rSubstitute.IsLink() && ( GFX_LINK_TYPE_NONE == maGfxLink.GetType() ) ) |
| maGfxLink = rSubstitute.GetLink(); |
| |
| if(maSvgData.get()) |
| { |
| rSubstitute = maSvgData; |
| } |
| else if( mpBmpEx ) |
| { |
| rSubstitute = *mpBmpEx; |
| } |
| else if( mpAnimation ) |
| { |
| rSubstitute = *mpAnimation; |
| } |
| else if( mpMtf ) |
| { |
| rSubstitute = *mpMtf; |
| } |
| else |
| { |
| rSubstitute.Clear(); |
| } |
| |
| if( eOldType != GRAPHIC_NONE ) |
| { |
| rSubstitute.SetPrefSize( aPrefSize ); |
| rSubstitute.SetPrefMapMode( aPrefMapMode ); |
| rSubstitute.SetAnimationNotifyHdl( aAnimationNotifyHdl ); |
| rSubstitute.SetDocFileName( aDocFileName, nDocFilePos ); |
| } |
| |
| if( GFX_LINK_TYPE_NONE != maGfxLink.GetType() ) |
| { |
| rSubstitute.SetLink( maGfxLink ); |
| } |
| |
| if( bDefaultType ) |
| { |
| rSubstitute.SetDefaultType(); |
| } |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void GraphicCacheEntry::AddGraphicObjectReference( const GraphicObject& rObj, Graphic& rSubstitute ) |
| { |
| if( mbSwappedAll ) |
| mbSwappedAll = !ImplInit( rObj ); |
| |
| ImplFillSubstitute( rSubstitute ); |
| maGraphicObjectList.Insert( (void*) &rObj, LIST_APPEND ); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| sal_Bool GraphicCacheEntry::ReleaseGraphicObjectReference( const GraphicObject& rObj ) |
| { |
| sal_Bool bRet = sal_False; |
| |
| for( void* pObj = maGraphicObjectList.First(); !bRet && pObj; pObj = maGraphicObjectList.Next() ) |
| { |
| if( &rObj == (GraphicObject*) pObj ) |
| { |
| maGraphicObjectList.Remove( pObj ); |
| bRet = sal_True; |
| } |
| } |
| |
| return bRet; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| sal_Bool GraphicCacheEntry::HasGraphicObjectReference( const GraphicObject& rObj ) |
| { |
| sal_Bool bRet = sal_False; |
| |
| for( void* pObj = maGraphicObjectList.First(); !bRet && pObj; pObj = maGraphicObjectList.Next() ) |
| if( &rObj == (GraphicObject*) pObj ) |
| bRet = sal_True; |
| |
| return bRet; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void GraphicCacheEntry::TryToSwapIn() |
| { |
| if( mbSwappedAll && maGraphicObjectList.Count() ) |
| ( (GraphicObject*) maGraphicObjectList.First() )->FireSwapInRequest(); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void GraphicCacheEntry::GraphicObjectWasSwappedOut( const GraphicObject& /*rObj*/ ) |
| { |
| mbSwappedAll = sal_True; |
| |
| for( void* pObj = maGraphicObjectList.First(); mbSwappedAll && pObj; pObj = maGraphicObjectList.Next() ) |
| if( !( (GraphicObject*) pObj )->IsSwappedOut() ) |
| mbSwappedAll = sal_False; |
| |
| if( mbSwappedAll ) |
| { |
| delete mpBmpEx, mpBmpEx = NULL; |
| delete mpMtf, mpMtf = NULL; |
| delete mpAnimation, mpAnimation = NULL; |
| |
| // #119176# also reset SvgData |
| maSvgData.reset(); |
| } |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| sal_Bool GraphicCacheEntry::FillSwappedGraphicObject( const GraphicObject& rObj, Graphic& rSubstitute ) |
| { |
| sal_Bool bRet; |
| |
| if( !mbSwappedAll && rObj.IsSwappedOut() ) |
| { |
| ImplFillSubstitute( rSubstitute ); |
| bRet = sal_True; |
| } |
| else |
| bRet = sal_False; |
| |
| return bRet; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void GraphicCacheEntry::GraphicObjectWasSwappedIn( const GraphicObject& rObj ) |
| { |
| if( mbSwappedAll ) |
| mbSwappedAll = !ImplInit( rObj ); |
| } |
| |
| // ---------------------------- |
| // - GraphicDisplayCacheEntry - |
| // ---------------------------- |
| |
| class GraphicDisplayCacheEntry |
| { |
| private: |
| |
| ::vos::TTimeValue maReleaseTime; |
| const GraphicCacheEntry* mpRefCacheEntry; |
| GDIMetaFile* mpMtf; |
| BitmapEx* mpBmpEx; |
| GraphicAttr maAttr; |
| Size maOutSizePix; |
| sal_uLong mnCacheSize; |
| sal_uLong mnOutDevDrawMode; |
| sal_uInt16 mnOutDevBitCount; |
| |
| public: |
| |
| static sal_uLong GetNeededSize( OutputDevice* pOut, const Point& rPt, const Size& rSz, |
| const GraphicObject& rObj, const GraphicAttr& rAttr ); |
| |
| public: |
| |
| GraphicDisplayCacheEntry( const GraphicCacheEntry* pRefCacheEntry, |
| OutputDevice* pOut, const Point& rPt, const Size& rSz, |
| const GraphicObject& rObj, const GraphicAttr& rAttr, |
| const BitmapEx& rBmpEx ) : |
| mpRefCacheEntry( pRefCacheEntry ), |
| mpMtf( NULL ), mpBmpEx( new BitmapEx( rBmpEx ) ), |
| maAttr( rAttr ), maOutSizePix( pOut->LogicToPixel( rSz ) ), |
| mnCacheSize( GetNeededSize( pOut, rPt, rSz, rObj, rAttr ) ), |
| mnOutDevDrawMode( pOut->GetDrawMode() ), |
| mnOutDevBitCount( pOut->GetBitCount() ) |
| { |
| } |
| |
| GraphicDisplayCacheEntry( const GraphicCacheEntry* pRefCacheEntry, |
| OutputDevice* pOut, const Point& rPt, const Size& rSz, |
| const GraphicObject& rObj, const GraphicAttr& rAttr, |
| const GDIMetaFile& rMtf ) : |
| mpRefCacheEntry( pRefCacheEntry ), |
| mpMtf( new GDIMetaFile( rMtf ) ), mpBmpEx( NULL ), |
| maAttr( rAttr ), maOutSizePix( pOut->LogicToPixel( rSz ) ), |
| mnCacheSize( GetNeededSize( pOut, rPt, rSz, rObj, rAttr ) ), |
| mnOutDevDrawMode( pOut->GetDrawMode() ), |
| mnOutDevBitCount( pOut->GetBitCount() ) |
| { |
| } |
| |
| |
| ~GraphicDisplayCacheEntry(); |
| |
| const GraphicAttr& GetAttr() const { return maAttr; } |
| const Size& GetOutputSizePixel() const { return maOutSizePix; } |
| sal_uLong GetCacheSize() const { return mnCacheSize; } |
| const GraphicCacheEntry* GetReferencedCacheEntry() const { return mpRefCacheEntry; } |
| sal_uLong GetOutDevDrawMode() const { return mnOutDevDrawMode; } |
| sal_uInt16 GetOutDevBitCount() const { return mnOutDevBitCount; } |
| |
| void SetReleaseTime( const ::vos::TTimeValue& rReleaseTime ) { maReleaseTime = rReleaseTime; } |
| const ::vos::TTimeValue& GetReleaseTime() const { return maReleaseTime; } |
| |
| sal_Bool Matches( OutputDevice* pOut, const Point& /*rPtPixel*/, const Size& rSzPixel, |
| const GraphicCacheEntry* pCacheEntry, const GraphicAttr& rAttr ) const |
| { |
| // #i46805# Additional match |
| // criteria: outdev draw mode and |
| // bit count. One cannot reuse |
| // this cache object, if it's |
| // e.g. generated for |
| // DRAWMODE_GRAYBITMAP. |
| return( ( pCacheEntry == mpRefCacheEntry ) && |
| ( maAttr == rAttr ) && |
| ( ( maOutSizePix == rSzPixel ) || ( !maOutSizePix.Width() && !maOutSizePix.Height() ) ) && |
| ( pOut->GetBitCount() == mnOutDevBitCount ) && |
| ( pOut->GetDrawMode() == mnOutDevDrawMode ) ); |
| } |
| |
| void Draw( OutputDevice* pOut, const Point& rPt, const Size& rSz ) const; |
| }; |
| |
| // ----------------------------------------------------------------------------- |
| |
| sal_uLong GraphicDisplayCacheEntry::GetNeededSize( OutputDevice* pOut, const Point& /*rPt*/, const Size& rSz, |
| const GraphicObject& rObj, const GraphicAttr& rAttr ) |
| { |
| const Graphic& rGraphic = rObj.GetGraphic(); |
| const GraphicType eType = rGraphic.GetType(); |
| sal_uLong nNeededSize; |
| |
| if( GRAPHIC_BITMAP == eType ) |
| { |
| const Size aOutSizePix( pOut->LogicToPixel( rSz ) ); |
| const long nBitCount = pOut->GetBitCount(); |
| |
| if( ( aOutSizePix.Width() > MAX_BMP_EXTENT ) || |
| ( aOutSizePix.Height() > MAX_BMP_EXTENT ) ) |
| { |
| nNeededSize = ULONG_MAX; |
| } |
| else if( nBitCount ) |
| { |
| nNeededSize = aOutSizePix.Width() * aOutSizePix.Height() * nBitCount / 8; |
| |
| if( rObj.IsTransparent() || ( rAttr.GetRotation() % 3600 ) ) |
| nNeededSize += nNeededSize / nBitCount; |
| } |
| else |
| { |
| DBG_ERROR( "GraphicDisplayCacheEntry::GetNeededSize(): pOut->GetBitCount() == 0" ); |
| nNeededSize = 256000; |
| } |
| } |
| else if( GRAPHIC_GDIMETAFILE == eType ) |
| nNeededSize = rGraphic.GetSizeBytes(); |
| else |
| nNeededSize = 0; |
| |
| return nNeededSize; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| GraphicDisplayCacheEntry::~GraphicDisplayCacheEntry() |
| { |
| if( mpMtf ) |
| delete mpMtf; |
| |
| if( mpBmpEx ) |
| delete mpBmpEx; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void GraphicDisplayCacheEntry::Draw( OutputDevice* pOut, const Point& rPt, const Size& rSz ) const |
| { |
| if( mpMtf ) |
| GraphicManager::ImplDraw( pOut, rPt, rSz, *mpMtf, maAttr ); |
| else if( mpBmpEx ) |
| { |
| if( maAttr.IsRotated() ) |
| { |
| Polygon aPoly( Rectangle( rPt, rSz ) ); |
| |
| aPoly.Rotate( rPt, maAttr.GetRotation() % 3600 ); |
| const Rectangle aRotBoundRect( aPoly.GetBoundRect() ); |
| pOut->DrawBitmapEx( aRotBoundRect.TopLeft(), aRotBoundRect.GetSize(), *mpBmpEx ); |
| } |
| else |
| pOut->DrawBitmapEx( rPt, rSz, *mpBmpEx ); |
| } |
| } |
| |
| // ----------------------- |
| // - GraphicCache - |
| // ----------------------- |
| |
| GraphicCache::GraphicCache( GraphicManager& rMgr, sal_uLong nDisplayCacheSize, sal_uLong nMaxObjDisplayCacheSize ) : |
| mrMgr ( rMgr ), |
| mnReleaseTimeoutSeconds ( 0UL ), |
| mnMaxDisplaySize ( nDisplayCacheSize ), |
| mnMaxObjDisplaySize ( nMaxObjDisplayCacheSize ), |
| mnUsedDisplaySize ( 0UL ) |
| { |
| maReleaseTimer.SetTimeoutHdl( LINK( this, GraphicCache, ReleaseTimeoutHdl ) ); |
| maReleaseTimer.SetTimeout( RELEASE_TIMEOUT ); |
| maReleaseTimer.Start(); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| GraphicCache::~GraphicCache() |
| { |
| DBG_ASSERT( !maGraphicCache.Count(), "GraphicCache::~GraphicCache(): there are some GraphicObjects in cache" ); |
| DBG_ASSERT( !maDisplayCache.Count(), "GraphicCache::~GraphicCache(): there are some GraphicObjects in display cache" ); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void GraphicCache::AddGraphicObject( const GraphicObject& rObj, Graphic& rSubstitute, |
| const ByteString* pID, const GraphicObject* pCopyObj ) |
| { |
| sal_Bool bInserted = sal_False; |
| |
| if( !rObj.IsSwappedOut() && |
| ( pID || ( pCopyObj && ( pCopyObj->GetType() != GRAPHIC_NONE ) ) || ( rObj.GetType() != GRAPHIC_NONE ) ) ) |
| { |
| if( pCopyObj ) |
| { |
| GraphicCacheEntry* pEntry = static_cast< GraphicCacheEntry* >( maGraphicCache.First() ); |
| |
| while( !bInserted && pEntry ) |
| { |
| if( pEntry->HasGraphicObjectReference( *pCopyObj ) ) |
| { |
| pEntry->AddGraphicObjectReference( rObj, rSubstitute ); |
| bInserted = sal_True; |
| } |
| else |
| { |
| pEntry = static_cast< GraphicCacheEntry* >( maGraphicCache.Next() ); |
| } |
| } |
| } |
| |
| if( !bInserted ) |
| { |
| GraphicCacheEntry* pEntry = static_cast< GraphicCacheEntry* >( maGraphicCache.First() ); |
| ::std::auto_ptr< GraphicID > apID; |
| |
| if( !pID ) |
| { |
| apID.reset( new GraphicID( rObj ) ); |
| } |
| |
| while( !bInserted && pEntry ) |
| { |
| const GraphicID& rEntryID = pEntry->GetID(); |
| |
| if( pID ) |
| { |
| if( rEntryID.GetIDString() == *pID ) |
| { |
| pEntry->TryToSwapIn(); |
| |
| // since pEntry->TryToSwapIn can modify our current list, we have to |
| // iterate from beginning to add a reference to the appropriate |
| // CacheEntry object; after this, quickly jump out of the outer iteration |
| for( pEntry = static_cast< GraphicCacheEntry* >( maGraphicCache.First() ); |
| !bInserted && pEntry; |
| pEntry = static_cast< GraphicCacheEntry* >( maGraphicCache.Next() ) ) |
| { |
| const GraphicID& rID = pEntry->GetID(); |
| |
| if( rID.GetIDString() == *pID ) |
| { |
| pEntry->AddGraphicObjectReference( rObj, rSubstitute ); |
| bInserted = sal_True; |
| } |
| } |
| |
| if( !bInserted ) |
| { |
| maGraphicCache.Insert( new GraphicCacheEntry( rObj ), LIST_APPEND ); |
| bInserted = sal_True; |
| } |
| } |
| } |
| else |
| { |
| if( rEntryID == *apID ) |
| { |
| pEntry->AddGraphicObjectReference( rObj, rSubstitute ); |
| bInserted = sal_True; |
| } |
| } |
| |
| if( !bInserted ) |
| pEntry = static_cast< GraphicCacheEntry* >( maGraphicCache.Next() ); |
| } |
| } |
| } |
| |
| if( !bInserted ) |
| maGraphicCache.Insert( new GraphicCacheEntry( rObj ), LIST_APPEND ); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void GraphicCache::ReleaseGraphicObject( const GraphicObject& rObj ) |
| { |
| // Release cached object |
| GraphicCacheEntry* pEntry = (GraphicCacheEntry*) maGraphicCache.First(); |
| sal_Bool bRemoved = sal_False; |
| |
| while( !bRemoved && pEntry ) |
| { |
| bRemoved = pEntry->ReleaseGraphicObjectReference( rObj ); |
| |
| if( bRemoved ) |
| { |
| if( 0 == pEntry->GetGraphicObjectReferenceCount() ) |
| { |
| // if graphic cache entry has no more references, |
| // the corresponding display cache object can be removed |
| GraphicDisplayCacheEntry* pDisplayEntry = (GraphicDisplayCacheEntry*) maDisplayCache.First(); |
| |
| while( pDisplayEntry ) |
| { |
| if( pDisplayEntry->GetReferencedCacheEntry() == pEntry ) |
| { |
| mnUsedDisplaySize -= pDisplayEntry->GetCacheSize(); |
| maDisplayCache.Remove( pDisplayEntry ); |
| delete pDisplayEntry; |
| pDisplayEntry = (GraphicDisplayCacheEntry*) maDisplayCache.GetCurObject(); |
| } |
| else |
| pDisplayEntry = (GraphicDisplayCacheEntry*) maDisplayCache.Next(); |
| } |
| |
| // delete graphic cache entry |
| maGraphicCache.Remove( (void*) pEntry ); |
| delete pEntry; |
| } |
| } |
| else |
| pEntry = (GraphicCacheEntry*) maGraphicCache.Next(); |
| } |
| |
| DBG_ASSERT( bRemoved, "GraphicCache::ReleaseGraphicObject(...): GraphicObject not found in cache" ); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void GraphicCache::GraphicObjectWasSwappedOut( const GraphicObject& rObj ) |
| { |
| // notify cache that rObj is swapped out (and can thus be pruned |
| // from the cache) |
| GraphicCacheEntry* pEntry = ImplGetCacheEntry( rObj ); |
| |
| if( pEntry ) |
| pEntry->GraphicObjectWasSwappedOut( rObj ); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| sal_Bool GraphicCache::FillSwappedGraphicObject( const GraphicObject& rObj, Graphic& rSubstitute ) |
| { |
| GraphicCacheEntry* pEntry = ImplGetCacheEntry( rObj ); |
| |
| if( !pEntry ) |
| return sal_False; |
| |
| return pEntry->FillSwappedGraphicObject( rObj, rSubstitute ); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void GraphicCache::GraphicObjectWasSwappedIn( const GraphicObject& rObj ) |
| { |
| GraphicCacheEntry* pEntry = ImplGetCacheEntry( rObj ); |
| |
| if( pEntry ) |
| { |
| if( pEntry->GetID().IsEmpty() ) |
| { |
| ReleaseGraphicObject( rObj ); |
| AddGraphicObject( rObj, (Graphic&) rObj.GetGraphic(), NULL, NULL ); |
| } |
| else |
| pEntry->GraphicObjectWasSwappedIn( rObj ); |
| } |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void GraphicCache::SetMaxDisplayCacheSize( sal_uLong nNewCacheSize ) |
| { |
| mnMaxDisplaySize = nNewCacheSize; |
| |
| if( GetMaxDisplayCacheSize() < GetUsedDisplayCacheSize() ) |
| ImplFreeDisplayCacheSpace( GetUsedDisplayCacheSize() - GetMaxDisplayCacheSize() ); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void GraphicCache::SetMaxObjDisplayCacheSize( sal_uLong nNewMaxObjSize, sal_Bool bDestroyGreaterCached ) |
| { |
| const sal_Bool bDestroy = ( bDestroyGreaterCached && ( nNewMaxObjSize < mnMaxObjDisplaySize ) ); |
| |
| mnMaxObjDisplaySize = Min( nNewMaxObjSize, mnMaxDisplaySize ); |
| |
| if( bDestroy ) |
| { |
| GraphicDisplayCacheEntry* pCacheObj = (GraphicDisplayCacheEntry*) maDisplayCache.First(); |
| |
| while( pCacheObj ) |
| { |
| if( pCacheObj->GetCacheSize() > mnMaxObjDisplaySize ) |
| { |
| mnUsedDisplaySize -= pCacheObj->GetCacheSize(); |
| maDisplayCache.Remove( pCacheObj ); |
| delete pCacheObj; |
| pCacheObj = (GraphicDisplayCacheEntry*) maDisplayCache.GetCurObject(); |
| } |
| else |
| pCacheObj = (GraphicDisplayCacheEntry*) maDisplayCache.Next(); |
| } |
| } |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void GraphicCache::SetCacheTimeout( sal_uLong nTimeoutSeconds ) |
| { |
| if( mnReleaseTimeoutSeconds != nTimeoutSeconds ) |
| { |
| GraphicDisplayCacheEntry* pDisplayEntry = (GraphicDisplayCacheEntry*) maDisplayCache.First(); |
| ::vos::TTimeValue aReleaseTime; |
| |
| if( ( mnReleaseTimeoutSeconds = nTimeoutSeconds ) != 0 ) |
| { |
| osl_getSystemTime( &aReleaseTime ); |
| aReleaseTime.addTime( ::vos::TTimeValue( nTimeoutSeconds, 0 ) ); |
| } |
| |
| while( pDisplayEntry ) |
| { |
| pDisplayEntry->SetReleaseTime( aReleaseTime ); |
| pDisplayEntry = (GraphicDisplayCacheEntry*) maDisplayCache.Next(); |
| } |
| } |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| void GraphicCache::ClearDisplayCache() |
| { |
| for( void* pObj = maDisplayCache.First(); pObj; pObj = maDisplayCache.Next() ) |
| delete (GraphicDisplayCacheEntry*) pObj; |
| |
| maDisplayCache.Clear(); |
| mnUsedDisplaySize = 0UL; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| sal_Bool GraphicCache::IsDisplayCacheable( OutputDevice* pOut, const Point& rPt, const Size& rSz, |
| const GraphicObject& rObj, const GraphicAttr& rAttr ) const |
| { |
| return( GraphicDisplayCacheEntry::GetNeededSize( pOut, rPt, rSz, rObj, rAttr ) <= |
| GetMaxObjDisplayCacheSize() ); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| sal_Bool GraphicCache::IsInDisplayCache( OutputDevice* pOut, const Point& rPt, const Size& rSz, |
| const GraphicObject& rObj, const GraphicAttr& rAttr ) const |
| { |
| const Point aPtPixel( pOut->LogicToPixel( rPt ) ); |
| const Size aSzPixel( pOut->LogicToPixel( rSz ) ); |
| const GraphicCacheEntry* pCacheEntry = ( (GraphicCache*) this )->ImplGetCacheEntry( rObj ); |
| //GraphicDisplayCacheEntry* pDisplayEntry = (GraphicDisplayCacheEntry*) ( (GraphicCache*) this )->maDisplayCache.First(); // -Wall removed .... |
| sal_Bool bFound = sal_False; |
| |
| if( pCacheEntry ) |
| { |
| for( long i = 0, nCount = maDisplayCache.Count(); !bFound && ( i < nCount ); i++ ) |
| if( ( (GraphicDisplayCacheEntry*) maDisplayCache.GetObject( i ) )->Matches( pOut, aPtPixel, aSzPixel, pCacheEntry, rAttr ) ) |
| bFound = sal_True; |
| } |
| |
| return bFound; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| ByteString GraphicCache::GetUniqueID( const GraphicObject& rObj ) const |
| { |
| ByteString aRet; |
| GraphicCacheEntry* pEntry = ( (GraphicCache*) this )->ImplGetCacheEntry( rObj ); |
| |
| // ensure that the entry is correctly initialized (it has to be read at least once) |
| if( pEntry && pEntry->GetID().IsEmpty() ) |
| pEntry->TryToSwapIn(); |
| |
| // do another call to ImplGetCacheEntry in case of modified entry list |
| pEntry = ( (GraphicCache*) this )->ImplGetCacheEntry( rObj ); |
| |
| if( pEntry ) |
| aRet = pEntry->GetID().GetIDString(); |
| |
| return aRet; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| sal_Bool GraphicCache::CreateDisplayCacheObj( OutputDevice* pOut, const Point& rPt, const Size& rSz, |
| const GraphicObject& rObj, const GraphicAttr& rAttr, |
| const BitmapEx& rBmpEx ) |
| { |
| const sal_uLong nNeededSize = GraphicDisplayCacheEntry::GetNeededSize( pOut, rPt, rSz, rObj, rAttr ); |
| sal_Bool bRet = sal_False; |
| |
| if( nNeededSize <= GetMaxObjDisplayCacheSize() ) |
| { |
| if( nNeededSize > GetFreeDisplayCacheSize() ) |
| ImplFreeDisplayCacheSpace( nNeededSize - GetFreeDisplayCacheSize() ); |
| |
| GraphicDisplayCacheEntry* pNewEntry = new GraphicDisplayCacheEntry( ImplGetCacheEntry( rObj ), |
| pOut, rPt, rSz, rObj, rAttr, rBmpEx ); |
| |
| if( GetCacheTimeout() ) |
| { |
| ::vos::TTimeValue aReleaseTime; |
| |
| osl_getSystemTime( &aReleaseTime ); |
| aReleaseTime.addTime( ::vos::TTimeValue( GetCacheTimeout(), 0 ) ); |
| pNewEntry->SetReleaseTime( aReleaseTime ); |
| } |
| |
| maDisplayCache.Insert( pNewEntry, LIST_APPEND ); |
| mnUsedDisplaySize += pNewEntry->GetCacheSize(); |
| bRet = sal_True; |
| } |
| |
| return bRet; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| sal_Bool GraphicCache::CreateDisplayCacheObj( OutputDevice* pOut, const Point& rPt, const Size& rSz, |
| const GraphicObject& rObj, const GraphicAttr& rAttr, |
| const GDIMetaFile& rMtf ) |
| { |
| const sal_uLong nNeededSize = GraphicDisplayCacheEntry::GetNeededSize( pOut, rPt, rSz, rObj, rAttr ); |
| sal_Bool bRet = sal_False; |
| |
| if( nNeededSize <= GetMaxObjDisplayCacheSize() ) |
| { |
| if( nNeededSize > GetFreeDisplayCacheSize() ) |
| ImplFreeDisplayCacheSpace( nNeededSize - GetFreeDisplayCacheSize() ); |
| |
| GraphicDisplayCacheEntry* pNewEntry = new GraphicDisplayCacheEntry( ImplGetCacheEntry( rObj ), |
| pOut, rPt, rSz, rObj, rAttr, rMtf ); |
| |
| if( GetCacheTimeout() ) |
| { |
| ::vos::TTimeValue aReleaseTime; |
| |
| osl_getSystemTime( &aReleaseTime ); |
| aReleaseTime.addTime( ::vos::TTimeValue( GetCacheTimeout(), 0 ) ); |
| pNewEntry->SetReleaseTime( aReleaseTime ); |
| } |
| |
| maDisplayCache.Insert( pNewEntry, LIST_APPEND ); |
| mnUsedDisplaySize += pNewEntry->GetCacheSize(); |
| bRet = sal_True; |
| } |
| |
| return bRet; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| sal_Bool GraphicCache::DrawDisplayCacheObj( OutputDevice* pOut, const Point& rPt, const Size& rSz, |
| const GraphicObject& rObj, const GraphicAttr& rAttr ) |
| { |
| const Point aPtPixel( pOut->LogicToPixel( rPt ) ); |
| const Size aSzPixel( pOut->LogicToPixel( rSz ) ); |
| const GraphicCacheEntry* pCacheEntry = ImplGetCacheEntry( rObj ); |
| GraphicDisplayCacheEntry* pDisplayCacheEntry = (GraphicDisplayCacheEntry*) maDisplayCache.First(); |
| sal_Bool bRet = sal_False; |
| |
| while( !bRet && pDisplayCacheEntry ) |
| { |
| if( pDisplayCacheEntry->Matches( pOut, aPtPixel, aSzPixel, pCacheEntry, rAttr ) ) |
| { |
| ::vos::TTimeValue aReleaseTime; |
| |
| // put found object at last used position |
| maDisplayCache.Insert( maDisplayCache.Remove( pDisplayCacheEntry ), LIST_APPEND ); |
| |
| if( GetCacheTimeout() ) |
| { |
| osl_getSystemTime( &aReleaseTime ); |
| aReleaseTime.addTime( ::vos::TTimeValue( GetCacheTimeout(), 0 ) ); |
| } |
| |
| pDisplayCacheEntry->SetReleaseTime( aReleaseTime ); |
| bRet = sal_True; |
| } |
| else |
| pDisplayCacheEntry = (GraphicDisplayCacheEntry*) maDisplayCache.Next(); |
| } |
| |
| if( bRet ) |
| pDisplayCacheEntry->Draw( pOut, rPt, rSz ); |
| |
| return bRet; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| sal_Bool GraphicCache::ImplFreeDisplayCacheSpace( sal_uLong nSizeToFree ) |
| { |
| sal_uLong nFreedSize = 0UL; |
| |
| if( nSizeToFree ) |
| { |
| void* pObj = maDisplayCache.First(); |
| |
| if( nSizeToFree > mnUsedDisplaySize ) |
| nSizeToFree = mnUsedDisplaySize; |
| |
| while( pObj ) |
| { |
| GraphicDisplayCacheEntry* pCacheObj = (GraphicDisplayCacheEntry*) pObj; |
| |
| nFreedSize += pCacheObj->GetCacheSize(); |
| mnUsedDisplaySize -= pCacheObj->GetCacheSize(); |
| maDisplayCache.Remove( pObj ); |
| delete pCacheObj; |
| |
| if( nFreedSize >= nSizeToFree ) |
| break; |
| else |
| pObj = maDisplayCache.GetCurObject(); |
| } |
| } |
| |
| return( nFreedSize >= nSizeToFree ); |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| GraphicCacheEntry* GraphicCache::ImplGetCacheEntry( const GraphicObject& rObj ) |
| { |
| GraphicCacheEntry* pRet = NULL; |
| |
| for( void* pObj = maGraphicCache.First(); !pRet && pObj; pObj = maGraphicCache.Next() ) |
| if( ( (GraphicCacheEntry*) pObj )->HasGraphicObjectReference( rObj ) ) |
| pRet = (GraphicCacheEntry*) pObj; |
| |
| return pRet; |
| } |
| |
| // ----------------------------------------------------------------------------- |
| |
| IMPL_LINK( GraphicCache, ReleaseTimeoutHdl, Timer*, pTimer ) |
| { |
| pTimer->Stop(); |
| |
| ::vos::TTimeValue aCurTime; |
| GraphicDisplayCacheEntry* pDisplayEntry = (GraphicDisplayCacheEntry*) maDisplayCache.First(); |
| |
| osl_getSystemTime( &aCurTime ); |
| |
| while( pDisplayEntry ) |
| { |
| const ::vos::TTimeValue& rReleaseTime = pDisplayEntry->GetReleaseTime(); |
| |
| if( !rReleaseTime.isEmpty() && ( rReleaseTime < aCurTime ) ) |
| { |
| mnUsedDisplaySize -= pDisplayEntry->GetCacheSize(); |
| maDisplayCache.Remove( pDisplayEntry ); |
| delete pDisplayEntry; |
| pDisplayEntry = (GraphicDisplayCacheEntry*) maDisplayCache.GetCurObject(); |
| } |
| else |
| pDisplayEntry = (GraphicDisplayCacheEntry*) maDisplayCache.Next(); |
| } |
| |
| pTimer->Start(); |
| |
| return 0; |
| } |