diff options
author | Tor Lillqvist <tml@collabora.com> | 2015-12-18 14:38:27 +0200 |
---|---|---|
committer | Tor Lillqvist <tml@collabora.com> | 2015-12-18 15:02:47 +0200 |
commit | ac04051a3565bb5cde904da9a84b6e22443cf8b5 (patch) | |
tree | f7a3f4d6710d6b28e7bfec00366766f62a9b81a2 | |
parent | 6e80c6b9d40408a745ab0ced5d217118985e4079 (diff) |
tdf#95054: Make sure glyphs alpha blend properly in the Graphite+OpenGL case
The problem apparently was that the GraphiteWinLayout::DrawTextImpl()
function drew each glyph using a separate call to ExtTextOutW(). That
mishandled anti-aliased glyphs (alpha), somewhat in the way as
described in the nice long comment (thanks kendy!) in
WinLayout::DrawText().
The irony here is that in the case of Graphite fonts and OpenGL, it is
exactly from that code block in WinLayout::DrawText() that
GraphiteWinLayout::DrawTextImpl() gets called, and in that situation
it itself runs into the same or similar problem as the calling code
wants to avoid for the run as a whole. It draws each glyph separately,
and subsequent glyphs will overwrite the rightmost pixels of the
earlier one instead of blend properly. Or something like that.
As a solution, change the interface of DrawTextImpl() so that instead
of being called once to draw a run of text, it might draw just a part
of the run, and in that case expects to be called repeatedly to draw
the whole text.
The GraphiteWinLayout::DrawTextImpl() implementation does it like this
in the case of using OpenGL (as indicated by the presence of a
non-null pRectToErase, as added in
b7842c93dc06b831d3fa649410ed847358ce9d17 for tdf#95648). The end
result is that it draws one glyph at a time into the DC for the bitmap
allocated in the caller, WinLayout::DrawText(). The caller uses that
bitmap as a texture and blends it into the actual destination,
separately for each glyph.
For non-Graphite fonts, or when not using OpenGL, nothing should
change. No repeated DrawTextImpl calls are done to iterate over a run.
Change-Id: Ib7adc30665fc7804913fd2f8886c5b29d9ca42c4
(cherry picked from commit 61085083e4a5060ba7e2135818264d63c6da13c2)
-rw-r--r-- | vcl/win/source/gdi/winlayout.cxx | 79 | ||||
-rw-r--r-- | vcl/win/source/gdi/winlayout.hxx | 6 |
2 files changed, 52 insertions, 33 deletions
diff --git a/vcl/win/source/gdi/winlayout.cxx b/vcl/win/source/gdi/winlayout.cxx index 7c573666edd8..cef4f8a73f5b 100644 --- a/vcl/win/source/gdi/winlayout.cxx +++ b/vcl/win/source/gdi/winlayout.cxx @@ -566,7 +566,10 @@ void WinLayout::DrawText(SalGraphics& rGraphics) const if (!mbUseOpenGL) { // no OpenGL, just classic rendering - DrawTextImpl(hDC, NULL); + Point aPos(0, 0); + int nGetNextGlypInfo(0); + bool bContinue = DrawTextImpl(hDC, NULL, &aPos, &nGetNextGlypInfo); + assert(!bContinue); } else if (CacheGlyphs(rGraphics) && DrawCachedGlyphs(rGraphics)) @@ -607,40 +610,49 @@ void WinLayout::DrawText(SalGraphics& rGraphics) const Rectangle aRect; GetBoundRect(rGraphics, aRect); - OpenGLCompatibleDC aDC(rGraphics, aRect.Left(), aRect.Top(), aRect.GetWidth(), aRect.GetHeight()); + WinOpenGLSalGraphicsImpl *pImpl = dynamic_cast<WinOpenGLSalGraphicsImpl*>(rWinGraphics.mpImpl.get()); - // we are making changes to the DC, make sure we got a new one - assert(aDC.getCompatibleHDC() != hDC); + if (pImpl) + { + pImpl->PreDraw(); - // setup the hidden DC with black color and white background, we will - // use the result of the text drawing later as a mask only - HFONT hOrigFont = SelectFont(aDC.getCompatibleHDC(), mhFont); + Point aPos(0, 0); + int nGetNextGlypInfo(0); + while (true) + { + OpenGLCompatibleDC aDC(rGraphics, aRect.Left(), aRect.Top(), aRect.GetWidth(), aRect.GetHeight()); - SetTextColor(aDC.getCompatibleHDC(), RGB(0, 0, 0)); - SetBkColor(aDC.getCompatibleHDC(), RGB(255, 255, 255)); + // we are making changes to the DC, make sure we got a new one + assert(aDC.getCompatibleHDC() != hDC); - UINT nTextAlign = GetTextAlign(hDC); - SetTextAlign(aDC.getCompatibleHDC(), nTextAlign); + // setup the hidden DC with black color and white background, we will + // use the result of the text drawing later as a mask only + HFONT hOrigFont = SelectFont(aDC.getCompatibleHDC(), mhFont); - // the actual drawing - DrawTextImpl(aDC.getCompatibleHDC(), &aRect); + SetTextColor(aDC.getCompatibleHDC(), RGB(0, 0, 0)); + SetBkColor(aDC.getCompatibleHDC(), RGB(255, 255, 255)); - COLORREF color = GetTextColor(hDC); - SalColor salColor = MAKE_SALCOLOR(GetRValue(color), GetGValue(color), GetBValue(color)); + UINT nTextAlign = GetTextAlign(hDC); + SetTextAlign(aDC.getCompatibleHDC(), nTextAlign); - WinOpenGLSalGraphicsImpl *pImpl = dynamic_cast<WinOpenGLSalGraphicsImpl*>(rWinGraphics.mpImpl.get()); - if (pImpl) - { - pImpl->PreDraw(); + COLORREF color = GetTextColor(hDC); + SalColor salColor = MAKE_SALCOLOR(GetRValue(color), GetGValue(color), GetBValue(color)); + + // the actual drawing + bool bContinue = DrawTextImpl(aDC.getCompatibleHDC(), &aRect, &aPos, &nGetNextGlypInfo); - std::unique_ptr<OpenGLTexture> xTexture(aDC.getTexture()); - if (xTexture) - pImpl->DrawMask(*xTexture, salColor, aDC.getTwoRect()); + std::unique_ptr<OpenGLTexture> xTexture(aDC.getTexture()); + if (xTexture) + pImpl->DrawMask(*xTexture, salColor, aDC.getTwoRect()); + SelectFont(aDC.getCompatibleHDC(), hOrigFont); + + if (!bContinue) + break; + } pImpl->PostDraw(); } - SelectFont(aDC.getCompatibleHDC(), hOrigFont); } } @@ -1764,7 +1776,10 @@ void UniscribeLayout::Simplify( bool /*bIsBase*/ ) } } -void UniscribeLayout::DrawTextImpl(HDC hDC, const Rectangle* /* pRectToErase */) const +bool UniscribeLayout::DrawTextImpl(HDC hDC, + const Rectangle* /* pRectToErase */, + Point* /* pPos */, + int* /* pGetNextGlypInfo */) const { HFONT hOrigFont = DisableFontScaling(); @@ -1812,6 +1827,8 @@ void UniscribeLayout::DrawTextImpl(HDC hDC, const Rectangle* /* pRectToErase */) if( hOrigFont ) DeleteFont(SelectFont(hDC, hOrigFont)); + + return false; } bool UniscribeLayout::CacheGlyphs(SalGraphics& rGraphics) const @@ -2770,7 +2787,10 @@ void GraphiteWinLayout::AdjustLayout(ImplLayoutArgs& rArgs) maImpl.AdjustLayout(rArgs); } -void GraphiteWinLayout::DrawTextImpl(HDC hDC, const Rectangle* pRectToErase) const +bool GraphiteWinLayout::DrawTextImpl(HDC hDC, + const Rectangle* pRectToErase, + Point* pPos, + int* pGetNextGlypInfo) const { if (pRectToErase) { @@ -2784,19 +2804,18 @@ void GraphiteWinLayout::DrawTextImpl(HDC hDC, const Rectangle* pRectToErase) con const int MAX_GLYPHS = 2; sal_GlyphId glyphIntStr[MAX_GLYPHS]; WORD glyphWStr[MAX_GLYPHS]; - int glyphIndex = 0; - Point aPos(0,0); int nGlyphs = 0; do { - nGlyphs = maImpl.GetNextGlyphs(1, glyphIntStr, aPos, glyphIndex); + nGlyphs = maImpl.GetNextGlyphs(1, glyphIntStr, *pPos, *pGetNextGlypInfo); if (nGlyphs < 1) break; std::copy(glyphIntStr, glyphIntStr + nGlyphs, glyphWStr); - ExtTextOutW(hDC, aPos.X(), aPos.Y(), ETO_GLYPH_INDEX, NULL, (LPCWSTR)&(glyphWStr), nGlyphs, NULL); - } while (nGlyphs); + ExtTextOutW(hDC, pPos->X(), pPos->Y(), ETO_GLYPH_INDEX, NULL, (LPCWSTR)&(glyphWStr), nGlyphs, NULL); + } while (!pRectToErase); if( hOrigFont ) DeleteFont(SelectFont(hDC, hOrigFont)); + return (pRectToErase && nGlyphs >= 1); } bool GraphiteWinLayout::CacheGlyphs(SalGraphics& /*rGraphics*/) const diff --git a/vcl/win/source/gdi/winlayout.hxx b/vcl/win/source/gdi/winlayout.hxx index db09d1eda308..ff4e5cced2a3 100644 --- a/vcl/win/source/gdi/winlayout.hxx +++ b/vcl/win/source/gdi/winlayout.hxx @@ -53,7 +53,7 @@ public: virtual void DrawText(SalGraphics&) const override; /// Draw to the provided HDC. - virtual void DrawTextImpl(HDC hDC, const Rectangle* pRectToErase) const = 0; + virtual bool DrawTextImpl(HDC hDC, const Rectangle* pRectToErase, Point* pPos, int* pGetNextGlypInfo) const = 0; virtual bool CacheGlyphs(SalGraphics& rGraphics) const = 0; virtual bool DrawCachedGlyphs(SalGraphics& rGraphics) const = 0; @@ -75,7 +75,7 @@ public: virtual bool LayoutText( ImplLayoutArgs& ) override; virtual void AdjustLayout( ImplLayoutArgs& ) override; - virtual void DrawTextImpl(HDC hDC, const Rectangle* pRectToErase) const override; + virtual bool DrawTextImpl(HDC hDC, const Rectangle* pRectToErase, Point* pPos, int* pGetNextGlypInfo) const override; virtual bool CacheGlyphs(SalGraphics& rGraphics) const override; virtual bool DrawCachedGlyphs(SalGraphics& rGraphics) const override; virtual int GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos, int&, @@ -168,7 +168,7 @@ public: // used by upper layers virtual bool LayoutText( ImplLayoutArgs& ) override; // first step of layout virtual void AdjustLayout( ImplLayoutArgs& ) override; // adjusting after fallback etc. - virtual void DrawTextImpl(HDC hDC, const Rectangle* pRectToErase) const override; + virtual bool DrawTextImpl(HDC hDC, const Rectangle* pRectToErase, Point* pPos, int* pGetNextGlypInfo) const override; virtual bool CacheGlyphs(SalGraphics& rGraphics) const override; virtual bool DrawCachedGlyphs(SalGraphics& rGraphics) const override; |