diff options
author | Luboš Luňák <l.lunak@collabora.com> | 2019-12-11 14:18:00 +0100 |
---|---|---|
committer | Luboš Luňák <l.lunak@collabora.com> | 2019-12-12 11:02:04 +0100 |
commit | e2c34ce3feac29e12ff47957eb8efcb6ad303709 (patch) | |
tree | add4d4f133e5fefce5ea3ba09f920431db5f1725 /vcl/skia/win | |
parent | 23b3de0b9a6cb69ed258905effa096ce5d5f1f13 (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.cxx | 55 |
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) { |