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 <allan.jensen@qt.io>
(cherry picked from commit 421e7621faa50bf9007076d6be4e0da9514edc59)
This commit is contained in:
Eskil Abrahamsen Blomfeldt 2024-04-08 11:56:56 +02:00
parent a225fb5d89
commit b62b6094dd
2 changed files with 42 additions and 11 deletions

View File

@ -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<uint *>(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<uint *>(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<uint *>(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);

View File

@ -22,6 +22,7 @@ QT_REQUIRE_CONFIG(directwrite);
#include <QtGui/private/qfontengine_p.h>
#include <QtCore/QSharedPointer>
#include <dwrite.h>
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<QWindowsFontEngineData> m_fontEngineData;