[Libreoffice-commits] core.git: vcl/inc vcl/skia vcl/source
LuboÅ¡ LuÅák (via logerrit)
logerrit at kemper.freedesktop.org
Wed Jul 1 05:37:26 UTC 2020
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.lunak at collabora.com>
AuthorDate: Tue Jun 30 10:19:34 2020 +0200
Commit: Luboš Luňák <l.lunak at 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.lunak at 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;
More information about the Libreoffice-commits
mailing list