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

Luboš Luňák (via logerrit) logerrit at kemper.freedesktop.org
Thu Dec 12 10:04:04 UTC 2019


 vcl/inc/opengl/win/gdiimpl.hxx |    6 ++--
 vcl/inc/skia/utils.hxx         |    6 ++--
 vcl/inc/skia/win/gdiimpl.hxx   |    7 ++---
 vcl/inc/win/salgdi.h           |    2 -
 vcl/opengl/win/gdiimpl.cxx     |    6 ++--
 vcl/skia/win/gdiimpl.cxx       |   55 ++++++++++++++++++++++++++++++++++++-----
 6 files changed, 63 insertions(+), 19 deletions(-)

New commits:
commit e2c34ce3feac29e12ff47957eb8efcb6ad303709
Author:     Luboš Luňák <l.lunak at collabora.com>
AuthorDate: Wed Dec 11 14:18:00 2019 +0100
Commit:     Luboš Luňák <l.lunak at collabora.com>
CommitDate: Thu Dec 12 11:02:04 2019 +0100

    make Skia Windows widget drawing use correct alpha (tdf#129074)
    
    The OpenGL code made the widget drawing use two variants drawn
    on black and on white, for reasons not explained
    in 3149cc341b1866d215110f0783227549a99b5920 (probably the Windows
    API doesn't handle alpha completely correctly or whatever).
    This means that getting the actual alpha requires a custom
    algorithm that needs to be implemented manually for Skia use.
    
    Change-Id: I1438f3829a1bdeda9e55700c4a397c60d5663446
    Reviewed-on: https://gerrit.libreoffice.org/84948
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lunak at collabora.com>

diff --git a/vcl/inc/opengl/win/gdiimpl.hxx b/vcl/inc/opengl/win/gdiimpl.hxx
index 91e55a2ca28f..dff47ef7e550 100644
--- a/vcl/inc/opengl/win/gdiimpl.hxx
+++ b/vcl/inc/opengl/win/gdiimpl.hxx
@@ -26,12 +26,12 @@ class OpenGLCompatibleDC : public CompatibleDC
 public:
     OpenGLCompatibleDC(SalGraphics &rGraphics, int x, int y, int width, int height);
 
-    virtual std::unique_ptr<Texture> getAsMaskTexture() override;
+    virtual std::unique_ptr<Texture> getAsMaskTexture() const override;
     // caller must delete
-    OpenGLTexture* getOpenGLTexture();
+    OpenGLTexture* getOpenGLTexture() const;
 
     /// Copy bitmap data to the texture. Texture must be initialized and the correct size to hold the bitmap.
-    bool copyToTexture(Texture& aTexture);
+    bool copyToTexture(Texture& aTexture) const;
 
     struct Texture;
 };
diff --git a/vcl/inc/skia/utils.hxx b/vcl/inc/skia/utils.hxx
index 27ca2b1f0b72..6fd61afd0a05 100644
--- a/vcl/inc/skia/utils.hxx
+++ b/vcl/inc/skia/utils.hxx
@@ -44,9 +44,9 @@ inline sk_sp<SkSurface> createSkSurface(const Size& size, SkColorType type = kN3
 
 #ifdef DBG_UTIL
 void prefillSurface(sk_sp<SkSurface>& surface);
-void dump(const SkBitmap& bitmap, const char* file);
-void dump(const sk_sp<SkImage>& image, const char* file);
-void dump(const sk_sp<SkSurface>& surface, const char* file);
+VCL_DLLPUBLIC void dump(const SkBitmap& bitmap, const char* file);
+VCL_DLLPUBLIC void dump(const sk_sp<SkImage>& image, const char* file);
+VCL_DLLPUBLIC void dump(const sk_sp<SkSurface>& surface, const char* file);
 #endif
 
 } // namespace
diff --git a/vcl/inc/skia/win/gdiimpl.hxx b/vcl/inc/skia/win/gdiimpl.hxx
index 003fac2cc65b..dabd56ad04a3 100644
--- a/vcl/inc/skia/win/gdiimpl.hxx
+++ b/vcl/inc/skia/win/gdiimpl.hxx
@@ -27,12 +27,13 @@ class SkiaCompatibleDC : public CompatibleDC
 public:
     SkiaCompatibleDC(SalGraphics& rGraphics, int x, int y, int width, int height);
 
-    virtual std::unique_ptr<Texture> getAsMaskTexture() override;
+    virtual std::unique_ptr<Texture> getAsMaskTexture() const override;
 
     virtual bool wantsTextColorWhite() const override { return true; }
 
-    sk_sp<SkImage> getAsImage();
-    sk_sp<SkImage> getAsMaskImage();
+    sk_sp<SkImage> getAsImage() const;
+    sk_sp<SkImage> getAsMaskImage() const;
+    sk_sp<SkImage> getAsImageDiff(const SkiaCompatibleDC& other) const;
 
     struct Texture;
 };
diff --git a/vcl/inc/win/salgdi.h b/vcl/inc/win/salgdi.h
index eb0d428cc77f..15866800b8f4 100644
--- a/vcl/inc/win/salgdi.h
+++ b/vcl/inc/win/salgdi.h
@@ -140,7 +140,7 @@ public:
     struct Texture;
 
     /// Obtain the texture in format for WinSalGraphicsImplBase::DrawTextMask().
-    virtual std::unique_ptr<Texture> getAsMaskTexture() { abort(); };
+    virtual std::unique_ptr<Texture> getAsMaskTexture() const { abort(); };
 
     /// Return true if text glyphs should be drawn as white instead of black.
     virtual bool wantsTextColorWhite() const { return false; }
diff --git a/vcl/opengl/win/gdiimpl.cxx b/vcl/opengl/win/gdiimpl.cxx
index d736cfc08972..eabfe8a090b3 100644
--- a/vcl/opengl/win/gdiimpl.cxx
+++ b/vcl/opengl/win/gdiimpl.cxx
@@ -769,7 +769,7 @@ OpenGLCompatibleDC::OpenGLCompatibleDC(SalGraphics &rGraphics, int x, int y, int
 {
 }
 
-OpenGLTexture* OpenGLCompatibleDC::getOpenGLTexture()
+OpenGLTexture* OpenGLCompatibleDC::getOpenGLTexture() const
 {
     if (!mpImpl)
         return nullptr;
@@ -778,14 +778,14 @@ OpenGLTexture* OpenGLCompatibleDC::getOpenGLTexture()
     return new OpenGLTexture(maRects.mnSrcWidth, maRects.mnSrcHeight, GL_BGRA, GL_UNSIGNED_BYTE, mpData);
 }
 
-std::unique_ptr<CompatibleDC::Texture> OpenGLCompatibleDC::getAsMaskTexture()
+std::unique_ptr<CompatibleDC::Texture> OpenGLCompatibleDC::getAsMaskTexture() const
 {
     auto ret = std::make_unique<OpenGLCompatibleDC::Texture>();
     ret->texture = OpenGLTexture(maRects.mnSrcWidth, maRects.mnSrcHeight, GL_BGRA, GL_UNSIGNED_BYTE, mpData);
     return ret;
 }
 
-bool OpenGLCompatibleDC::copyToTexture(CompatibleDC::Texture& aTexture)
+bool OpenGLCompatibleDC::copyToTexture(CompatibleDC::Texture& aTexture) const
 {
     if (!mpImpl)
         return false;
diff --git a/vcl/skia/win/gdiimpl.cxx b/vcl/skia/win/gdiimpl.cxx
index 09ebb0139660..b3f538bcea5b 100644
--- a/vcl/skia/win/gdiimpl.cxx
+++ b/vcl/skia/win/gdiimpl.cxx
@@ -104,12 +104,11 @@ bool WinSkiaSalGraphicsImpl::RenderAndCacheNativeControl(CompatibleDC& rWhite, C
     assert(dynamic_cast<SkiaCompatibleDC*>(&rWhite));
     assert(dynamic_cast<SkiaCompatibleDC*>(&rBlack));
 
-    sk_sp<SkImage> image = static_cast<SkiaCompatibleDC&>(rWhite).getAsImage();
+    sk_sp<SkImage> image = static_cast<SkiaCompatibleDC&>(rWhite).getAsImageDiff(
+        static_cast<SkiaCompatibleDC&>(rBlack));
     preDraw();
     mSurface->getCanvas()->drawImage(image, nX, nY);
     postDraw();
-    // TODO what is the point of the second texture?
-    (void)rBlack;
 
     if (!aControlCacheKey.canCacheControl())
         return true;
@@ -159,14 +158,14 @@ SkiaCompatibleDC::SkiaCompatibleDC(SalGraphics& rGraphics, int x, int y, int wid
 {
 }
 
-std::unique_ptr<CompatibleDC::Texture> SkiaCompatibleDC::getAsMaskTexture()
+std::unique_ptr<CompatibleDC::Texture> SkiaCompatibleDC::getAsMaskTexture() const
 {
     auto ret = std::make_unique<SkiaCompatibleDC::Texture>();
     ret->image = getAsMaskImage();
     return ret;
 }
 
-sk_sp<SkImage> SkiaCompatibleDC::getAsMaskImage()
+sk_sp<SkImage> SkiaCompatibleDC::getAsMaskImage() const
 {
     // mpData is in the BGRA format, with A unused (and set to 0), and RGB are grey,
     // so convert it to Skia format, then to 8bit and finally use as alpha mask
@@ -208,7 +207,7 @@ sk_sp<SkImage> SkiaCompatibleDC::getAsMaskImage()
     return surface->makeImageSnapshot();
 }
 
-sk_sp<SkImage> SkiaCompatibleDC::getAsImage()
+sk_sp<SkImage> SkiaCompatibleDC::getAsImage() const
 {
     SkBitmap tmpBitmap;
     if (!tmpBitmap.installPixels(SkImageInfo::Make(maRects.mnSrcWidth, maRects.mnSrcHeight,
@@ -233,6 +232,50 @@ sk_sp<SkImage> SkiaCompatibleDC::getAsImage()
     return surface->makeImageSnapshot();
 }
 
+sk_sp<SkImage> SkiaCompatibleDC::getAsImageDiff(const SkiaCompatibleDC& other) const
+{
+    assert(maRects.mnSrcWidth == other.maRects.mnSrcWidth
+           || maRects.mnSrcHeight == other.maRects.mnSrcHeight);
+    SkBitmap tmpBitmap;
+    if (!tmpBitmap.tryAllocPixels(SkImageInfo::Make(maRects.mnSrcWidth, maRects.mnSrcHeight,
+                                                    kBGRA_8888_SkColorType, kUnpremul_SkAlphaType),
+                                  maRects.mnSrcWidth * 4))
+        abort();
+    // Native widgets are drawn twice on black/white background to synthetize alpha
+    // (commit c6b66646870cb2bffaa73565affcf80bf74e0b5c).
+    // Alpha is computed as "alpha = 1.0 - abs(black.red - white.red)".
+    // TODO I doubt this can be done using Skia, so do it manually here. Fortunately
+    // the bitmaps should be fairly small and are cached.
+    uint32_t* dest = tmpBitmap.getAddr32(0, 0);
+    assert(dest == tmpBitmap.getPixels());
+    const sal_uInt32* src = mpData;
+    const sal_uInt32* otherSrc = other.mpData;
+    uint32_t* end = dest + tmpBitmap.width() * tmpBitmap.height();
+    while (dest < end)
+    {
+        uint32_t alpha = 255 - abs(int(*src >> 24) - int(*otherSrc >> 24));
+        *dest = (*src & 0x00ffffff) | (alpha << 24);
+        ++dest;
+        ++src;
+        ++otherSrc;
+    }
+    tmpBitmap.notifyPixelsChanged();
+    tmpBitmap.setImmutable();
+    sk_sp<SkSurface> surface = SkiaHelper::createSkSurface(tmpBitmap.width(), tmpBitmap.height());
+    SkPaint paint;
+    paint.setBlendMode(SkBlendMode::kSrc); // set as is, including alpha
+    SkCanvas* canvas = surface->getCanvas();
+    canvas->save();
+    // The data we got is upside-down.
+    SkMatrix matrix;
+    matrix.preTranslate(0, tmpBitmap.height());
+    matrix.setConcat(matrix, SkMatrix::MakeScale(1, -1));
+    canvas->concat(matrix);
+    canvas->drawBitmap(tmpBitmap, 0, 0, &paint);
+    canvas->restore();
+    return surface->makeImageSnapshot();
+}
+
 SkiaControlsCache::SkiaControlsCache()
     : cache(200)
 {


More information about the Libreoffice-commits mailing list