vcl/inc/salbmp.hxx                |    5 +
 vcl/inc/skia/gdiimpl.hxx          |    6 +
 vcl/inc/skia/salbmp.hxx           |   15 ++++
 vcl/skia/gdiimpl.cxx              |   87 +++++++++++++++++-------
 vcl/skia/salbmp.cxx               |  134 +++++++++++++++++++++++++++++++++++++-
 vcl/source/bitmap/bitmappaint.cxx |   13 +++
 6 files changed, 231 insertions(+), 29 deletions(-)

New commits:
commit d1fcc9053f98cc4afb52498b40a836884bb5ec6f
Author:     Luboš Luňák <l.lu...@collabora.com>
AuthorDate: Tue Jun 30 10:19:34 2020 +0200
Commit:     Luboš Luňák <l.lu...@collabora.com>
CommitDate: Wed Jul 1 07:36:39 2020 +0200

    optimize Bitmap::Erase() for Skia by delaying the erase (tdf#134363)
    
    Tdf#134363 causes OutputDevice::DrawTransformBitmapExDirect()
    to create a huge 1bpp bitmap as mask, and Skia code then tries
    to convert all the bits to a format Skia would understand. Which
    is wasteful, as SkShader with the color given will do the same
    task much more efficiently.
    
    Change-Id: If0bba16f56fed9c3720be801b25a1e703054ed8d
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/97488
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lu...@collabora.com>

diff --git a/vcl/inc/salbmp.hxx b/vcl/inc/salbmp.hxx
index 4244ae1a376f..ab16b317d7eb 100644
--- a/vcl/inc/salbmp.hxx
+++ b/vcl/inc/salbmp.hxx
@@ -86,6 +86,11 @@ public:
         return false;
     }
 
+    virtual bool            Erase( const Color& /*color*/ )
+    {
+        return false;
+    }
+
     void GetChecksum(BitmapChecksum& rChecksum) const
     {
         updateChecksum();
diff --git a/vcl/inc/skia/gdiimpl.hxx b/vcl/inc/skia/gdiimpl.hxx
index 73fbee394072..c98038807287 100644
--- a/vcl/inc/skia/gdiimpl.hxx
+++ b/vcl/inc/skia/gdiimpl.hxx
@@ -200,10 +200,14 @@ public:
 #endif
 
     // Default blend mode for SkPaint is SkBlendMode::kSrcOver
+    void drawBitmap(const SalTwoRect& rPosAry, const SkiaSalBitmap& bitmap,
+                    SkBlendMode blendMode = SkBlendMode::kSrcOver);
+
     void drawImage(const SalTwoRect& rPosAry, const sk_sp<SkImage>& aImage,
                    SkBlendMode eBlendMode = SkBlendMode::kSrcOver);
 
-    void drawShader(const SalTwoRect& rPosAry, const sk_sp<SkShader>& shader);
+    void drawShader(const SalTwoRect& rPosAry, const sk_sp<SkShader>& shader,
+                    SkBlendMode blendMode = SkBlendMode::kSrcOver);
 
     enum class GlyphOrientation
     {
diff --git a/vcl/inc/skia/salbmp.hxx b/vcl/inc/skia/salbmp.hxx
index d5491e367700..4ee6e4908ee7 100644
--- a/vcl/inc/skia/salbmp.hxx
+++ b/vcl/inc/skia/salbmp.hxx
@@ -59,13 +59,24 @@ public:
                          sal_uInt8 nTol) override;
     virtual bool InterpretAs8Bit() override;
     virtual bool ConvertToGreyscale() override;
+    virtual bool Erase(const Color& color) override;
 
     const BitmapPalette& Palette() const { return mPalette; }
+
+    // True if GetSkShader() should be preferred to GetSkImage() (or the Alpha 
variants).
+    bool PreferSkShader() const;
+
     // Returns the contents as SkImage (possibly GPU-backed).
     const sk_sp<SkImage>& GetSkImage() const;
+    sk_sp<SkShader> GetSkShader() const;
 
     // Returns the contents as alpha SkImage (possibly GPU-backed)
     const sk_sp<SkImage>& GetAlphaSkImage() const;
+    sk_sp<SkShader> GetAlphaSkShader() const;
+
+    // Key for caching/hashing.
+    OString GetImageKey() const;
+    OString GetAlphaImageKey() const;
 
 #ifdef DBG_UTIL
     void dump(const char* file) const;
@@ -86,6 +97,7 @@ private:
     void EnsureBitmapUniqueData();
     // Allocate mBuffer (with uninitialized contents).
     bool CreateBitmapData();
+    void EraseInternal();
     SkBitmap GetAsSkBitmap() const;
 #ifdef DBG_UTIL
     void verify() const;
@@ -126,6 +138,9 @@ private:
     // data in mBuffer, if it differs from mSize, then there is a scaling 
operation pending.
     Size mPixelsSize;
     SkFilterQuality mScaleQuality = kHigh_SkFilterQuality; // quality for 
on-demand scaling
+    // Erase() is delayed, just sets these two instead of filling the buffer.
+    bool mEraseColorSet = false;
+    Color mEraseColor;
 #ifdef DBG_UTIL
     int mWriteAccessCount = 0; // number of write AcquireAccess() that have 
not been released
 #endif
diff --git a/vcl/skia/gdiimpl.cxx b/vcl/skia/gdiimpl.cxx
index b00b74d24647..c11705486926 100644
--- a/vcl/skia/gdiimpl.cxx
+++ b/vcl/skia/gdiimpl.cxx
@@ -1009,7 +1009,7 @@ bool SkiaSalGraphicsImpl::blendBitmap(const SalTwoRect& 
rPosAry, const SalBitmap
     // combinedTextureFragmentShader.glsl, the layer is not even alpha values 
but
     // simply yes-or-no mask.
     // See also blendAlphaBitmap().
-    drawImage(rPosAry, rSkiaBitmap.GetSkImage(), SkBlendMode::kMultiply);
+    drawBitmap(rPosAry, rSkiaBitmap, SkBlendMode::kMultiply);
     return true;
 }
 
@@ -1040,11 +1040,11 @@ bool SkiaSalGraphicsImpl::blendAlphaBitmap(const 
SalTwoRect& rPosAry,
     // First do the "( 1 - alpha ) * mask"
     // (no idea how to do "floor", but hopefully not needed in practice).
     sk_sp<SkShader> shaderAlpha
-        = SkShaders::Blend(SkBlendMode::kDstOut, 
rSkiaMaskBitmap.GetAlphaSkImage()->makeShader(),
-                           rSkiaAlphaBitmap.GetAlphaSkImage()->makeShader());
+        = SkShaders::Blend(SkBlendMode::kDstOut, 
rSkiaMaskBitmap.GetAlphaSkShader(),
+                           rSkiaAlphaBitmap.GetAlphaSkShader());
     // And now draw the bitmap with "1 - x", where x is the "( 1 - alpha ) * 
mask".
-    sk_sp<SkShader> shader = SkShaders::Blend(SkBlendMode::kSrcOut, 
shaderAlpha,
-                                              
rSkiaSourceBitmap.GetSkImage()->makeShader());
+    sk_sp<SkShader> shader
+        = SkShaders::Blend(SkBlendMode::kSrcOut, shaderAlpha, 
rSkiaSourceBitmap.GetSkShader());
     drawShader(rPosAry, shader);
     return true;
 }
@@ -1057,7 +1057,7 @@ void SkiaSalGraphicsImpl::drawBitmap(const SalTwoRect& 
rPosAry, const SalBitmap&
     assert(dynamic_cast<const SkiaSalBitmap*>(&rSalBitmap));
     const SkiaSalBitmap& rSkiaSourceBitmap = static_cast<const 
SkiaSalBitmap&>(rSalBitmap);
 
-    drawImage(rPosAry, rSkiaSourceBitmap.GetSkImage());
+    drawBitmap(rPosAry, rSkiaSourceBitmap);
 }
 
 void SkiaSalGraphicsImpl::drawBitmap(const SalTwoRect& rPosAry, const 
SalBitmap& rSalBitmap,
@@ -1074,7 +1074,7 @@ void SkiaSalGraphicsImpl::drawMask(const SalTwoRect& 
rPosAry, const SalBitmap& r
     drawShader(rPosAry,
                SkShaders::Blend(SkBlendMode::kDstOut, // VCL alpha is 
one-minus-alpha.
                                 SkShaders::Color(toSkColor(nMaskColor)),
-                                skiaBitmap.GetAlphaSkImage()->makeShader()));
+                                skiaBitmap.GetAlphaSkShader()));
 }
 
 std::shared_ptr<SalBitmap> SkiaSalGraphicsImpl::getBitmap(long nX, long nY, 
long nWidth,
@@ -1227,6 +1227,31 @@ void SkiaSalGraphicsImpl::invert(sal_uInt32 nPoints, 
const SalPoint* pPointArray
 
 bool SkiaSalGraphicsImpl::drawEPS(long, long, long, long, void*, sal_uInt32) { 
return false; }
 
+static void drawBitmapToCanvas(const SkiaSalBitmap& bitmap, SkCanvas* canvas, 
const SkPaint& paint)
+{
+    if (bitmap.PreferSkShader())
+    {
+        SkPaint paint2(paint);
+        paint2.setShader(bitmap.GetSkShader());
+        canvas->drawPaint(paint2);
+    }
+    else
+        canvas->drawImage(bitmap.GetSkImage(), 0, 0, &paint);
+}
+
+static void drawAlphaBitmapToCanvas(const SkiaSalBitmap& bitmap, SkCanvas* 
canvas,
+                                    const SkPaint& paint)
+{
+    if (bitmap.PreferSkShader())
+    {
+        SkPaint paint2(paint);
+        paint2.setShader(bitmap.GetAlphaSkShader());
+        canvas->drawPaint(paint2);
+    }
+    else
+        canvas->drawImage(bitmap.GetAlphaSkImage(), 0, 0, &paint);
+}
+
 // Create SkImage from a bitmap and possibly an alpha mask (the usual VCL 
one-minus-alpha),
 // with the given target size. Result will be possibly cached, unless disabled.
 sk_sp<SkImage> SkiaSalGraphicsImpl::mergeCacheBitmaps(const SkiaSalBitmap& 
bitmap,
@@ -1254,15 +1279,10 @@ sk_sp<SkImage> 
SkiaSalGraphicsImpl::mergeCacheBitmaps(const SkiaSalBitmap& bitma
     keyBuf.append(targetSize.Width())
         .append("x")
         .append(targetSize.Height())
-        .append("_0x")
-        .append(reinterpret_cast<sal_IntPtr>(&bitmap), 16)
-        .append("_0x")
-        .append(reinterpret_cast<sal_IntPtr>(alphaBitmap), 16)
         .append("_")
-        .append(static_cast<sal_Int64>(bitmap.GetSkImage()->uniqueID()));
+        .append(bitmap.GetImageKey());
     if (alphaBitmap)
-        keyBuf.append("_").append(
-            
static_cast<sal_Int64>(alphaBitmap->GetAlphaSkImage()->uniqueID()));
+        keyBuf.append("_").append(alphaBitmap->GetAlphaImageKey());
     key = keyBuf.makeStringAndClear();
     image = SkiaHelper::findCachedImage(key);
     if (image)
@@ -1279,9 +1299,9 @@ sk_sp<SkImage> 
SkiaSalGraphicsImpl::mergeCacheBitmaps(const SkiaSalBitmap& bitma
             return nullptr;
         SkPaint paint;
         paint.setBlendMode(SkBlendMode::kSrc); // copy as is, including alpha
-        mergedSurface->getCanvas()->drawImage(bitmap.GetSkImage(), 0, 0, 
&paint);
+        drawBitmapToCanvas(bitmap, mergedSurface->getCanvas(), paint);
         paint.setBlendMode(SkBlendMode::kDstOut); // VCL alpha is 
one-minus-alpha
-        mergedSurface->getCanvas()->drawImage(alphaBitmap->GetAlphaSkImage(), 
0, 0, &paint);
+        drawAlphaBitmapToCanvas(*alphaBitmap, mergedSurface->getCanvas(), 
paint);
         sk_sp<SkSurface> scaledSurface = 
SkiaHelper::createSkSurface(targetSize);
         if (!scaledSurface)
             return nullptr;
@@ -1310,11 +1330,11 @@ sk_sp<SkImage> 
SkiaSalGraphicsImpl::mergeCacheBitmaps(const SkiaSalBitmap& bitma
             paint.setFilterQuality(kHigh_SkFilterQuality);
         }
         paint.setBlendMode(SkBlendMode::kSrc); // copy as is, including alpha
-        canvas->drawImage(bitmap.GetSkImage(), 0, 0, &paint);
+        drawBitmapToCanvas(bitmap, canvas, paint);
         if (alphaBitmap != nullptr)
         {
             paint.setBlendMode(SkBlendMode::kDstOut); // VCL alpha is 
one-minus-alpha
-            canvas->drawImage(alphaBitmap->GetAlphaSkImage(), 0, 0, &paint);
+            drawAlphaBitmapToCanvas(*alphaBitmap, canvas, paint);
         }
         image = tmpSurface->makeImageSnapshot();
     }
@@ -1349,13 +1369,21 @@ bool SkiaSalGraphicsImpl::drawAlphaBitmap(const 
SalTwoRect& rPosAry, const SalBi
     else
         drawShader(
             rPosAry,
-            SkShaders::Blend(
-                SkBlendMode::kDstOut, // VCL alpha is one-minus-alpha.
-                static_cast<const 
SkiaSalBitmap&>(rSourceBitmap).GetSkImage()->makeShader(),
-                static_cast<const 
SkiaSalBitmap*>(&rAlphaBitmap)->GetAlphaSkImage()->makeShader()));
+            SkShaders::Blend(SkBlendMode::kDstOut, // VCL alpha is 
one-minus-alpha.
+                             static_cast<const 
SkiaSalBitmap&>(rSourceBitmap).GetSkShader(),
+                             static_cast<const 
SkiaSalBitmap*>(&rAlphaBitmap)->GetAlphaSkShader()));
     return true;
 }
 
+void SkiaSalGraphicsImpl::drawBitmap(const SalTwoRect& rPosAry, const 
SkiaSalBitmap& bitmap,
+                                     SkBlendMode blendMode)
+{
+    if (bitmap.PreferSkShader())
+        drawShader(rPosAry, bitmap.GetSkShader(), blendMode);
+    else
+        drawImage(rPosAry, bitmap.GetSkImage(), blendMode);
+}
+
 void SkiaSalGraphicsImpl::drawImage(const SalTwoRect& rPosAry, const 
sk_sp<SkImage>& aImage,
                                     SkBlendMode eBlendMode)
 {
@@ -1379,13 +1407,15 @@ void SkiaSalGraphicsImpl::drawImage(const SalTwoRect& 
rPosAry, const sk_sp<SkIma
 
 // SkShader can be used to merge multiple bitmaps with appropriate blend modes 
(e.g. when
 // merging a bitmap with its alpha mask).
-void SkiaSalGraphicsImpl::drawShader(const SalTwoRect& rPosAry, const 
sk_sp<SkShader>& shader)
+void SkiaSalGraphicsImpl::drawShader(const SalTwoRect& rPosAry, const 
sk_sp<SkShader>& shader,
+                                     SkBlendMode blendMode)
 {
     preDraw();
     SAL_INFO("vcl.skia.trace", "drawshader(" << this << "): " << rPosAry);
     SkRect destinationRect = SkRect::MakeXYWH(rPosAry.mnDestX, 
rPosAry.mnDestY, rPosAry.mnDestWidth,
                                               rPosAry.mnDestHeight);
     SkPaint paint;
+    paint.setBlendMode(blendMode);
     paint.setShader(shader);
     if (rPosAry.mnSrcWidth != rPosAry.mnDestWidth || rPosAry.mnSrcHeight != 
rPosAry.mnDestHeight)
         paint.setFilterQuality(kHigh_SkFilterQuality);
@@ -1472,8 +1502,15 @@ bool SkiaSalGraphicsImpl::drawTransformedBitmap(const 
basegfx::B2DPoint& rNull,
             // SkCanvas::drawPaint() cannot do rectangles, so clip (is 
transformed by the matrix too).
             canvas->clipRect(SkRect::MakeWH(aSize.Width(), aSize.Height()));
             paint.setShader(SkShaders::Blend(SkBlendMode::kDstOut, // VCL 
alpha is one-minus-alpha.
-                                             
rSkiaBitmap.GetSkImage()->makeShader(),
-                                             
pSkiaAlphaBitmap->GetAlphaSkImage()->makeShader()));
+                                             rSkiaBitmap.GetSkShader(),
+                                             
pSkiaAlphaBitmap->GetAlphaSkShader()));
+            canvas->drawPaint(paint);
+        }
+        else if (rSkiaBitmap.PreferSkShader())
+        {
+            // SkCanvas::drawPaint() cannot do rectangles, so clip (is 
transformed by the matrix too).
+            canvas->clipRect(SkRect::MakeWH(aSize.Width(), aSize.Height()));
+            paint.setShader(rSkiaBitmap.GetSkShader());
             canvas->drawPaint(paint);
         }
         else
diff --git a/vcl/skia/salbmp.cxx b/vcl/skia/salbmp.cxx
index 35d0c2a0849c..43286ac4a9fe 100644
--- a/vcl/skia/salbmp.cxx
+++ b/vcl/skia/salbmp.cxx
@@ -27,6 +27,8 @@
 #include <salinst.hxx>
 #include <scanlinewriter.hxx>
 #include <svdata.hxx>
+#include <bmpfast.hxx>
+#include <vcl/bitmapaccess.hxx>
 
 #include <SkCanvas.h>
 #include <SkImage.h>
@@ -148,6 +150,8 @@ bool SkiaSalBitmap::Create(const SalBitmap& rSalBmp, 
sal_uInt16 nNewBitCount)
     mPixelsSize = src.mPixelsSize;
     mScanlineSize = src.mScanlineSize;
     mScaleQuality = src.mScaleQuality;
+    mEraseColorSet = src.mEraseColorSet;
+    mEraseColor = src.mEraseColor;
 #ifdef DBG_UTIL
     mWriteAccessCount = 0;
 #endif
@@ -400,6 +404,17 @@ bool SkiaSalBitmap::InterpretAs8Bit()
     return false;
 }
 
+bool SkiaSalBitmap::Erase(const Color& color)
+{
+    // Optimized variant, just remember the color and apply it when needed,
+    // which may save having to do format conversions (e.g. GetSkImage()
+    // may directly erase the SkImage).
+    ResetCachedData();
+    mEraseColorSet = true;
+    mEraseColor = color;
+    return true;
+}
+
 SkBitmap SkiaSalBitmap::GetAsSkBitmap() const
 {
 #ifdef DBG_UTIL
@@ -496,11 +511,28 @@ SkBitmap SkiaSalBitmap::GetAsSkBitmap() const
     return bitmap;
 }
 
+static SkColor toSkColor(Color color)
+{
+    return SkColorSetARGB(255 - color.GetTransparency(), color.GetRed(), 
color.GetGreen(),
+                          color.GetBlue());
+}
+
 const sk_sp<SkImage>& SkiaSalBitmap::GetSkImage() const
 {
 #ifdef DBG_UTIL
     assert(mWriteAccessCount == 0);
 #endif
+    if (mEraseColorSet)
+    {
+        SkiaZone zone;
+        sk_sp<SkSurface> surface = SkiaHelper::createSkSurface(mSize);
+        assert(surface);
+        surface->getCanvas()->clear(toSkColor(mEraseColor));
+        SkiaSalBitmap* thisPtr = const_cast<SkiaSalBitmap*>(this);
+        thisPtr->mImage = surface->makeImageSnapshot();
+        SAL_INFO("vcl.skia.trace", "getskimage(" << this << ") from erase 
color " << mEraseColor);
+        return mImage;
+    }
     if (mPixelsSize != mSize && !mImage
         && SkiaHelper::renderMethodToUse() != SkiaHelper::RenderRaster)
     {
@@ -554,6 +586,18 @@ const sk_sp<SkImage>& SkiaSalBitmap::GetAlphaSkImage() 
const
 #ifdef DBG_UTIL
     assert(mWriteAccessCount == 0);
 #endif
+    if (mEraseColorSet)
+    {
+        SkiaZone zone;
+        sk_sp<SkSurface> surface = SkiaHelper::createSkSurface(mSize, 
kAlpha_8_SkColorType);
+        assert(surface);
+        surface->getCanvas()->clear(SkColorSetARGB(255 - 
mEraseColor.GetBlue(), 0, 0, 0));
+        SkiaSalBitmap* thisPtr = const_cast<SkiaSalBitmap*>(this);
+        thisPtr->mAlphaImage = surface->makeImageSnapshot();
+        SAL_INFO("vcl.skia.trace",
+                 "getalphaskimage(" << this << ") from erase color " << 
mEraseColor);
+        return mAlphaImage;
+    }
     if (mAlphaImage)
     {
         assert(mSize == mPixelsSize); // data has already been scaled if needed
@@ -636,8 +680,71 @@ const sk_sp<SkImage>& SkiaSalBitmap::GetAlphaSkImage() 
const
     return mAlphaImage;
 }
 
+// If the bitmap is to be erased, SkShader with the color set is more efficient
+// than creating an image filled with the color.
+bool SkiaSalBitmap::PreferSkShader() const { return mEraseColorSet; }
+
+sk_sp<SkShader> SkiaSalBitmap::GetSkShader() const
+{
+    if (mEraseColorSet)
+        return SkShaders::Color(toSkColor(mEraseColor));
+    return GetSkImage()->makeShader();
+}
+
+sk_sp<SkShader> SkiaSalBitmap::GetAlphaSkShader() const
+{
+    if (mEraseColorSet)
+        return SkShaders::Color(toSkColor(mEraseColor));
+    return GetAlphaSkImage()->makeShader();
+}
+
+void SkiaSalBitmap::EraseInternal()
+{
+    if (mPixelsSize.IsEmpty())
+        return;
+    BitmapBuffer* bitmapBuffer = AcquireBuffer(BitmapAccessMode::Write);
+    if (bitmapBuffer == nullptr)
+        abort();
+    Color fastColor = mEraseColor;
+    if (!!mPalette)
+        fastColor = mPalette.GetBestIndex(fastColor);
+    if (!ImplFastEraseBitmap(*bitmapBuffer, fastColor))
+    {
+        FncSetPixel setPixel = 
BitmapReadAccess::SetPixelFunction(bitmapBuffer->mnFormat);
+        assert(bitmapBuffer->mnFormat & ScanlineFormat::TopDown);
+        // Set first scanline, copy to others.
+        Scanline scanline = bitmapBuffer->mpBits;
+        for (long x = 0; x < bitmapBuffer->mnWidth; ++x)
+            setPixel(scanline, x, mEraseColor, bitmapBuffer->maColorMask);
+        for (long y = 1; y < bitmapBuffer->mnHeight; ++y)
+            memcpy(scanline + y * bitmapBuffer->mnScanlineSize, scanline,
+                   bitmapBuffer->mnScanlineSize);
+    }
+    ReleaseBuffer(bitmapBuffer, BitmapAccessMode::Write);
+}
+
 void SkiaSalBitmap::EnsureBitmapData()
 {
+    if (mEraseColorSet)
+    {
+        SkiaZone zone;
+        if (mPixelsSize != mSize)
+        {
+            mPixelsSize = mSize;
+            mBuffer.reset();
+        }
+        mScaleQuality = kHigh_SkFilterQuality;
+        if (!mBuffer && !CreateBitmapData())
+            abort();
+        // Unset now, so that repeated call will return mBuffer.
+        mEraseColorSet = false;
+        EraseInternal();
+        verify();
+        SAL_INFO("vcl.skia.trace",
+                 "ensurebitmapdata(" << this << ") from erase color " << 
mEraseColor);
+        return;
+    }
+
     if (mBuffer)
     {
         if (mSize == mPixelsSize)
@@ -768,9 +875,6 @@ void SkiaSalBitmap::EnsureBitmapUniqueData()
 void SkiaSalBitmap::ResetCachedData()
 {
     SkiaZone zone;
-    // There may be a case when only mImage is set and CreatBitmapData() will 
create
-    // mBuffer from it if needed, in that case ResetToSkImage() should be used.
-    assert(mBuffer.get() || !mImage);
     mImage.reset();
     mAlphaImage.reset();
 }
@@ -794,6 +898,30 @@ void SkiaSalBitmap::ResetCachedDataBySize()
         mAlphaImage.reset();
 }
 
+OString SkiaSalBitmap::GetImageKey() const
+{
+    if (mEraseColorSet)
+    {
+        std::stringstream ss;
+        ss << std::hex << std::setfill('0') << std::setw(2) << (255 - 
mEraseColor.GetTransparency())
+           << std::setw(6) << sal_uInt32(mEraseColor.GetRGBColor());
+        return OStringLiteral("E") + ss.str().c_str();
+    }
+    return OStringLiteral("I") + OString::number(GetSkImage()->uniqueID());
+}
+
+OString SkiaSalBitmap::GetAlphaImageKey() const
+{
+    if (mEraseColorSet)
+    {
+        std::stringstream ss;
+        ss << std::hex << std::setfill('0') << std::setw(2) << (255 - 
mEraseColor.GetTransparency())
+           << std::setw(6) << sal_uInt32(mEraseColor.GetRGBColor());
+        return OStringLiteral("E") + ss.str().c_str();
+    }
+    return OStringLiteral("I") + 
OString::number(GetAlphaSkImage()->uniqueID());
+}
+
 #ifdef DBG_UTIL
 void SkiaSalBitmap::dump(const char* file) const
 {
diff --git a/vcl/source/bitmap/bitmappaint.cxx 
b/vcl/source/bitmap/bitmappaint.cxx
index 22ddf2ea5e6b..046b0e3ba3b5 100644
--- a/vcl/source/bitmap/bitmappaint.cxx
+++ b/vcl/source/bitmap/bitmappaint.cxx
@@ -36,6 +36,19 @@ bool Bitmap::Erase(const Color& rFillColor)
     if (IsEmpty())
         return true;
 
+    if (mxSalBmp)
+    {
+        // implementation specific replace
+        std::shared_ptr<SalBitmap> 
xImpBmp(ImplGetSVData()->mpDefInst->CreateSalBitmap());
+        if (xImpBmp->Create(*mxSalBmp) && xImpBmp->Erase(rFillColor))
+        {
+            ImplSetSalBitmap(xImpBmp);
+            maPrefMapMode = MapMode(MapUnit::MapPixel);
+            maPrefSize = xImpBmp->GetSize();
+            return true;
+        }
+    }
+
     BitmapScopedWriteAccess pWriteAcc(*this);
     bool bRet = false;
 
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to