tdf#123165 cache recently scaled bitmaps for reuse

dropping the cached scaled bitmap when the bitmap
is accesed via BitmapAccessMode::Write for writing

Change-Id: Ib6539522944838238bd699ec3531039d21dc0f8b
Reviewed-on: https://gerrit.libreoffice.org/67459
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
Tested-by: Caolán McNamara <caolanm@redhat.com>
diff --git a/vcl/inc/salbmp.hxx b/vcl/inc/salbmp.hxx
index 9e58c3b..5b020f6 100644
--- a/vcl/inc/salbmp.hxx
+++ b/vcl/inc/salbmp.hxx
@@ -73,6 +73,8 @@ public:

    virtual bool            ScalingSupported() const = 0;
    virtual bool            Scale( const double& rScaleX, const double& rScaleY, BmpScaleFlag nScaleFlag ) = 0;
    void                    DropScaledCache();

    virtual bool            Replace( const Color& rSearchColor, const Color& rReplaceColor, sal_uInt8 nTol ) = 0;

    virtual bool            ConvertToGreyscale()
diff --git a/vcl/inc/svdata.hxx b/vcl/inc/svdata.hxx
index ea48d77..08c1e5a 100644
--- a/vcl/inc/svdata.hxx
+++ b/vcl/inc/svdata.hxx
@@ -22,6 +22,7 @@

#include <config_version.h>

#include <o3tl/lru_map.hxx>
#include <tools/fldunit.hxx>
#include <unotools/options.hxx>
#include <vcl/bitmapex.hxx>
@@ -194,6 +195,7 @@ struct ImplSVGDIData
    std::unique_ptr<ImplPrnQueueList> mpPrinterQueueList;   // List of all printer queue
    std::shared_ptr<PhysicalFontCollection> mxScreenFontList; // Screen-Font-List
    std::shared_ptr<ImplFontCache> mxScreenFontCache;       // Screen-Font-Cache
    o3tl::lru_map<SalBitmap*, BitmapEx> maScaleCache = o3tl::lru_map<SalBitmap*, BitmapEx>(10); // Cache for scaled images
    ImplDirectFontSubstitution* mpDirectFontSubst = nullptr; // Font-Substitutions defined in Tools->Options->Fonts
    GraphicConverter*       mpGrfConverter = nullptr;       // Converter for graphics
    long                    mnAppFontX = 0;                 // AppFont X-Numenator for 40/tel Width
diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx
index f55c6fc..fd769b9 100644
--- a/vcl/source/app/salvtables.cxx
+++ b/vcl/source/app/salvtables.cxx
@@ -144,8 +144,19 @@ SalTimer::~SalTimer() COVERITY_NOEXCEPT_FALSE
{
}

void SalBitmap::DropScaledCache()
{
    if (ImplSVData* pSVData = ImplGetSVData())
    {
        auto& rCache = pSVData->maGDIData.maScaleCache;
        rCache.remove_if([this] (const o3tl::lru_map<SalBitmap*, BitmapEx>::key_value_pair_t& rKeyValuePair)
                         { return rKeyValuePair.first == this; });
    }
}

SalBitmap::~SalBitmap()
{
    DropScaledCache();
}

SalI18NImeStatus::~SalI18NImeStatus()
diff --git a/vcl/source/app/svmain.cxx b/vcl/source/app/svmain.cxx
index ce825e7..c543732 100644
--- a/vcl/source/app/svmain.cxx
+++ b/vcl/source/app/svmain.cxx
@@ -574,6 +574,8 @@ void DeInitVCL()

    pSVData->maGDIData.mxScreenFontList.reset();
    pSVData->maGDIData.mxScreenFontCache.reset();
    pSVData->maGDIData.maScaleCache.remove_if([](const o3tl::lru_map<SalBitmap*, BitmapEx>::key_value_pair_t&)
                                                { return true; });

    // Deinit Sal
    if (pSVData->mpDefInst)
diff --git a/vcl/source/bitmap/BitmapScaleSuperFilter.cxx b/vcl/source/bitmap/BitmapScaleSuperFilter.cxx
index 9f4eabf..ea73f3b 100644
--- a/vcl/source/bitmap/BitmapScaleSuperFilter.cxx
+++ b/vcl/source/bitmap/BitmapScaleSuperFilter.cxx
@@ -27,6 +27,7 @@

#include <algorithm>
#include <memory>
#include <svdata.hxx>
#include <sal/log.hxx>

namespace {
@@ -934,6 +935,7 @@ BitmapScaleSuperFilter::~BitmapScaleSuperFilter()
BitmapEx BitmapScaleSuperFilter::execute(BitmapEx const& rBitmap) const
{
    Bitmap aBitmap(rBitmap.GetBitmap());
    SalBitmap* pKey = aBitmap.ImplGetSalBitmap().get();

    bool bRet = false;

@@ -953,6 +955,16 @@ BitmapEx BitmapScaleSuperFilter::execute(BitmapEx const& rBitmap) const
    if (nDstW <= 1 || nDstH <= 1)
        return BitmapEx();

    // check cache for a previously scaled version of this
    ImplSVData* pSVData = ImplGetSVData();
    auto& rCache = pSVData->maGDIData.maScaleCache;
    auto aFind = rCache.find(pKey);
    if (aFind != rCache.end())
    {
        if (aFind->second.GetSizePixel().Width() == nDstW && aFind->second.GetSizePixel().Height() == nDstH)
            return aFind->second;
    }

    {
        Bitmap::ScopedReadAccess pReadAccess(aBitmap);

@@ -1076,7 +1088,9 @@ BitmapEx BitmapScaleSuperFilter::execute(BitmapEx const& rBitmap) const
    {
        tools::Rectangle aRect(Point(0, 0), Point(nDstW, nDstH));
        aBitmap.Crop(aRect);
        return BitmapEx(aBitmap);
        BitmapEx aRet(aBitmap);
        rCache.insert(std::make_pair(pKey, aRet));
        return aRet;
    }

    return BitmapEx();
diff --git a/vcl/source/gdi/bmpacc.cxx b/vcl/source/gdi/bmpacc.cxx
index af8d753..cc4e86a 100644
--- a/vcl/source/gdi/bmpacc.cxx
+++ b/vcl/source/gdi/bmpacc.cxx
@@ -41,11 +41,16 @@ BitmapInfoAccess::BitmapInfoAccess( Bitmap& rBitmap, BitmapAccessMode nMode ) :
    if( !xImpBmp )
        return;

    if( mnAccessMode == BitmapAccessMode::Write && xImpBmp.use_count() > 2 )
    if (mnAccessMode == BitmapAccessMode::Write)
    {
        xImpBmp.reset();
        rBitmap.ImplMakeUnique();
        xImpBmp = rBitmap.ImplGetSalBitmap();
        xImpBmp->DropScaledCache();

        if (xImpBmp.use_count() > 2)
        {
            xImpBmp.reset();
            rBitmap.ImplMakeUnique();
            xImpBmp = rBitmap.ImplGetSalBitmap();
        }
    }

    mpBuffer = xImpBmp->AcquireBuffer( mnAccessMode );