[Libreoffice-commits] core.git: vcl/backendtest vcl/skia

Luboš Luňák (via logerrit) logerrit at kemper.freedesktop.org
Thu Jan 9 14:25:59 UTC 2020


 vcl/backendtest/outputdevice/bitmap.cxx |   12 +++++++-----
 vcl/skia/gdiimpl.cxx                    |   29 +++++++++++++++++++++++------
 2 files changed, 30 insertions(+), 11 deletions(-)

New commits:
commit 3aa151e4de4c02b094acb6fa8a919cc86051a6fd
Author:     Luboš Luňák <l.lunak at collabora.com>
AuthorDate: Thu Jan 9 13:21:04 2020 +0100
Commit:     Luboš Luňák <l.lunak at collabora.com>
CommitDate: Thu Jan 9 15:25:25 2020 +0100

    fix Skia virtual device alpha blending (tdf#129865)
    
    The blendBitmap()/blendAlphaBitmap() stuff coming from the OpenGL code
    is some undocumented crazy stuff (probably because the VirtualDevice
    alpha handling itself is rather crazy). Hopefully I've finally figured
    it out to work properly for Skia too. This separate alpha handling
    all over the place in VCL should be just nuked.
    
    Change-Id: I82615a9be7064e9ade00ec4970a131a80a543c14
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/86488
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lunak at collabora.com>

diff --git a/vcl/backendtest/outputdevice/bitmap.cxx b/vcl/backendtest/outputdevice/bitmap.cxx
index 66a0a64adf49..2e7e0713294a 100644
--- a/vcl/backendtest/outputdevice/bitmap.cxx
+++ b/vcl/backendtest/outputdevice/bitmap.cxx
@@ -133,10 +133,13 @@ BitmapEx OutputDeviceTestBitmap::setupDrawBlend()
         aWriteAccess->DrawRect(tools::Rectangle(3, 3, 5, 5));
     }
 
-    initialSetup(13, 13, constBackgroundColor, false, true);
+    initialSetup(13, 13, COL_TRANSPARENT, false, true);
     mpVirtualDevice->SetFillColor(constBackgroundColor);
     mpVirtualDevice->SetLineColor(constBackgroundColor);
-    mpVirtualDevice->DrawRect(maVDRectangle);
+    // Leave the outer part of the device transparent, the inner part set to the background color.
+    // This will test blending of VirtualDevice's "alpha" device (outer yellow rectangle
+    // will be blended with transparent background, inner with the grey one).
+    mpVirtualDevice->DrawRect( tools::Rectangle( Point( 3, 3 ), Size( 7, 7 )));
 
     Point aPoint(alignToCenter(maVDRectangle, tools::Rectangle(Point(), aBitmapSize)).TopLeft());
 
@@ -179,9 +182,8 @@ TestResult OutputDeviceTestBitmap::checkBlend(BitmapEx& rBitmapEx)
 
     std::vector<Color> aExpected
     {
-        constBackgroundColor, constBackgroundColor,
-        aBlendedColor, constBackgroundColor, constBackgroundColor,
-        aBlendedColor, constBackgroundColor
+        COL_WHITE, COL_WHITE, COL_YELLOW, constBackgroundColor,
+        constBackgroundColor, aBlendedColor, constBackgroundColor
     };
     Bitmap aBitmap(rBitmapEx.GetBitmap());
     return checkRectangles(aBitmap, aExpected);
diff --git a/vcl/skia/gdiimpl.cxx b/vcl/skia/gdiimpl.cxx
index 25980de0cc60..a4e716122c3a 100644
--- a/vcl/skia/gdiimpl.cxx
+++ b/vcl/skia/gdiimpl.cxx
@@ -738,6 +738,15 @@ bool SkiaSalGraphicsImpl::blendBitmap(const SalTwoRect& rPosAry, const SalBitmap
 
     assert(dynamic_cast<const SkiaSalBitmap*>(&rBitmap));
     const SkiaSalBitmap& rSkiaBitmap = static_cast<const SkiaSalBitmap&>(rBitmap);
+    // This is used by VirtualDevice in the alpha mode for the "alpha" layer which
+    // is actually one-minus-alpha (opacity). Therefore white=0xff=transparent,
+    // black=0x00=opaque. So the result is transparent only if both the inputs
+    // are transparent. Since for blending operations white=1.0 and black=0.0,
+    // kMultiply should handle exactly that (transparent*transparent=transparent,
+    // opaque*transparent=opaque). And guessing from the "floor" in TYPE_BLEND in opengl's
+    // combinedTextureFragmentShader.glsl, the layer is not even alpha values but
+    // simply yes-or-no mask.
+    // See also blendAlphaBitmap().
     drawImage(rPosAry, rSkiaBitmap.GetSkImage(), SkBlendMode::kMultiply);
     return true;
 }
@@ -762,17 +771,25 @@ bool SkiaSalGraphicsImpl::blendAlphaBitmap(const SalTwoRect& rPosAry,
     const SkiaSalBitmap& rSkiaMaskBitmap = static_cast<const SkiaSalBitmap&>(rMaskBitmap);
     const SkiaSalBitmap& rSkiaAlphaBitmap = static_cast<const SkiaSalBitmap&>(rAlphaBitmap);
 
+    // This was originally implemented for the OpenGL drawing method and it is poorly documented.
+    // The source and mask bitmaps are the usual data and alpha bitmaps, and 'alpha'
+    // is the "alpha" layer of the VirtualDevice (the alpha in VirtualDevice is also stored
+    // as a separate bitmap). Now I understand it correctly these two alpha masks first need
+    // to be combined into the actual alpha mask to be used. The formula for TYPE_BLEND
+    // in opengl's combinedTextureFragmentShader.glsl is
+    // "result_alpha = 1.0 - (1.0 - floor(alpha)) * mask".
+    // See also blendBitmap().
     SkCanvas* aCanvas = tmpSurface->getCanvas();
     SkPaint aPaint;
-
+    // First copy the mask as is.
     aPaint.setBlendMode(SkBlendMode::kSrc);
-    aCanvas->drawImage(rSkiaSourceBitmap.GetSkImage(), 0, 0, &aPaint);
-
-    // Apply cumulatively both the bitmap alpha and the device alpha.
-    aPaint.setBlendMode(SkBlendMode::kDstOut); // VCL alpha is one-minus-alpha
     aCanvas->drawImage(rSkiaMaskBitmap.GetAlphaSkImage(), 0, 0, &aPaint);
-    aPaint.setBlendMode(SkBlendMode::kDstOut); // VCL alpha is one-minus-alpha
+    // Do the "1 - alpha" (no idea how to do "floor", but hopefully not needed in practice).
+    aPaint.setBlendMode(SkBlendMode::kDstOut);
     aCanvas->drawImage(rSkiaAlphaBitmap.GetAlphaSkImage(), 0, 0, &aPaint);
+    // And now draw the bitmap with "1 - x", where x is the "( 1 - alpha ) * mask".
+    aPaint.setBlendMode(SkBlendMode::kSrcOut);
+    aCanvas->drawImage(rSkiaSourceBitmap.GetSkImage(), 0, 0, &aPaint);
 
     drawImage(rPosAry, tmpSurface->makeImageSnapshot());
     return true;


More information about the Libreoffice-commits mailing list