diff options
author | Tomaž Vajngerl <tomaz.vajngerl@collabora.co.uk> | 2017-07-19 23:28:31 +0200 |
---|---|---|
committer | Tomaž Vajngerl <quikee@gmail.com> | 2017-07-20 18:26:24 +0200 |
commit | 3fdc41af6370a53f7db4e52104cfd3328ee40563 (patch) | |
tree | 3d29c37e366f6e81dd65d0b8be650c67b119f94e | |
parent | 37436815970b14f8940fc0c547862452a2dc3e1e (diff) |
tdf#107166 improve AA mode selection, retry, more checks
Major problem when setting the render mode and the text antialias
mode is that when you set the render mode to something that isn't
compatible with the text antialias mode, then every next call will
cause an error (invalid parameters). So we need to be sure that we
never set incompatible modes. Additionally we just need to set it
one time when we create the surface and not every time we draw.
If we get the D2DERR_RECREATE_TARGET we can create a new render
target and retry the whole call. Somethimes this is not possible
so we try 3 times and the give up.
We need to add more checks where we exit early or not continue with
some calls as any additional calls could taint the draw state and
some things wouldn't be drawn. For example if we calculate the
sizes of 0 glyphs we shouldn't continue with binding the hDC with
an "empty" rectangle. This will fail and cause some text that is
called afterwards to not draw.
Change-Id: Iabbdbd7956e90ea84aea96824c0d985ca9020c59
Reviewed-on: https://gerrit.libreoffice.org/40211
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
-rwxr-xr-x | vcl/inc/win/DWriteTextRenderer.hxx | 13 | ||||
-rwxr-xr-x | vcl/win/gdi/DWriteTextRenderer.cxx | 106 | ||||
-rw-r--r-- | vcl/win/gdi/winlayout.cxx | 3 |
3 files changed, 84 insertions, 38 deletions
diff --git a/vcl/inc/win/DWriteTextRenderer.hxx b/vcl/inc/win/DWriteTextRenderer.hxx index 611a134396f7..e87ef5fe977b 100755 --- a/vcl/inc/win/DWriteTextRenderer.hxx +++ b/vcl/inc/win/DWriteTextRenderer.hxx @@ -29,8 +29,9 @@ enum class D2DTextAntiAliasMode { Default, - ClearType, + Aliased, AntiAliased, + ClearType, }; class D2DWriteTextOutRenderer : public TextOutRenderer @@ -55,7 +56,7 @@ public: SalGraphics &rGraphics, HDC hDC) override; - bool BindDC(HDC hDC, tools::Rectangle const & rRect = tools::Rectangle(0, 0, 1, 1)); + HRESULT BindDC(HDC hDC, tools::Rectangle const & rRect = tools::Rectangle(0, 0, 1, 1)); bool BindFont(HDC hDC) /*override*/; bool ReleaseFont() /*override*/; @@ -70,10 +71,8 @@ public: bool Ready() const; void applyTextAntiAliasMode(); - void setTextAntiAliasMode(D2DTextAntiAliasMode eMode) - { - meTextAntiAliasMode = eMode; - } + void changeTextAntiAliasMode(D2DTextAntiAliasMode eMode); + private: static void CleanupModules(); @@ -82,6 +81,7 @@ private: D2DWriteTextOutRenderer & operator = (const D2DWriteTextOutRenderer &) = delete; bool GetDWriteFaceFromHDC(HDC hDC, IDWriteFontFace ** ppFontFace, float * lfSize) const; + bool performRender(CommonSalLayout const &rLayout, SalGraphics &rGraphics, HDC hDC, bool& bRetry); ID2D1Factory * mpD2DFactory; IDWriteFactory * mpDWriteFactory; @@ -93,7 +93,6 @@ private: float mlfEmHeight; HDC mhDC; D2DTextAntiAliasMode meTextAntiAliasMode; - IDWriteRenderingParams* mpRenderingParameters; }; #endif // INCLUDED_VCL_INC_WIN_DWRITERENDERER_HXX diff --git a/vcl/win/gdi/DWriteTextRenderer.cxx b/vcl/win/gdi/DWriteTextRenderer.cxx index f876f368e882..11469aadb597 100755 --- a/vcl/win/gdi/DWriteTextRenderer.cxx +++ b/vcl/win/gdi/DWriteTextRenderer.cxx @@ -80,12 +80,15 @@ D2DTextAntiAliasMode lclGetSystemTextAntiAliasMode() if (bFontSmoothing) { - UINT nType; - if (!SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &nType, 0)) - return eMode; + eMode = D2DTextAntiAliasMode::AntiAliased; - eMode = (nType == FE_FONTSMOOTHINGCLEARTYPE) ? D2DTextAntiAliasMode::ClearType - : D2DTextAntiAliasMode::AntiAliased; + UINT nType; + if (SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &nType, 0) && nType == FE_FONTSMOOTHINGCLEARTYPE) + eMode = D2DTextAntiAliasMode::ClearType; + } + else + { + eMode = D2DTextAntiAliasMode::Aliased; } return eMode; @@ -150,7 +153,6 @@ D2DWriteTextOutRenderer::D2DWriteTextOutRenderer() hr = CreateRenderTarget(); } meTextAntiAliasMode = lclGetSystemTextAntiAliasMode(); - mpRenderingParameters = lclSetRenderingMode(mpDWriteFactory, DWRITE_RENDERING_MODE_GDI_CLASSIC); } D2DWriteTextOutRenderer::~D2DWriteTextOutRenderer() @@ -169,23 +171,31 @@ D2DWriteTextOutRenderer::~D2DWriteTextOutRenderer() void D2DWriteTextOutRenderer::applyTextAntiAliasMode() { - D2D1_TEXT_ANTIALIAS_MODE eMode = D2D1_TEXT_ANTIALIAS_MODE_DEFAULT; + D2D1_TEXT_ANTIALIAS_MODE eTextAAMode = D2D1_TEXT_ANTIALIAS_MODE_DEFAULT; + DWRITE_RENDERING_MODE eRenderingMode = DWRITE_RENDERING_MODE_DEFAULT; switch (meTextAntiAliasMode) { case D2DTextAntiAliasMode::Default: - eMode = D2D1_TEXT_ANTIALIAS_MODE_ALIASED; + eRenderingMode = DWRITE_RENDERING_MODE_DEFAULT; + eTextAAMode = D2D1_TEXT_ANTIALIAS_MODE_DEFAULT; + break; + case D2DTextAntiAliasMode::Aliased: + eRenderingMode = DWRITE_RENDERING_MODE_ALIASED; + eTextAAMode = D2D1_TEXT_ANTIALIAS_MODE_ALIASED; break; case D2DTextAntiAliasMode::AntiAliased: - eMode = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE; + eRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC; + eTextAAMode = D2D1_TEXT_ANTIALIAS_MODE_GRAYSCALE; break; case D2DTextAntiAliasMode::ClearType: - eMode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE; + eRenderingMode = DWRITE_RENDERING_MODE_CLEARTYPE_GDI_CLASSIC; + eTextAAMode = D2D1_TEXT_ANTIALIAS_MODE_CLEARTYPE; break; default: break; } - mpRT->SetTextAntialiasMode(eMode); - mpRT->SetTextRenderingParams(mpRenderingParameters); + mpRT->SetTextRenderingParams(lclSetRenderingMode(mpDWriteFactory, eRenderingMode)); + mpRT->SetTextAntialiasMode(eTextAAMode); } HRESULT D2DWriteTextOutRenderer::CreateRenderTarget() @@ -195,7 +205,19 @@ HRESULT D2DWriteTextOutRenderer::CreateRenderTarget() mpRT->Release(); mpRT = nullptr; } - return CHECKHR(mpD2DFactory->CreateDCRenderTarget(&mRTProps, &mpRT)); + HRESULT hr = CHECKHR(mpD2DFactory->CreateDCRenderTarget(&mRTProps, &mpRT)); + if (SUCCEEDED(hr)) + applyTextAntiAliasMode(); + return hr; +} + +void D2DWriteTextOutRenderer::changeTextAntiAliasMode(D2DTextAntiAliasMode eMode) +{ + if (meTextAntiAliasMode != eMode) + { + meTextAntiAliasMode = eMode; + applyTextAntiAliasMode(); + } } bool D2DWriteTextOutRenderer::Ready() const @@ -203,41 +225,64 @@ bool D2DWriteTextOutRenderer::Ready() const return mpGdiInterop && mpRT; } -bool D2DWriteTextOutRenderer::BindDC(HDC hDC, tools::Rectangle const & rRect) +HRESULT D2DWriteTextOutRenderer::BindDC(HDC hDC, tools::Rectangle const & rRect) { - if (rRect.GetWidth() == 0 || rRect.GetHeight() == 0) - return false; RECT const rc = { rRect.Left(), rRect.Top(), rRect.Right(), rRect.Bottom() }; - return SUCCEEDED(CHECKHR(mpRT->BindDC(hDC, &rc))); + return CHECKHR(mpRT->BindDC(hDC, &rc)); +} + +bool D2DWriteTextOutRenderer::operator ()(CommonSalLayout const & rLayout, SalGraphics& rGraphics, HDC hDC) +{ + bool bRetry = false; + bool bResult = false; + int nCount = 0; + do + { + bRetry = false; + bResult = performRender(rLayout, rGraphics, hDC, bRetry); + nCount++; + } while (bRetry && nCount < 3); + return bResult; } -bool D2DWriteTextOutRenderer::operator ()(CommonSalLayout const &rLayout, - SalGraphics &rGraphics, - HDC hDC) +bool D2DWriteTextOutRenderer::performRender(CommonSalLayout const & rLayout, SalGraphics& rGraphics, HDC hDC, bool& bRetry) { if (!Ready()) return false; - if (!BindFont(hDC)) + HRESULT hr = S_OK; + hr = BindDC(hDC); + + if (hr == D2DERR_RECREATE_TARGET) { - // If for any reason we can't bind fallback to legacy APIs. - return ExTextOutRenderer()(rLayout, rGraphics, hDC); + CreateRenderTarget(); + bRetry = true; + return false; } + mlfEmHeight = 0; + if (!GetDWriteFaceFromHDC(hDC, &mpFontFace, &mlfEmHeight)) + return false; + tools::Rectangle bounds; bool succeeded = rLayout.GetBoundRect(rGraphics, bounds); - succeeded &= BindDC(hDC, bounds); // Update the bounding rect. + if (succeeded) + { + hr = BindDC(hDC, bounds); // Update the bounding rect. + succeeded &= SUCCEEDED(hr); + } ID2D1SolidColorBrush* pBrush = nullptr; - COLORREF bgrTextColor = GetTextColor(mhDC); - D2D1::ColorF aD2DColor(GetRValue(bgrTextColor) / 255.0f, GetGValue(bgrTextColor) / 255.0f, GetBValue(bgrTextColor) / 255.0f); - succeeded &= SUCCEEDED(CHECKHR(mpRT->CreateSolidColorBrush(aD2DColor, &pBrush))); + if (succeeded) + { + COLORREF bgrTextColor = GetTextColor(hDC); + D2D1::ColorF aD2DColor(GetRValue(bgrTextColor) / 255.0f, GetGValue(bgrTextColor) / 255.0f, GetBValue(bgrTextColor) / 255.0f); + succeeded &= SUCCEEDED(CHECKHR(mpRT->CreateSolidColorBrush(aD2DColor, &pBrush))); + } - HRESULT hr = S_OK; if (succeeded) { mpRT->BeginDraw(); - applyTextAntiAliasMode(); int nStart = 0; Point aPos(0, 0); @@ -271,7 +316,10 @@ bool D2DWriteTextOutRenderer::operator ()(CommonSalLayout const &rLayout, ReleaseFont(); if (hr == D2DERR_RECREATE_TARGET) + { CreateRenderTarget(); + bRetry = true; + } return succeeded; } diff --git a/vcl/win/gdi/winlayout.cxx b/vcl/win/gdi/winlayout.cxx index facaf82ad93c..df3db65362ab 100644 --- a/vcl/win/gdi/winlayout.cxx +++ b/vcl/win/gdi/winlayout.cxx @@ -79,7 +79,7 @@ bool WinFontInstance::CacheGlyphToAtlas(HDC hDC, HFONT hFont, int nGlyphIndex, S if (!pTxt) return false; - pTxt->setTextAntiAliasMode(D2DTextAntiAliasMode::AntiAliased); + pTxt->changeTextAntiAliasMode(D2DTextAntiAliasMode::AntiAliased); if (!pTxt->BindFont(aHDC.get())) { @@ -180,7 +180,6 @@ bool WinFontInstance::CacheGlyphToAtlas(HDC hDC, HFONT hFont, int nGlyphIndex, S }; pRT->BeginDraw(); - pTxt->applyTextAntiAliasMode(); pRT->DrawGlyphRun(baseline, &glyphs, pBrush); HRESULT hResult = pRT->EndDraw(); |