summaryrefslogtreecommitdiff
path: root/vcl
diff options
context:
space:
mode:
authorLuboš Luňák <l.lunak@collabora.com>2019-10-25 16:29:49 +0200
committerLuboš Luňák <l.lunak@collabora.com>2019-11-27 09:55:12 +0100
commit5ac9a62f3a354db80837bdd1c95b763989b303bb (patch)
tree94a5bd6875589fa3827c20b84a5edee9da60090b /vcl
parentaa08385d1a07c530d32de91b633dbe087a3848ba (diff)
fix Skia Windows text rendering
There are two cases in WinSalGraphics::DrawTextLayout(), with and without cached glyphs: - Cached case DeferredTextDraw() gets data as BGRA with the glyph drawn in white, it just needs to be modulated to the proper color and drawn. - Uncached case DrawTextMask() gets data as BGRA with A invalid, it must be used as mask for the color to drawn, but without the inverse alpha VCL idiosyncracy that DrawMask() handles. Change-Id: I05dcec994df68d5986cd85cffa42a8f9f23c42c4
Diffstat (limited to 'vcl')
-rw-r--r--vcl/inc/opengl/win/gdiimpl.hxx6
-rw-r--r--vcl/inc/skia/win/gdiimpl.hxx8
-rw-r--r--vcl/inc/win/salgdi.h7
-rw-r--r--vcl/inc/win/wingdiimpl.hxx4
-rw-r--r--vcl/opengl/win/gdiimpl.cxx4
-rw-r--r--vcl/skia/win/gdiimpl.cxx79
-rw-r--r--vcl/win/gdi/winlayout.cxx7
7 files changed, 90 insertions, 25 deletions
diff --git a/vcl/inc/opengl/win/gdiimpl.hxx b/vcl/inc/opengl/win/gdiimpl.hxx
index 02b8b3850cab..2130654a3951 100644
--- a/vcl/inc/opengl/win/gdiimpl.hxx
+++ b/vcl/inc/opengl/win/gdiimpl.hxx
@@ -26,8 +26,8 @@ class OpenGLCompatibleDC : public CompatibleDC
public:
OpenGLCompatibleDC(SalGraphics &rGraphics, int x, int y, int width, int height);
- virtual std::unique_ptr<Texture> getTexture() override;
- // overload, caller must delete
+ virtual std::unique_ptr<Texture> getAsMaskTexture() override;
+ // caller must delete
OpenGLTexture* getOpenGLTexture();
virtual bool copyToTexture(Texture& aTexture) override;
@@ -68,7 +68,7 @@ public:
virtual bool UseTextDraw() const override { return true; }
virtual void PreDrawText() override;
virtual void PostDrawText() override;
- virtual void DrawMask( CompatibleDC::Texture* rTexture, Color nMaskColor, const SalTwoRect& rPosAry ) override;
+ virtual void DrawTextMask( CompatibleDC::Texture* rTexture, Color nMaskColor, const SalTwoRect& rPosAry ) override;
using OpenGLSalGraphicsImpl::DrawMask;
virtual void DeferredTextDraw(const CompatibleDC::Texture* pTexture, Color nMaskColor, const SalTwoRect& rPosAry) override;
diff --git a/vcl/inc/skia/win/gdiimpl.hxx b/vcl/inc/skia/win/gdiimpl.hxx
index bc177337b3de..6bd52b073aa5 100644
--- a/vcl/inc/skia/win/gdiimpl.hxx
+++ b/vcl/inc/skia/win/gdiimpl.hxx
@@ -28,10 +28,12 @@ class SkiaCompatibleDC : public CompatibleDC
public:
SkiaCompatibleDC(SalGraphics& rGraphics, int x, int y, int width, int height);
- virtual std::unique_ptr<Texture> getTexture() override;
+ virtual std::unique_ptr<Texture> getAsMaskTexture() override;
virtual bool copyToTexture(Texture& aTexture) override;
+ virtual bool wantsTextColorWhite() const override { return true; }
+
struct Texture;
};
@@ -65,8 +67,8 @@ public:
virtual bool UseTextDraw() const override { return true; }
virtual void PreDrawText() override;
virtual void PostDrawText() override;
- virtual void DrawMask(CompatibleDC::Texture* rTexture, Color nMaskColor,
- const SalTwoRect& rPosAry) override;
+ virtual void DrawTextMask(CompatibleDC::Texture* rTexture, Color nMaskColor,
+ const SalTwoRect& rPosAry) override;
virtual void DeferredTextDraw(const CompatibleDC::Texture* pTexture, Color nMaskColor,
const SalTwoRect& rPosAry) override;
diff --git a/vcl/inc/win/salgdi.h b/vcl/inc/win/salgdi.h
index f7fb206624b5..fc12bc823b93 100644
--- a/vcl/inc/win/salgdi.h
+++ b/vcl/inc/win/salgdi.h
@@ -138,11 +138,14 @@ public:
/// Base texture class (OpenGL and Skia will provide their implementations).
struct Texture;
- /// Obtain the texture.
- virtual std::unique_ptr<Texture> getTexture() { abort(); };
+ /// Obtain the texture in format for WinSalGraphicsImplBase::DrawTextMask().
+ virtual std::unique_ptr<Texture> getAsMaskTexture() { abort(); };
/// Copy bitmap data to the texture. Texture must be initialized and the correct size to hold the bitmap.
virtual bool copyToTexture(Texture& /*aTexture*/) { abort(); };
+
+ /// Return true if text glyphs should be drawn as white instead of black.
+ virtual bool wantsTextColorWhite() const { return false; }
};
struct CompatibleDC::Texture
diff --git a/vcl/inc/win/wingdiimpl.hxx b/vcl/inc/win/wingdiimpl.hxx
index 2264eecf353d..84884220318f 100644
--- a/vcl/inc/win/wingdiimpl.hxx
+++ b/vcl/inc/win/wingdiimpl.hxx
@@ -39,8 +39,8 @@ public:
virtual bool UseTextDraw() const { return false; }
virtual void PreDrawText() {}
virtual void PostDrawText() {}
- virtual void DrawMask(CompatibleDC::Texture* /*rTexture*/, Color /*nMaskColor*/,
- const SalTwoRect& /*rPosAry*/)
+ virtual void DrawTextMask(CompatibleDC::Texture* /*rTexture*/, Color /*nMaskColor*/,
+ const SalTwoRect& /*rPosAry*/)
{
abort();
};
diff --git a/vcl/opengl/win/gdiimpl.cxx b/vcl/opengl/win/gdiimpl.cxx
index d71a03714198..bb6e5bf0a16c 100644
--- a/vcl/opengl/win/gdiimpl.cxx
+++ b/vcl/opengl/win/gdiimpl.cxx
@@ -770,7 +770,7 @@ OpenGLTexture* OpenGLCompatibleDC::getOpenGLTexture()
return new OpenGLTexture(maRects.mnSrcWidth, maRects.mnSrcHeight, GL_BGRA, GL_UNSIGNED_BYTE, mpData);
}
-std::unique_ptr<CompatibleDC::Texture> OpenGLCompatibleDC::getTexture()
+std::unique_ptr<CompatibleDC::Texture> OpenGLCompatibleDC::getAsMaskTexture()
{
auto ret = std::make_unique<OpenGLCompatibleDC::Texture>();
ret->texture = OpenGLTexture(maRects.mnSrcWidth, maRects.mnSrcHeight, GL_BGRA, GL_UNSIGNED_BYTE, mpData);
@@ -881,7 +881,7 @@ void WinOpenGLSalGraphicsImpl::DeferredTextDraw(const CompatibleDC::Texture* pTe
PostBatchDraw();
}
-void WinOpenGLSalGraphicsImpl::DrawMask( CompatibleDC::Texture* pTexture, Color nMaskColor, const SalTwoRect& rPosAry )
+void WinOpenGLSalGraphicsImpl::DrawTextMask( CompatibleDC::Texture* pTexture, Color nMaskColor, const SalTwoRect& rPosAry )
{
assert(dynamic_cast<OpenGLCompatibleDC::Texture*>(pTexture));
DrawMask( static_cast<OpenGLCompatibleDC::Texture*>(pTexture)->texture, nMaskColor, rPosAry );
diff --git a/vcl/skia/win/gdiimpl.cxx b/vcl/skia/win/gdiimpl.cxx
index 9a41ffc7da27..e583cea86f3c 100644
--- a/vcl/skia/win/gdiimpl.cxx
+++ b/vcl/skia/win/gdiimpl.cxx
@@ -12,6 +12,9 @@
#include <tools/sk_app/win/WindowContextFactory_win.h>
#include <tools/sk_app/WindowContext.h>
+#include <SkColorFilter.h>
+#include <SkPixelRef.h>
+
WinSkiaSalGraphicsImpl::WinSkiaSalGraphicsImpl(WinSalGraphics& rGraphics,
SalGeometryProvider* mpProvider)
: SkiaSalGraphicsImpl(rGraphics, mpProvider)
@@ -102,18 +105,54 @@ void WinSkiaSalGraphicsImpl::PreDrawText() { preDraw(); }
void WinSkiaSalGraphicsImpl::PostDrawText() { postDraw(); }
+SkColor toSkColor(Color color)
+{
+ return SkColorSetARGB(255 - color.GetTransparency(), color.GetRed(), color.GetGreen(),
+ color.GetBlue());
+}
+
void WinSkiaSalGraphicsImpl::DeferredTextDraw(const CompatibleDC::Texture* pTexture,
Color aMaskColor, const SalTwoRect& rPosAry)
{
assert(dynamic_cast<const SkiaCompatibleDC::Texture*>(pTexture));
- drawMask(rPosAry, static_cast<const SkiaCompatibleDC::Texture*>(pTexture)->bitmap, aMaskColor);
+ preDraw();
+ SkPaint paint;
+ // The glyph is painted as white, modulate it to be of the appropriate color.
+ // SkiaCompatibleDC::wantsTextColorWhite() ensures the glyph is white.
+ // TODO maybe other black/white in WinFontInstance::CacheGlyphToAtlas() should be swapped.
+ paint.setColorFilter(SkColorFilters::Blend(toSkColor(aMaskColor), SkBlendMode::kModulate));
+ mSurface->getCanvas()->drawBitmapRect(
+ static_cast<const SkiaCompatibleDC::Texture*>(pTexture)->bitmap,
+ SkRect::MakeXYWH(rPosAry.mnSrcX, rPosAry.mnSrcY, rPosAry.mnSrcWidth, rPosAry.mnSrcHeight),
+ SkRect::MakeXYWH(rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnDestWidth,
+ rPosAry.mnDestHeight),
+ &paint);
+ postDraw();
}
-void WinSkiaSalGraphicsImpl::DrawMask(CompatibleDC::Texture* pTexture, Color nMaskColor,
- const SalTwoRect& rPosAry)
+void WinSkiaSalGraphicsImpl::DrawTextMask(CompatibleDC::Texture* pTexture, Color nMaskColor,
+ const SalTwoRect& rPosAry)
{
assert(dynamic_cast<SkiaCompatibleDC::Texture*>(pTexture));
- drawMask(rPosAry, static_cast<const SkiaCompatibleDC::Texture*>(pTexture)->bitmap, nMaskColor);
+ const SkBitmap& bitmap = static_cast<const SkiaCompatibleDC::Texture*>(pTexture)->bitmap;
+ preDraw();
+ SkBitmap tmpBitmap;
+ if (!tmpBitmap.tryAllocN32Pixels(bitmap.width(), bitmap.height()))
+ abort();
+ tmpBitmap.eraseColor(toSkColor(nMaskColor));
+ SkPaint paint;
+ // Draw the color with the given mask.
+ // TODO figure out the right blend mode to avoid the temporary bitmap
+ paint.setBlendMode(SkBlendMode::kDstOut);
+ SkCanvas canvas(tmpBitmap);
+ canvas.drawBitmap(bitmap, 0, 0, &paint);
+ mSurface->getCanvas()->drawBitmapRect(
+ tmpBitmap,
+ SkRect::MakeXYWH(rPosAry.mnSrcX, rPosAry.mnSrcY, rPosAry.mnSrcWidth, rPosAry.mnSrcHeight),
+ SkRect::MakeXYWH(rPosAry.mnDestX, rPosAry.mnDestY, rPosAry.mnDestWidth,
+ rPosAry.mnDestHeight),
+ nullptr);
+ postDraw();
}
SkiaCompatibleDC::SkiaCompatibleDC(SalGraphics& rGraphics, int x, int y, int width, int height)
@@ -121,15 +160,35 @@ SkiaCompatibleDC::SkiaCompatibleDC(SalGraphics& rGraphics, int x, int y, int wid
{
}
-std::unique_ptr<CompatibleDC::Texture> SkiaCompatibleDC::getTexture()
+std::unique_ptr<CompatibleDC::Texture> SkiaCompatibleDC::getAsMaskTexture()
{
auto ret = std::make_unique<SkiaCompatibleDC::Texture>();
- // TODO is this correct?
- // TODO make copy of data?
- if (!ret->bitmap.installPixels(SkImageInfo::Make(maRects.mnSrcWidth, maRects.mnSrcHeight,
- kBGRA_8888_SkColorType, kUnpremul_SkAlphaType),
- mpData, maRects.mnSrcWidth * 4))
+ // 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
+ SkBitmap tmpBitmap;
+ if (!tmpBitmap.installPixels(SkImageInfo::Make(maRects.mnSrcWidth, maRects.mnSrcHeight,
+ kBGRA_8888_SkColorType, kOpaque_SkAlphaType),
+ mpData, maRects.mnSrcWidth * 4))
+ abort();
+ SkBitmap bitmap8;
+ if (!bitmap8.tryAllocPixels(SkImageInfo::Make(maRects.mnSrcWidth, maRects.mnSrcHeight,
+ kGray_8_SkColorType, kOpaque_SkAlphaType)))
abort();
+ SkCanvas canvas8(bitmap8);
+ SkPaint paint8;
+ paint8.setBlendMode(SkBlendMode::kSrc); // copy and convert depth
+ // The data we got is upside-down.
+ SkMatrix matrix;
+ matrix.preTranslate(0, maRects.mnSrcHeight);
+ matrix.setConcat(matrix, SkMatrix::MakeScale(1, -1));
+ canvas8.concat(matrix);
+ canvas8.drawBitmap(tmpBitmap, 0, 0, &paint8);
+ // use the 8bit data as an alpha channel
+ SkBitmap alpha;
+ alpha.setInfo(bitmap8.info().makeColorType(kAlpha_8_SkColorType), bitmap8.rowBytes());
+ alpha.setPixelRef(sk_ref_sp(bitmap8.pixelRef()), bitmap8.pixelRefOrigin().x(),
+ bitmap8.pixelRefOrigin().y());
+ ret->bitmap = alpha;
return ret;
}
diff --git a/vcl/win/gdi/winlayout.cxx b/vcl/win/gdi/winlayout.cxx
index 06189c6a7643..cf264425ae17 100644
--- a/vcl/win/gdi/winlayout.cxx
+++ b/vcl/win/gdi/winlayout.cxx
@@ -171,7 +171,8 @@ bool WinFontInstance::CacheGlyphToAtlas(HDC hDC, HFONT hFont, int nGlyphIndex,
auto pRT = pTxt->GetRenderTarget();
ID2D1SolidColorBrush* pBrush = nullptr;
- if (!SUCCEEDED(pRT->CreateSolidColorBrush(D2D1::ColorF(D2D1::ColorF::Black), &pBrush)))
+ D2D1::ColorF textColor = aDC->wantsTextColorWhite() ? D2D1::ColorF::White : D2D1::ColorF::Black;
+ if (!SUCCEEDED(pRT->CreateSolidColorBrush(textColor, &pBrush)))
return false;
D2D1_POINT_2F baseline = {
@@ -622,9 +623,9 @@ void WinSalGraphics::DrawTextLayout(const GenericSalLayout& rLayout)
// the actual drawing
DrawTextLayout(rLayout, aDC->getCompatibleHDC(), !bForceGDI);
- std::unique_ptr<CompatibleDC::Texture> xTexture(aDC->getTexture());
+ std::unique_ptr<CompatibleDC::Texture> xTexture(aDC->getAsMaskTexture());
if (xTexture)
- pImpl->DrawMask(xTexture.get(), salColor, aDC->getTwoRect());
+ pImpl->DrawTextMask(xTexture.get(), salColor, aDC->getTwoRect());
::SelectFont(aDC->getCompatibleHDC(), hOrigFont);