Windows: Fix missing glyphs for very large font

When the font size gets to a certain size (at some point
after 1200 pixels), DirectWrite will just return an empty
rect as the bound for it and does not want to render it. At
this point, you might want to consider other ways of
rendering the text, but since the same did not happen
e.g. with the Freetype backend, it was an unfortunate
platform difference.

As a fail safe, we detect when this occurs and fall back to
the QFontEngine base class approach of drawing the glyph as a
QPainterPath instead.

[ChangeLog][Windows] Fixed an issue where glyphs might be missing
for very large fonts.

Fixes: QTBUG-126671
Change-Id: I13cc1e5d71fae114e2a7933a7c5f7b9980237390
Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
(cherry picked from commit a5ddcbb76b674470f0c3d1d5e0bb7697a2828d25)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Eskil Abrahamsen Blomfeldt 2024-11-01 09:37:52 +01:00 committed by Qt Cherry-pick Bot
parent 9d5e3ffc33
commit 98d03964ac
3 changed files with 33 additions and 14 deletions

View File

@ -868,7 +868,7 @@ QFontEngine::Glyph *QFontEngine::glyphData(glyph_t,
return nullptr;
}
QImage QFontEngine::alphaMapForGlyph(glyph_t glyph)
QImage QFontEngine::renderedPathForGlyph(glyph_t glyph, const QColor &color)
{
glyph_metrics_t gm = boundingBox(glyph);
int glyph_x = qFloor(gm.x.toReal());
@ -889,10 +889,16 @@ QImage QFontEngine::alphaMapForGlyph(glyph_t glyph)
p.setRenderHint(QPainter::Antialiasing);
addGlyphsToPath(&glyph, &pt, 1, &path, { });
p.setPen(Qt::NoPen);
p.setBrush(Qt::black);
p.setBrush(color);
p.drawPath(path);
p.end();
return im;
}
QImage QFontEngine::alphaMapForGlyph(glyph_t glyph)
{
QImage im = renderedPathForGlyph(glyph, Qt::black);
QImage alphaMap(im.width(), im.height(), QImage::Format_Alpha8);
for (int y=0; y<im.height(); ++y) {

View File

@ -186,6 +186,7 @@ public:
virtual QImage alphaMapForGlyph(glyph_t, const QFixedPoint &subPixelPosition, const QTransform &t);
virtual QImage alphaRGBMapForGlyph(glyph_t, const QFixedPoint &subPixelPosition, const QTransform &t);
virtual QImage bitmapForGlyph(glyph_t, const QFixedPoint &subPixelPosition, const QTransform &t, const QColor &color = QColor());
QImage renderedPathForGlyph(glyph_t glyph, const QColor &color);
virtual Glyph *glyphData(glyph_t glyph, const QFixedPoint &subPixelPosition, GlyphFormat neededFormat, const QTransform &t);
virtual bool hasInternalCaching() const { return false; }

View File

@ -660,19 +660,23 @@ QImage QWindowsFontEngineDirectWrite::alphaMapForGlyph(glyph_t glyph,
{
QImage im = imageForGlyph(glyph, subPixelPosition, glyphMargin(Format_A8), t);
QImage alphaMap(im.width(), im.height(), QImage::Format_Alpha8);
if (!im.isNull()) {
QImage alphaMap(im.width(), im.height(), QImage::Format_Alpha8);
for (int y=0; y<im.height(); ++y) {
const uint *src = reinterpret_cast<const uint *>(im.constScanLine(y));
uchar *dst = alphaMap.scanLine(y);
for (int x=0; x<im.width(); ++x) {
*dst = 255 - (m_fontEngineData->pow_gamma[qGray(0xffffffff - *src)] * 255. / 2047.);
++dst;
++src;
for (int y=0; y<im.height(); ++y) {
const uint *src = reinterpret_cast<const uint *>(im.constScanLine(y));
uchar *dst = alphaMap.scanLine(y);
for (int x=0; x<im.width(); ++x) {
*dst = 255 - (m_fontEngineData->pow_gamma[qGray(0xffffffff - *src)] * 255. / 2047.);
++dst;
++src;
}
}
}
return alphaMap;
return alphaMap;
} else {
return QFontEngine::alphaMapForGlyph(glyph, t);
}
}
QImage QWindowsFontEngineDirectWrite::alphaMapForGlyph(glyph_t glyph,
@ -794,8 +798,10 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t,
: DWRITE_TEXTURE_CLEARTYPE_3x1,
&rect);
if (rect.top == rect.bottom || rect.left == rect.right)
if (rect.top == rect.bottom || rect.left == rect.right) {
qCDebug(lcQpaFonts) << __FUNCTION__ << "Cannot get alpha texture bounds. Falling back to slower rendering path.";
return QImage();
}
QRect boundingRect = QRect(QPoint(rect.left - margin,
rect.top - margin),
@ -1009,6 +1015,12 @@ QImage QWindowsFontEngineDirectWrite::alphaRGBMapForGlyph(glyph_t t,
glyphMargin(QFontEngine::Format_A32),
xform);
if (mask.isNull()) {
mask = QFontEngine::renderedPathForGlyph(t, Qt::white);
if (!xform.isIdentity())
mask = mask.transformed(xform);
}
return mask.depth() == 32
? mask
: mask.convertToFormat(QImage::Format_RGB32);
@ -1157,7 +1169,7 @@ glyph_metrics_t QWindowsFontEngineDirectWrite::alphaMapBoundingBox(glyph_t glyph
int margin = glyphMargin(format);
if (rect.left == rect.right || rect.top == rect.bottom)
return glyph_metrics_t();
return bbox;
return glyph_metrics_t(rect.left,
rect.top,