summaryrefslogtreecommitdiff
path: root/vcl
diff options
context:
space:
mode:
authorLuboš Luňák <l.lunak@collabora.com>2019-12-11 14:18:00 +0100
committerLuboš Luňák <l.lunak@collabora.com>2019-12-12 11:02:04 +0100
commite2c34ce3feac29e12ff47957eb8efcb6ad303709 (patch)
treeadd4d4f133e5fefce5ea3ba09f920431db5f1725 /vcl
parent23b3de0b9a6cb69ed258905effa096ce5d5f1f13 (diff)
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@collabora.com>
Diffstat (limited to 'vcl')
-rw-r--r--vcl/inc/opengl/win/gdiimpl.hxx6
-rw-r--r--vcl/inc/skia/utils.hxx6
-rw-r--r--vcl/inc/skia/win/gdiimpl.hxx7
-rw-r--r--vcl/inc/win/salgdi.h2
-rw-r--r--vcl/opengl/win/gdiimpl.cxx6
-rw-r--r--vcl/skia/win/gdiimpl.cxx55
6 files changed, 63 insertions, 19 deletions
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)
{