[Libreoffice-commits] core.git: Branch 'aoo/trunk' - svtools/inc svtools/source sw/source vcl/win
Armin Le Grand
alg at apache.org
Thu Jun 19 11:08:01 PDT 2014
svtools/inc/svtools/grfmgr.hxx | 24 +++++++++++-
svtools/source/graphic/grfmgr.cxx | 47 ++++++++++++++++++++++++
svtools/source/graphic/grfmgr2.cxx | 72 ++++++++++++++++++++++++++++++++++++-
sw/source/core/doc/notxtfrm.cxx | 3 +
sw/source/core/graphic/ndgrf.cxx | 36 ++++++++++++++----
vcl/win/source/gdi/salbmp.cxx | 54 +++++++++++++++------------
6 files changed, 204 insertions(+), 32 deletions(-)
New commits:
commit 61b32a70c92ee1b1148bcd9788561b79dc1910c8
Author: Armin Le Grand <alg at apache.org>
Date: Thu Jun 19 16:49:26 2014 +0000
i125111 limit mem footprint for GraphicObjects in 32Bit environments
diff --git a/svtools/inc/svtools/grfmgr.hxx b/svtools/inc/svtools/grfmgr.hxx
index ca2e10b..a30df40 100644
--- a/svtools/inc/svtools/grfmgr.hxx
+++ b/svtools/inc/svtools/grfmgr.hxx
@@ -207,7 +207,10 @@ private:
Timer* mpSwapOutTimer;
GrfSimpleCacheObj* mpSimpleCache;
sal_uLong mnAnimationLoopCount;
- void* mpDummy1;
+
+ // a unique increasing ID to be able to say which data change is older
+ sal_uLong mnDataChangeTimeStamp;
+
void* mpDummy2;
sal_Bool mbAutoSwapped : 1;
sal_Bool mbTransparent : 1;
@@ -299,6 +302,10 @@ private:
DECL_LINK( ImplAutoSwapOutHdl, void* );
+ // Handle evtl. needed AfterDataChanges, needs to be called when new
+ // graphic data is swapped in/added to the GraphicManager
+ void ImplAfterDataChange();
+
protected:
virtual void GraphicManagerDestroyed();
@@ -481,6 +488,12 @@ public:
double fTopCrop,
double fRightCrop,
double fBottomCrop) const;
+
+ // read access
+ sal_uLong GetDataChangeTimeStamp() const { return mnDataChangeTimeStamp; }
+
+ // restart SwapOut timer; this is like touching in a cache to reset to the full timeout value
+ void restartSwapOutTimer() const;
};
// ------------------
@@ -545,6 +558,15 @@ private:
ByteString SVT_DLLPRIVATE ImplGetUniqueID( const GraphicObject& rObj ) const;
+ // This method allows to check memory footprint for all currently swapped in GraphicObjects on this GraphicManager
+ // which are based on Bitmaps. This is needed on 32Bit systems and only does something on those systems. The problem
+ // to solve is that normally the SwapOut is timer-driven, but even with short timer settings there are situations
+ // where this does not trigger - or in other words: A maximum limitation for GraphicManagers was not in place before.
+ // For 32Bit systems this leads to situations where graphics will be missing. This method will actively swap out
+ // the longest swapped in graphics until a maximum memory boundary (derived from user settings in tools/options/memory)
+ // is no longer exceeded
+ void ImplCheckSizeOfSwappedInGraphics();
+
public:
GraphicManager( sal_uLong nCacheSize = 10000000UL, sal_uLong nMaxObjCacheSize = 2400000UL );
diff --git a/svtools/source/graphic/grfmgr.cxx b/svtools/source/graphic/grfmgr.cxx
index 59dc21b..00cfcc0 100644
--- a/svtools/source/graphic/grfmgr.cxx
+++ b/svtools/source/graphic/grfmgr.cxx
@@ -76,6 +76,19 @@ struct GrfSimpleCacheObj
TYPEINIT1_AUTOFACTORY( GraphicObject, SvDataCopyStream );
+// unique increasing ID for being able to detect the GraphicObject with the
+// oldest last data changes
+static sal_uLong aIncrementingTimeOfLastDataChange = 1;
+
+void GraphicObject::ImplAfterDataChange()
+{
+ // set unique timestamp ID of last data change
+ mnDataChangeTimeStamp = aIncrementingTimeOfLastDataChange++;
+
+ // check memory footprint of all GraphicObjects managed and evtl. take action
+ GetGraphicManager().ImplCheckSizeOfSwappedInGraphics();
+}
+
// -----------------------------------------------------------------------------
GraphicObject::GraphicObject( const GraphicManager* pMgr ) :
@@ -173,6 +186,9 @@ void GraphicObject::ImplConstruct()
mbAutoSwapped = sal_False;
mbIsInSwapIn = sal_False;
mbIsInSwapOut = sal_False;
+
+ // Init with a unique, increasing ID
+ mnDataChangeTimeStamp = aIncrementingTimeOfLastDataChange++;
}
// -----------------------------------------------------------------------------
@@ -290,6 +306,9 @@ void GraphicObject::ImplAutoSwapIn()
if( !mbAutoSwapped && mpMgr )
mpMgr->ImplGraphicObjectWasSwappedIn( *this );
}
+
+ // Handle evtl. needed AfterDataChanges
+ ImplAfterDataChange();
}
}
@@ -914,6 +933,9 @@ void GraphicObject::SetGraphic( const Graphic& rGraphic, const GraphicObject* pC
if( mpSwapOutTimer )
mpSwapOutTimer->Start();
+
+ // Handle evtl. needed AfterDataChanges
+ ImplAfterDataChange();
}
// -----------------------------------------------------------------------------
@@ -1255,7 +1277,9 @@ sal_Bool GraphicObject::SwapIn()
bRet = sal_True;
}
else if( mpMgr && mpMgr->ImplFillSwappedGraphicObject( *this, maGraphic ) )
+ {
bRet = sal_True;
+ }
else
{
bRet = maGraphic.SwapIn();
@@ -1265,8 +1289,13 @@ sal_Bool GraphicObject::SwapIn()
}
if( bRet )
+ {
ImplAssignGraphicData();
+ // Handle evtl. needed AfterDataChanges
+ ImplAfterDataChange();
+ }
+
return bRet;
}
@@ -1282,7 +1311,9 @@ sal_Bool GraphicObject::SwapIn( SvStream* pIStm )
bRet = sal_True;
}
else if( mpMgr && mpMgr->ImplFillSwappedGraphicObject( *this, maGraphic ) )
+ {
bRet = sal_True;
+ }
else
{
bRet = maGraphic.SwapIn( pIStm );
@@ -1292,8 +1323,13 @@ sal_Bool GraphicObject::SwapIn( SvStream* pIStm )
}
if( bRet )
+ {
ImplAssignGraphicData();
+ //
+ ImplAfterDataChange();
+ }
+
return bRet;
}
@@ -1453,4 +1489,15 @@ basegfx::B2DVector GraphicObject::calculateCropScaling(
return basegfx::B2DVector(fFactorX,fFactorY);
}
+// ------------------------------------------------------------------------
+// restart SwapOut timer
+
+void GraphicObject::restartSwapOutTimer() const
+{
+ if( mpSwapOutTimer && mpSwapOutTimer->IsActive() )
+ {
+ mpSwapOutTimer->Start();
+ }
+}
+
// eof
diff --git a/svtools/source/graphic/grfmgr2.cxx b/svtools/source/graphic/grfmgr2.cxx
index c599a1d..c8532bb 100644
--- a/svtools/source/graphic/grfmgr2.cxx
+++ b/svtools/source/graphic/grfmgr2.cxx
@@ -295,9 +295,79 @@ ByteString GraphicManager::ImplGetUniqueID( const GraphicObject& rObj ) const
// -----------------------------------------------------------------------------
+void GraphicManager::ImplCheckSizeOfSwappedInGraphics()
+{
+ // only necessary for 32bit systems
+ if(SAL_TYPES_SIZEOFPOINTER <= 4)
+ {
+ // get the currently used memory footprint of all swapped in bitmap graphics
+ // of this graphic manager. Remember candidates in a vector. The size in bytes is
+ // already available, thus this loop is not expensive to execute
+ sal_uLong nUsedSize(0);
+ GraphicObject* pObj = 0;
+ std::vector< GraphicObject* > aCandidates;
+
+ for(pObj = (GraphicObject*)maObjList.First(); pObj; pObj = (GraphicObject*)maObjList.Next())
+ {
+ if(pObj->meType == GRAPHIC_BITMAP && !pObj->IsSwappedOut() && pObj->GetSizeBytes())
+ {
+ aCandidates.push_back(pObj);
+ nUsedSize += pObj->GetSizeBytes();
+ }
+ }
+
+ // detect maximum allowed memory footprint. Use the user-settings of MaxCacheSize (defaulted
+ // to 20MB) and add a decent multiplicator (expecrimented to find one). Limit to
+ // a useful maximum for 32Bit address space
+
+ // default is 20MB, so allow 200MB initially
+ static sal_uLong aMultiplicator(10);
+
+ // max at 500MB; I experimented with 800 for debug and 750 for non-debug settings (pics start
+ // missing when AOO reaches a mem footprint of 1.5GB) but some secure left over space for
+ // app activity is needed
+ static sal_uLong aMaxSize32Bit(500 * 1024 * 1024);
+
+ // calc max allowed cache size
+ const sal_uLong nMaxCacheSize(::std::min(GetMaxCacheSize() * aMultiplicator, aMaxSize32Bit));
+
+ if(nUsedSize >= nMaxCacheSize && !aCandidates.empty())
+ {
+ // if we use more currently, sort by last DataChangeTimeStamp
+ struct simpleSortByDataChangeTimeStamp
+ {
+ bool operator() (GraphicObject* p1, GraphicObject* p2) const
+ {
+ return p1->GetDataChangeTimeStamp() < p2->GetDataChangeTimeStamp();
+ }
+ };
+
+ // sort by DataChangeTimeStamp so that the oldest get removed first
+ ::std::sort(aCandidates.begin(), aCandidates.end(), simpleSortByDataChangeTimeStamp());
+
+ for(sal_uInt32 a(0); nUsedSize >= nMaxCacheSize && a < aCandidates.size(); a++)
+ {
+ // swap out until we have no more or the goal to use less than nMaxCacheSize
+ // is reached
+ pObj = aCandidates[a];
+ const sal_uLong nSizeBytes(pObj->GetSizeBytes());
+
+ // do not swap out when we have less than 16KB data objects
+ if(nSizeBytes >= (16 * 1024))
+ {
+ pObj->FireSwapOutRequest();
+ nUsedSize = (nSizeBytes < nUsedSize) ? nUsedSize - nSizeBytes : 0;
+ }
+ }
+ }
+ }
+}
+
+// -----------------------------------------------------------------------------
+
sal_Bool GraphicManager::ImplFillSwappedGraphicObject( const GraphicObject& rObj, Graphic& rSubstitute )
{
- return( mpCache->FillSwappedGraphicObject( rObj, rSubstitute ) );
+ return mpCache->FillSwappedGraphicObject(rObj, rSubstitute);
}
// -----------------------------------------------------------------------------
diff --git a/sw/source/core/doc/notxtfrm.cxx b/sw/source/core/doc/notxtfrm.cxx
index 95eb23c..d96023a 100644
--- a/sw/source/core/doc/notxtfrm.cxx
+++ b/sw/source/core/doc/notxtfrm.cxx
@@ -1019,6 +1019,9 @@ void SwNoTxtFrm::PaintPicture( OutputDevice* pOut, const SwRect &rGrfArea ) cons
aContent,
aTargetRange,
aTargetRange);
+
+ // need to reset the timer manually (was in original paints at GraphicManager)
+ rGrfObj.restartSwapOutTimer();
}
}
else
diff --git a/sw/source/core/graphic/ndgrf.cxx b/sw/source/core/graphic/ndgrf.cxx
index bf789f1..2ba4518 100644
--- a/sw/source/core/graphic/ndgrf.cxx
+++ b/sw/source/core/graphic/ndgrf.cxx
@@ -58,14 +58,36 @@
#include <retrieveinputstreamconsumer.hxx>
#include <drawinglayer/processor2d/objectinfoextractor2d.hxx>
#include <drawinglayer/primitive2d/objectinfoprimitive2d.hxx>
+#include <unotools/cacheoptions.hxx>
using namespace com::sun::star;
+#define SWAPGRAPHIC_TIMEOUT 5000
-// As Writer graphics are no longer painted via the graphic manager - see <SwNoTxtFrm::PaintPicture(..)> -
-// it is needed to swap out the Writer graphics automatically after a certain amount of time.
-// --> 5000ms
-#define TIMETOSWAPOUTGRAPHICAUTOMATICALLY 5000
+// For comments see same method used in svx
+sal_uInt32 getCacheTimeInMs()
+{
+ static bool bSetAtAll(true);
+
+ if(bSetAtAll)
+ {
+ static bool bSetToPreferenceTime(true);
+
+ if(bSetToPreferenceTime)
+ {
+ const SvtCacheOptions aCacheOptions;
+ const sal_Int32 nSeconds(aCacheOptions.GetGraphicManagerObjectReleaseTime());
+
+ return nSeconds * 1000 / 12;
+ }
+ else
+ {
+ return SWAPGRAPHIC_TIMEOUT;
+ }
+ }
+
+ return 0;
+}
// --------------------
// SwGrfNode
@@ -83,7 +105,7 @@ SwGrfNode::SwGrfNode(
mbLinkedInputStreamReady( false ),
mbIsStreamReadOnly( sal_False )
{
- maGrfObj.SetSwapStreamHdl( LINK( this, SwGrfNode, SwapGraphic ), TIMETOSWAPOUTGRAPHICAUTOMATICALLY );
+ maGrfObj.SetSwapStreamHdl( LINK( this, SwGrfNode, SwapGraphic ), getCacheTimeInMs() );
bInSwapIn = bChgTwipSize = bChgTwipSizeFromPixel = bLoadLowResGrf = bFrameInPaint = bScaleImageMap = sal_False;
bGrafikArrived = sal_True;
@@ -102,7 +124,7 @@ SwGrfNode::SwGrfNode(
mbIsStreamReadOnly( sal_False )
{
maGrfObj = rGrfObj;
- maGrfObj.SetSwapStreamHdl( LINK( this, SwGrfNode, SwapGraphic ), TIMETOSWAPOUTGRAPHICAUTOMATICALLY );
+ maGrfObj.SetSwapStreamHdl( LINK( this, SwGrfNode, SwapGraphic ), getCacheTimeInMs() );
if ( rGrfObj.HasUserData() && rGrfObj.IsSwappedOut() )
maGrfObj.SetSwapState();
bInSwapIn = bChgTwipSize = bChgTwipSizeFromPixel = bLoadLowResGrf = bFrameInPaint = bScaleImageMap = sal_False;
@@ -125,7 +147,7 @@ SwGrfNode::SwGrfNode(
mbLinkedInputStreamReady( false ),
mbIsStreamReadOnly( sal_False )
{
- maGrfObj.SetSwapStreamHdl( LINK( this, SwGrfNode, SwapGraphic ), TIMETOSWAPOUTGRAPHICAUTOMATICALLY );
+ maGrfObj.SetSwapStreamHdl( LINK( this, SwGrfNode, SwapGraphic ), getCacheTimeInMs() );
Graphic aGrf;
aGrf.SetDefaultType();
diff --git a/vcl/win/source/gdi/salbmp.cxx b/vcl/win/source/gdi/salbmp.cxx
index 0173b8e..f4578ed 100644
--- a/vcl/win/source/gdi/salbmp.cxx
+++ b/vcl/win/source/gdi/salbmp.cxx
@@ -448,35 +448,43 @@ Gdiplus::Bitmap* WinSalBitmap::ImplCreateGdiPlusBitmap(const WinSalBitmap& rAlph
if(pRetval)
{
- sal_uInt8* pSrcRGB(pRGB->mpBits);
- sal_uInt8* pSrcA(pA->mpBits);
- const sal_uInt32 nExtraRGB(pRGB->mnScanlineSize - (nW * 3));
- const sal_uInt32 nExtraA(pA->mnScanlineSize - nW);
- const bool bTopDown(pRGB->mnFormat & BMP_FORMAT_TOP_DOWN);
- const Gdiplus::Rect aAllRect(0, 0, nW, nH);
- Gdiplus::BitmapData aGdiPlusBitmapData;
- pRetval->LockBits(&aAllRect, Gdiplus::ImageLockModeWrite, PixelFormat32bppARGB, &aGdiPlusBitmapData);
-
- // copy data to Gdiplus::Bitmap; format is BGRA; need to mix BGR from Bitmap and
- // A from alpha, so inner loop is needed (who invented BitmapEx..?)
- for(sal_uInt32 y(0); y < nH; y++)
+ if ( pRetval->GetLastStatus() == Gdiplus::Ok ) // 2nd place to secure with new Gdiplus::Bitmap
{
- const sal_uInt32 nYInsert(bTopDown ? y : nH - y - 1);
- sal_uInt8* targetPixels = (sal_uInt8*)aGdiPlusBitmapData.Scan0 + (nYInsert * aGdiPlusBitmapData.Stride);
+ sal_uInt8* pSrcRGB(pRGB->mpBits);
+ sal_uInt8* pSrcA(pA->mpBits);
+ const sal_uInt32 nExtraRGB(pRGB->mnScanlineSize - (nW * 3));
+ const sal_uInt32 nExtraA(pA->mnScanlineSize - nW);
+ const bool bTopDown(pRGB->mnFormat & BMP_FORMAT_TOP_DOWN);
+ const Gdiplus::Rect aAllRect(0, 0, nW, nH);
+ Gdiplus::BitmapData aGdiPlusBitmapData;
+ pRetval->LockBits(&aAllRect, Gdiplus::ImageLockModeWrite, PixelFormat32bppARGB, &aGdiPlusBitmapData);
- for(sal_uInt32 x(0); x < nW; x++)
+ // copy data to Gdiplus::Bitmap; format is BGRA; need to mix BGR from Bitmap and
+ // A from alpha, so inner loop is needed (who invented BitmapEx..?)
+ for(sal_uInt32 y(0); y < nH; y++)
{
- *targetPixels++ = *pSrcRGB++;
- *targetPixels++ = *pSrcRGB++;
- *targetPixels++ = *pSrcRGB++;
- *targetPixels++ = 0xff - *pSrcA++;
+ const sal_uInt32 nYInsert(bTopDown ? y : nH - y - 1);
+ sal_uInt8* targetPixels = (sal_uInt8*)aGdiPlusBitmapData.Scan0 + (nYInsert * aGdiPlusBitmapData.Stride);
+
+ for(sal_uInt32 x(0); x < nW; x++)
+ {
+ *targetPixels++ = *pSrcRGB++;
+ *targetPixels++ = *pSrcRGB++;
+ *targetPixels++ = *pSrcRGB++;
+ *targetPixels++ = 0xff - *pSrcA++;
+ }
+
+ pSrcRGB += nExtraRGB;
+ pSrcA += nExtraA;
}
- pSrcRGB += nExtraRGB;
- pSrcA += nExtraA;
+ pRetval->UnlockBits(&aGdiPlusBitmapData);
+ }
+ else
+ {
+ delete pRetval;
+ pRetval = NULL;
}
-
- pRetval->UnlockBits(&aGdiPlusBitmapData);
}
}
More information about the Libreoffice-commits
mailing list