From 717ce6838b7ef0add1f9a9655e2b8c0bf60203f0 Mon Sep 17 00:00:00 2001 From: Luboš Luňák Date: Sat, 5 Sep 2020 07:05:16 +0200 Subject: avoid temporary SkImage when merging bitmaps in Skia (tdf#136244) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The original idea was to create a temporary SkImage in order to first merge the bitmap and its alpha bitmap, otherwise scaling already while merging them could introduce artefacts because of smoothscaling the alpha. But SkShader use blends the bitmap and alpha values before the scaling, so this is actually not necessary. Change-Id: I4e351611e3c33530dd5326c542b0a191955b5109 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/102068 Tested-by: Jenkins Reviewed-by: Luboš Luňák --- vcl/skia/gdiimpl.cxx | 92 ++++++++++++++-------------------------------------- 1 file changed, 24 insertions(+), 68 deletions(-) (limited to 'vcl/skia/gdiimpl.cxx') diff --git a/vcl/skia/gdiimpl.cxx b/vcl/skia/gdiimpl.cxx index 61f843dee609..652fea88f38e 100644 --- a/vcl/skia/gdiimpl.cxx +++ b/vcl/skia/gdiimpl.cxx @@ -1391,31 +1391,6 @@ 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 SkiaSalGraphicsImpl::mergeCacheBitmaps(const SkiaSalBitmap& bitmap, @@ -1477,54 +1452,35 @@ sk_sp SkiaSalGraphicsImpl::mergeCacheBitmaps(const SkiaSalBitmap& bitma assert(image->width() == targetSize.Width() && image->height() == targetSize.Height()); return image; } - // Combine bitmap + alpha bitmap into one temporary bitmap with alpha. - // If scaling is needed, first apply the alpha, then scale, otherwise the scaling might affect the alpha values. - if (alphaBitmap && targetSize != bitmap.GetSize()) + sk_sp tmpSurface = SkiaHelper::createSkSurface(targetSize); + if (!tmpSurface) + return nullptr; + SkCanvas* canvas = tmpSurface->getCanvas(); + SkAutoCanvasRestore autoRestore(canvas, true); + SkPaint paint; + if (targetSize != bitmap.GetSize()) { - sk_sp mergedSurface = SkiaHelper::createSkSurface(bitmap.GetSize()); - if (!mergedSurface) - return nullptr; - SkPaint paint; - paint.setBlendMode(SkBlendMode::kSrc); // copy as is, including alpha - drawBitmapToCanvas(bitmap, mergedSurface->getCanvas(), paint); - paint.setBlendMode(SkBlendMode::kDstOut); // VCL alpha is one-minus-alpha - drawAlphaBitmapToCanvas(*alphaBitmap, mergedSurface->getCanvas(), paint); - sk_sp scaledSurface = SkiaHelper::createSkSurface(targetSize); - if (!scaledSurface) - return nullptr; - paint.setBlendMode(SkBlendMode::kSrc); // copy as is, including alpha + SkMatrix matrix; + matrix.set(SkMatrix::kMScaleX, 1.0 * targetSize.Width() / bitmap.GetSize().Width()); + matrix.set(SkMatrix::kMScaleY, 1.0 * targetSize.Height() / bitmap.GetSize().Height()); + canvas->concat(matrix); paint.setFilterQuality(kHigh_SkFilterQuality); - scaledSurface->getCanvas()->drawImageRect( - mergedSurface->makeImageSnapshot(), - SkRect::MakeXYWH(0, 0, bitmap.GetSize().Width(), bitmap.GetSize().Height()), - SkRect::MakeXYWH(0, 0, targetSize.Width(), targetSize.Height()), &paint); - image = scaledSurface->makeImageSnapshot(); } - else // No alpha or no scaling, scale directly. + if (alphaBitmap != nullptr) { - sk_sp tmpSurface = SkiaHelper::createSkSurface(targetSize); - if (!tmpSurface) - return nullptr; - SkCanvas* canvas = tmpSurface->getCanvas(); - SkAutoCanvasRestore autoRestore(canvas, true); - SkPaint paint; - if (targetSize != bitmap.GetSize()) - { - SkMatrix matrix; - matrix.set(SkMatrix::kMScaleX, 1.0 * targetSize.Width() / bitmap.GetSize().Width()); - matrix.set(SkMatrix::kMScaleY, 1.0 * targetSize.Height() / bitmap.GetSize().Height()); - canvas->concat(matrix); - paint.setFilterQuality(kHigh_SkFilterQuality); - } - paint.setBlendMode(SkBlendMode::kSrc); // copy as is, including alpha - drawBitmapToCanvas(bitmap, canvas, paint); - if (alphaBitmap != nullptr) - { - paint.setBlendMode(SkBlendMode::kDstOut); // VCL alpha is one-minus-alpha - drawAlphaBitmapToCanvas(*alphaBitmap, canvas, paint); - } - image = tmpSurface->makeImageSnapshot(); + canvas->clear(SK_ColorTRANSPARENT); + paint.setShader(SkShaders::Blend(SkBlendMode::kDstOut, bitmap.GetSkShader(), + alphaBitmap->GetAlphaSkShader())); + canvas->drawPaint(paint); } + else if (bitmap.PreferSkShader()) + { + paint.setShader(bitmap.GetSkShader()); + canvas->drawPaint(paint); + } + else + canvas->drawImage(bitmap.GetSkImage(), 0, 0, &paint); + image = tmpSurface->makeImageSnapshot(); SkiaHelper::addCachedImage(key, image); return image; } -- cgit