summaryrefslogtreecommitdiff
path: root/vcl/skia/win
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/skia/win
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/skia/win')
-rw-r--r--vcl/skia/win/gdiimpl.cxx55
1 files changed, 49 insertions, 6 deletions
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)
{