finally fix Skia Windows widget drawing (tdf#129416)
So much time wasted just because c6b66646870cb2bf couldn't be bothered spending a minute or two explaining the weird black/white alpha hack that it turns out is not even necessary as the resulting image is incidentally in the premultiplied alpha format. Change-Id: I810458a670b2c0c8047118f55f58bf588a37f9f1 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/86569 Tested-by: Jenkins Reviewed-by: Luboš Luňák <l.lunak@collabora.com>
This commit is contained in:
@@ -31,9 +31,8 @@ public:
|
||||
|
||||
virtual bool wantsTextColorWhite() const override { return true; }
|
||||
|
||||
sk_sp<SkImage> getAsImage() const;
|
||||
sk_sp<SkImage> getAsImage(bool fromPremultiplied = false) const;
|
||||
sk_sp<SkImage> getAsMaskImage() const;
|
||||
sk_sp<SkImage> getAsImageDiff(const SkiaCompatibleDC& other) const;
|
||||
|
||||
struct Texture;
|
||||
};
|
||||
|
@@ -97,15 +97,21 @@ bool WinSkiaSalGraphicsImpl::TryRenderCachedNativeControl(ControlCacheKey const&
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WinSkiaSalGraphicsImpl::RenderAndCacheNativeControl(CompatibleDC& rWhite, CompatibleDC& rBlack,
|
||||
int nX, int nY,
|
||||
bool WinSkiaSalGraphicsImpl::RenderAndCacheNativeControl(CompatibleDC& /*rWhite*/,
|
||||
CompatibleDC& rBlack, int nX, int nY,
|
||||
ControlCacheKey& aControlCacheKey)
|
||||
{
|
||||
assert(dynamic_cast<SkiaCompatibleDC*>(&rWhite));
|
||||
// assert(dynamic_cast<SkiaCompatibleDC*>(&rWhite));
|
||||
assert(dynamic_cast<SkiaCompatibleDC*>(&rBlack));
|
||||
|
||||
sk_sp<SkImage> image = static_cast<SkiaCompatibleDC&>(rWhite).getAsImageDiff(
|
||||
static_cast<SkiaCompatibleDC&>(rBlack));
|
||||
// Native widgets are drawn twice on black/white background, which comes from an OpenGL
|
||||
// commit c6b66646870cb2bffaa73565affcf80bf74e0b5c, where it is used to synthetize alpha.
|
||||
// But getting the Windows theming API to draw into an empty area (fully transparent)
|
||||
// actually results in the widget being in the premultiplied alpha format (and I have no
|
||||
// idea why the OpenGL code uses the weird undocumented pixel diffing it does, probably
|
||||
// the author did not realize this). Simply use the black variant as premultiplied data.
|
||||
// TODO Remove the white variant completely once OpenGL code is removed.
|
||||
sk_sp<SkImage> image = static_cast<SkiaCompatibleDC&>(rBlack).getAsImage(true);
|
||||
preDraw();
|
||||
mSurface->getCanvas()->drawImage(image, nX, nY);
|
||||
postDraw();
|
||||
@@ -207,12 +213,13 @@ sk_sp<SkImage> SkiaCompatibleDC::getAsMaskImage() const
|
||||
return surface->makeImageSnapshot();
|
||||
}
|
||||
|
||||
sk_sp<SkImage> SkiaCompatibleDC::getAsImage() const
|
||||
sk_sp<SkImage> SkiaCompatibleDC::getAsImage(bool fromPremultiplied) const
|
||||
{
|
||||
SkBitmap tmpBitmap;
|
||||
if (!tmpBitmap.installPixels(SkImageInfo::Make(maRects.mnSrcWidth, maRects.mnSrcHeight,
|
||||
kBGRA_8888_SkColorType, kUnpremul_SkAlphaType),
|
||||
mpData, maRects.mnSrcWidth * 4))
|
||||
if (!tmpBitmap.installPixels(
|
||||
SkImageInfo::Make(maRects.mnSrcWidth, maRects.mnSrcHeight, kBGRA_8888_SkColorType,
|
||||
fromPremultiplied ? kPremul_SkAlphaType : kUnpremul_SkAlphaType),
|
||||
mpData, maRects.mnSrcWidth * 4))
|
||||
abort();
|
||||
tmpBitmap.setImmutable();
|
||||
sk_sp<SkSurface> surface = SkiaHelper::createSkSurface(tmpBitmap.width(), tmpBitmap.height());
|
||||
@@ -232,50 +239,6 @@ sk_sp<SkImage> SkiaCompatibleDC::getAsImage() const
|
||||
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)
|
||||
{
|
||||
|
Reference in New Issue
Block a user