From b62b6094dd56c53f6508feaa61b43b49247d25ff Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Mon, 8 Apr 2024 11:56:56 +0200 Subject: [PATCH] Implement aliased text rendering with DirectWrite This creates aliased glyphs using the DirectWrite engine when requested. Note: There was previously a fallback to GDI to support aliased text, which ignored the hinting settings. This patch also removes that fallback. [ChangeLog][Windows] Support QFont::NoAntialias with the DirectWrite font engine. Pick-to: 6.6 6.5 Fixes: QTBUG-97645 Change-Id: I587f56ace468cfdd57debe7bc8492a96587a4e05 Reviewed-by: Allan Sandfeld Jensen (cherry picked from commit 421e7621faa50bf9007076d6be4e0da9514edc59) --- .../windows/qwindowsfontenginedirectwrite.cpp | 42 ++++++++++++++----- .../windows/qwindowsfontenginedirectwrite_p.h | 11 ++++- 2 files changed, 42 insertions(+), 11 deletions(-) diff --git a/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp b/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp index 339c762754e..87cfbd2b506 100644 --- a/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp +++ b/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp @@ -162,8 +162,11 @@ static DWRITE_MEASURING_MODE renderModeToMeasureMode(DWRITE_RENDERING_MODE rende } } -static DWRITE_RENDERING_MODE hintingPreferenceToRenderingMode(const QFontDef &fontDef) +DWRITE_RENDERING_MODE QWindowsFontEngineDirectWrite::hintingPreferenceToRenderingMode(const QFontDef &fontDef) const { + if ((fontDef.styleStrategy & QFont::NoAntialias) && glyphFormat != QFontEngine::Format_ARGB) + return DWRITE_RENDERING_MODE_ALIASED; + QFont::HintingPreference hintingPreference = QFont::HintingPreference(fontDef.hintingPreference); if (!qFuzzyCompare(qApp->devicePixelRatio(), 1.0) && hintingPreference == QFont::PreferDefaultHinting) { // Microsoft documentation recommends using asymmetric rendering for small fonts @@ -484,7 +487,8 @@ void QWindowsFontEngineDirectWrite::recalcAdvances(QGlyphLayout *glyphs, QFontEn DWRITE_RENDERING_MODE renderMode = hintingPreferenceToRenderingMode(fontDef); bool needsDesignMetrics = shaperFlags & QFontEngine::DesignMetrics; if (!needsDesignMetrics && (renderMode == DWRITE_RENDERING_MODE_GDI_CLASSIC - || renderMode == DWRITE_RENDERING_MODE_GDI_NATURAL)) { + || renderMode == DWRITE_RENDERING_MODE_GDI_NATURAL + || renderMode == DWRITE_RENDERING_MODE_ALIASED)) { hr = m_directWriteFontFace->GetGdiCompatibleGlyphMetrics(float(fontDef.pixelSize), 1.0f, NULL, @@ -673,7 +677,8 @@ QImage QWindowsFontEngineDirectWrite::alphaMapForGlyph(glyph_t glyph, bool QWindowsFontEngineDirectWrite::supportsHorizontalSubPixelPositions() const { - return true; + DWRITE_RENDERING_MODE renderMode = hintingPreferenceToRenderingMode(fontDef); + return renderMode != DWRITE_RENDERING_MODE_ALIASED; } QFontEngine::Properties QWindowsFontEngineDirectWrite::properties() const @@ -776,7 +781,10 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t, if (SUCCEEDED(hr)) { RECT rect; - glyphAnalysis->GetAlphaTextureBounds(DWRITE_TEXTURE_CLEARTYPE_3x1, &rect); + glyphAnalysis->GetAlphaTextureBounds(renderMode == DWRITE_RENDERING_MODE_ALIASED + ? DWRITE_TEXTURE_ALIASED_1x1 + : DWRITE_TEXTURE_CLEARTYPE_3x1, + &rect); if (rect.top == rect.bottom || rect.left == rect.right) return QImage(); @@ -857,7 +865,8 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t, b, a, colorGlyphsAnalysis, - boundingRect); + boundingRect, + renderMode); } colorGlyphsAnalysis->Release(); @@ -884,7 +893,8 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t, b, a, glyphAnalysis, - boundingRect); + boundingRect, + renderMode); } glyphAnalysis->Release(); @@ -902,7 +912,8 @@ void QWindowsFontEngineDirectWrite::renderGlyphRun(QImage *destination, float b, float a, IDWriteGlyphRunAnalysis *glyphAnalysis, - const QRect &boundingRect) + const QRect &boundingRect, + DWRITE_RENDERING_MODE renderMode) { const int width = destination->width(); const int height = destination->height(); @@ -923,12 +934,14 @@ void QWindowsFontEngineDirectWrite::renderGlyphRun(QImage *destination, BYTE *alphaValues = alphaValueArray.data(); memset(alphaValues, 0, size); - HRESULT hr = glyphAnalysis->CreateAlphaTexture(DWRITE_TEXTURE_CLEARTYPE_3x1, + HRESULT hr = glyphAnalysis->CreateAlphaTexture(renderMode == DWRITE_RENDERING_MODE_ALIASED + ? DWRITE_TEXTURE_ALIASED_1x1 + : DWRITE_TEXTURE_CLEARTYPE_3x1, &rect, alphaValues, size); if (SUCCEEDED(hr)) { - if (destination->hasAlphaChannel()) { + if (destination->hasAlphaChannel()) { // Color glyphs for (int y = 0; y < height; ++y) { uint *dest = reinterpret_cast(destination->scanLine(y)); BYTE *src = alphaValues + width * 3 * y; @@ -946,7 +959,16 @@ void QWindowsFontEngineDirectWrite::renderGlyphRun(QImage *destination, qRound(qAlpha(currentRgb) * (1.0 - averageAlpha) + averageAlpha * 255)); } } + } else if (renderMode == DWRITE_RENDERING_MODE_ALIASED) { + for (int y = 0; y < height; ++y) { + uint *dest = reinterpret_cast(destination->scanLine(y)); + BYTE *src = alphaValues + width * y; + for (int x = 0; x < width; ++x) { + int alpha = *(src++); + dest[x] = (alpha << 16) + (alpha << 8) + alpha; + } + } } else { for (int y = 0; y < height; ++y) { uint *dest = reinterpret_cast(destination->scanLine(y)); @@ -1121,7 +1143,7 @@ glyph_metrics_t QWindowsFontEngineDirectWrite::alphaMapBoundingBox(glyph_t glyph if (SUCCEEDED(hr)) { RECT rect; - glyphAnalysis->GetAlphaTextureBounds(DWRITE_TEXTURE_CLEARTYPE_3x1, &rect); + glyphAnalysis->GetAlphaTextureBounds(renderMode == DWRITE_RENDERING_MODE_ALIASED ? DWRITE_TEXTURE_ALIASED_1x1 : DWRITE_TEXTURE_CLEARTYPE_3x1, &rect); glyphAnalysis->Release(); int margin = glyphMargin(format); diff --git a/src/gui/text/windows/qwindowsfontenginedirectwrite_p.h b/src/gui/text/windows/qwindowsfontenginedirectwrite_p.h index df6df1ad172..44e466789c8 100644 --- a/src/gui/text/windows/qwindowsfontenginedirectwrite_p.h +++ b/src/gui/text/windows/qwindowsfontenginedirectwrite_p.h @@ -22,6 +22,7 @@ QT_REQUIRE_CONFIG(directwrite); #include #include +#include struct IDWriteFont; struct IDWriteFontFace; @@ -108,8 +109,16 @@ private: const QTransform &xform, const QColor &color = QColor()); void collectMetrics(); - void renderGlyphRun(QImage *destination, float r, float g, float b, float a, IDWriteGlyphRunAnalysis *glyphAnalysis, const QRect &boundingRect); + void renderGlyphRun(QImage *destination, + float r, + float g, + float b, + float a, + IDWriteGlyphRunAnalysis *glyphAnalysis, + const QRect &boundingRect, + DWRITE_RENDERING_MODE renderMode); static QString filenameFromFontFile(IDWriteFontFile *fontFile); + DWRITE_RENDERING_MODE hintingPreferenceToRenderingMode(const QFontDef &fontDef) const; const QSharedPointer m_fontEngineData;