Kaydet (Commit) 61085083 authored tarafından Tor Lillqvist's avatar Tor Lillqvist

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
b7842c93 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
üst 4336db6d
...@@ -566,7 +566,10 @@ void WinLayout::DrawText(SalGraphics& rGraphics) const ...@@ -566,7 +566,10 @@ void WinLayout::DrawText(SalGraphics& rGraphics) const
if (!mbUseOpenGL) if (!mbUseOpenGL)
{ {
// no OpenGL, just classic rendering // 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) && else if (CacheGlyphs(rGraphics) &&
DrawCachedGlyphs(rGraphics)) DrawCachedGlyphs(rGraphics))
...@@ -607,40 +610,49 @@ void WinLayout::DrawText(SalGraphics& rGraphics) const ...@@ -607,40 +610,49 @@ void WinLayout::DrawText(SalGraphics& rGraphics) const
Rectangle aRect; Rectangle aRect;
GetBoundRect(rGraphics, 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 if (pImpl)
assert(aDC.getCompatibleHDC() != hDC); {
pImpl->PreDraw();
// setup the hidden DC with black color and white background, we will Point aPos(0, 0);
// use the result of the text drawing later as a mask only int nGetNextGlypInfo(0);
HFONT hOrigFont = SelectFont(aDC.getCompatibleHDC(), mhFont); while (true)
{
OpenGLCompatibleDC aDC(rGraphics, aRect.Left(), aRect.Top(), aRect.GetWidth(), aRect.GetHeight());
SetTextColor(aDC.getCompatibleHDC(), RGB(0, 0, 0)); // we are making changes to the DC, make sure we got a new one
SetBkColor(aDC.getCompatibleHDC(), RGB(255, 255, 255)); assert(aDC.getCompatibleHDC() != hDC);
UINT nTextAlign = GetTextAlign(hDC); // setup the hidden DC with black color and white background, we will
SetTextAlign(aDC.getCompatibleHDC(), nTextAlign); // use the result of the text drawing later as a mask only
HFONT hOrigFont = SelectFont(aDC.getCompatibleHDC(), mhFont);
// the actual drawing SetTextColor(aDC.getCompatibleHDC(), RGB(0, 0, 0));
DrawTextImpl(aDC.getCompatibleHDC(), &aRect); SetBkColor(aDC.getCompatibleHDC(), RGB(255, 255, 255));
COLORREF color = GetTextColor(hDC); UINT nTextAlign = GetTextAlign(hDC);
SalColor salColor = MAKE_SALCOLOR(GetRValue(color), GetGValue(color), GetBValue(color)); SetTextAlign(aDC.getCompatibleHDC(), nTextAlign);
WinOpenGLSalGraphicsImpl *pImpl = dynamic_cast<WinOpenGLSalGraphicsImpl*>(rWinGraphics.mpImpl.get()); COLORREF color = GetTextColor(hDC);
if (pImpl) SalColor salColor = MAKE_SALCOLOR(GetRValue(color), GetGValue(color), GetBValue(color));
{
pImpl->PreDraw(); // the actual drawing
bool bContinue = DrawTextImpl(aDC.getCompatibleHDC(), &aRect, &aPos, &nGetNextGlypInfo);
std::unique_ptr<OpenGLTexture> xTexture(aDC.getTexture()); std::unique_ptr<OpenGLTexture> xTexture(aDC.getTexture());
if (xTexture) if (xTexture)
pImpl->DrawMask(*xTexture, salColor, aDC.getTwoRect()); pImpl->DrawMask(*xTexture, salColor, aDC.getTwoRect());
SelectFont(aDC.getCompatibleHDC(), hOrigFont);
if (!bContinue)
break;
}
pImpl->PostDraw(); pImpl->PostDraw();
} }
SelectFont(aDC.getCompatibleHDC(), hOrigFont);
} }
} }
...@@ -1764,7 +1776,10 @@ void UniscribeLayout::Simplify( bool /*bIsBase*/ ) ...@@ -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(); HFONT hOrigFont = DisableFontScaling();
...@@ -1812,6 +1827,8 @@ void UniscribeLayout::DrawTextImpl(HDC hDC, const Rectangle* /* pRectToErase */) ...@@ -1812,6 +1827,8 @@ void UniscribeLayout::DrawTextImpl(HDC hDC, const Rectangle* /* pRectToErase */)
if( hOrigFont ) if( hOrigFont )
DeleteFont(SelectFont(hDC, hOrigFont)); DeleteFont(SelectFont(hDC, hOrigFont));
return false;
} }
bool UniscribeLayout::CacheGlyphs(SalGraphics& rGraphics) const bool UniscribeLayout::CacheGlyphs(SalGraphics& rGraphics) const
...@@ -2801,7 +2818,10 @@ void GraphiteWinLayout::AdjustLayout(ImplLayoutArgs& rArgs) ...@@ -2801,7 +2818,10 @@ void GraphiteWinLayout::AdjustLayout(ImplLayoutArgs& rArgs)
maImpl.AdjustLayout(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) if (pRectToErase)
{ {
...@@ -2815,19 +2835,18 @@ void GraphiteWinLayout::DrawTextImpl(HDC hDC, const Rectangle* pRectToErase) con ...@@ -2815,19 +2835,18 @@ void GraphiteWinLayout::DrawTextImpl(HDC hDC, const Rectangle* pRectToErase) con
const int MAX_GLYPHS = 2; const int MAX_GLYPHS = 2;
sal_GlyphId glyphIntStr[MAX_GLYPHS]; sal_GlyphId glyphIntStr[MAX_GLYPHS];
WORD glyphWStr[MAX_GLYPHS]; WORD glyphWStr[MAX_GLYPHS];
int glyphIndex = 0;
Point aPos(0,0);
int nGlyphs = 0; int nGlyphs = 0;
do do
{ {
nGlyphs = maImpl.GetNextGlyphs(1, glyphIntStr, aPos, glyphIndex); nGlyphs = maImpl.GetNextGlyphs(1, glyphIntStr, *pPos, *pGetNextGlypInfo);
if (nGlyphs < 1) if (nGlyphs < 1)
break; break;
std::copy(glyphIntStr, glyphIntStr + nGlyphs, glyphWStr); std::copy(glyphIntStr, glyphIntStr + nGlyphs, glyphWStr);
ExtTextOutW(hDC, aPos.X(), aPos.Y(), ETO_GLYPH_INDEX, NULL, (LPCWSTR)&(glyphWStr), nGlyphs, NULL); ExtTextOutW(hDC, pPos->X(), pPos->Y(), ETO_GLYPH_INDEX, NULL, (LPCWSTR)&(glyphWStr), nGlyphs, NULL);
} while (nGlyphs); } while (!pRectToErase);
if( hOrigFont ) if( hOrigFont )
DeleteFont(SelectFont(hDC, hOrigFont)); DeleteFont(SelectFont(hDC, hOrigFont));
return (pRectToErase && nGlyphs >= 1);
} }
bool GraphiteWinLayout::CacheGlyphs(SalGraphics& /*rGraphics*/) const bool GraphiteWinLayout::CacheGlyphs(SalGraphics& /*rGraphics*/) const
......
...@@ -53,7 +53,7 @@ public: ...@@ -53,7 +53,7 @@ public:
virtual void DrawText(SalGraphics&) const override; virtual void DrawText(SalGraphics&) const override;
/// Draw to the provided HDC. /// 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 CacheGlyphs(SalGraphics& rGraphics) const = 0;
virtual bool DrawCachedGlyphs(SalGraphics& rGraphics) const = 0; virtual bool DrawCachedGlyphs(SalGraphics& rGraphics) const = 0;
...@@ -75,7 +75,7 @@ public: ...@@ -75,7 +75,7 @@ public:
virtual bool LayoutText( ImplLayoutArgs& ) override; virtual bool LayoutText( ImplLayoutArgs& ) override;
virtual void AdjustLayout( 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 CacheGlyphs(SalGraphics& rGraphics) const override;
virtual bool DrawCachedGlyphs(SalGraphics& rGraphics) const override; virtual bool DrawCachedGlyphs(SalGraphics& rGraphics) const override;
virtual int GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos, int&, virtual int GetNextGlyphs( int nLen, sal_GlyphId* pGlyphs, Point& rPos, int&,
...@@ -168,7 +168,7 @@ public: ...@@ -168,7 +168,7 @@ public:
// used by upper layers // used by upper layers
virtual bool LayoutText( ImplLayoutArgs& ) override; // first step of layout virtual bool LayoutText( ImplLayoutArgs& ) override; // first step of layout
virtual void AdjustLayout( ImplLayoutArgs& ) override; // adjusting after fallback etc. 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 CacheGlyphs(SalGraphics& rGraphics) const override;
virtual bool DrawCachedGlyphs(SalGraphics& rGraphics) const override; virtual bool DrawCachedGlyphs(SalGraphics& rGraphics) const override;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment