DirectWrite: Avoid infinite recursion with broken font data
If a font has an em square size of 0 it is not going to be useful. However, if one was encountered we returned a default value to avoid division by zero. The default implementation called ascent(), which would depend on the em square size again and we would get an infinite recursion for these fonts. To avoid this, we simply return a default value of 16 in the case of a broken font. (The Apple spec gives the range 64 .. 16384 for the em square and the Microsoft spec says 16 .. 16384, so we use the smallest of the two.) Fixes: QTBUG-137277 Pick-to: 6.5 6.8 6.9 Change-Id: I63779e44c10c7021486787d1e1e818f4c6e47835 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
This commit is contained in:
parent
b23da37d71
commit
ab7a80a955
@ -496,6 +496,13 @@ QFixed QFontEngine::leading() const
|
||||
return m_leading;
|
||||
}
|
||||
|
||||
|
||||
QFixed QFontEngine::emSquareSize() const
|
||||
{
|
||||
qCWarning(lcQpaFonts) << "Font engine does not reimplement emSquareSize(). Returning minimum value.";
|
||||
return 16;
|
||||
}
|
||||
|
||||
QFixed QFontEngine::ascent() const
|
||||
{
|
||||
if (!m_heightMetricsQueried)
|
||||
@ -2354,6 +2361,9 @@ glyph_metrics_t QFontEngineMulti::boundingBox(glyph_t glyph)
|
||||
return engine(which)->boundingBox(stripped(glyph));
|
||||
}
|
||||
|
||||
QFixed QFontEngineMulti::emSquareSize() const
|
||||
{ return engine(0)->emSquareSize(); }
|
||||
|
||||
QFixed QFontEngineMulti::ascent() const
|
||||
{ return engine(0)->ascent(); }
|
||||
|
||||
|
@ -163,7 +163,7 @@ public:
|
||||
|| QChar::category(ucs4) == QChar::Other_Control;
|
||||
}
|
||||
|
||||
virtual QFixed emSquareSize() const { return ascent(); }
|
||||
virtual QFixed emSquareSize() const;
|
||||
|
||||
/* returns 0 as glyph index for non existent glyphs */
|
||||
virtual glyph_t glyphIndex(uint ucs4) const = 0;
|
||||
@ -425,6 +425,7 @@ public:
|
||||
virtual glyph_metrics_t boundingBox(glyph_t glyph) override;
|
||||
virtual QFontEngine *cloneWithSize(qreal pixelSize) const override;
|
||||
|
||||
virtual QFixed emSquareSize() const override { return _size; }
|
||||
virtual QFixed ascent() const override;
|
||||
virtual QFixed capHeight() const override;
|
||||
virtual QFixed descent() const override;
|
||||
@ -463,6 +464,7 @@ public:
|
||||
virtual void addOutlineToPath(qreal, qreal, const QGlyphLayout &, QPainterPath *, QTextItem::RenderFlags flags) override;
|
||||
virtual void getGlyphBearings(glyph_t glyph, qreal *leftBearing = nullptr, qreal *rightBearing = nullptr) override;
|
||||
|
||||
virtual QFixed emSquareSize() const override;
|
||||
virtual QFixed ascent() const override;
|
||||
virtual QFixed capHeight() const override;
|
||||
virtual QFixed descent() const override;
|
||||
|
@ -369,6 +369,14 @@ void QWindowsFontEngineDirectWrite::collectMetrics()
|
||||
m_directWriteFontFace->GetMetrics(&metrics);
|
||||
m_unitsPerEm = metrics.designUnitsPerEm;
|
||||
|
||||
// Something is wrong with this font. Set the em square size to the minimum value in
|
||||
// the spec.
|
||||
if (m_unitsPerEm == 0) {
|
||||
qCWarning(lcQpaFonts) << "Font" << fontDef.families << "reports an em square size of 0."
|
||||
<< "Clamping to minimum value.";
|
||||
m_unitsPerEm = 16;
|
||||
}
|
||||
|
||||
m_lineThickness = DESIGN_TO_LOGICAL(metrics.underlineThickness);
|
||||
m_capHeight = DESIGN_TO_LOGICAL(metrics.capHeight);
|
||||
m_xHeight = DESIGN_TO_LOGICAL(metrics.xHeight);
|
||||
@ -497,10 +505,7 @@ bool QWindowsFontEngineDirectWrite::getSfntTableData(uint tag, uchar *buffer, ui
|
||||
|
||||
QFixed QWindowsFontEngineDirectWrite::emSquareSize() const
|
||||
{
|
||||
if (m_unitsPerEm > 0)
|
||||
return m_unitsPerEm;
|
||||
else
|
||||
return QFontEngine::emSquareSize();
|
||||
}
|
||||
|
||||
glyph_t QWindowsFontEngineDirectWrite::glyphIndex(uint ucs4) const
|
||||
|
@ -17,6 +17,7 @@ set_source_files_properties("../../../shared/resources/testfont.ttf"
|
||||
)
|
||||
set(testdata_resource_files
|
||||
"../../../shared/resources/testfont.ttf"
|
||||
"testfont_zeroem.ttf"
|
||||
"testfont_bold_italic.ttf"
|
||||
"testfont_os2_v1.ttf"
|
||||
)
|
||||
|
BIN
tests/auto/gui/text/qrawfont/testfont_zeroem.ttf
Normal file
BIN
tests/auto/gui/text/qrawfont/testfont_zeroem.ttf
Normal file
Binary file not shown.
@ -71,10 +71,13 @@ private slots:
|
||||
void qtbug65923_partal_clone_data();
|
||||
void qtbug65923_partal_clone();
|
||||
|
||||
void zeroEmSquare();
|
||||
|
||||
private:
|
||||
QString testFont;
|
||||
QString testFontBoldItalic;
|
||||
QString testFontOs2V1;
|
||||
QString testFontNoEmSquare;
|
||||
#endif // QT_NO_RAWFONT
|
||||
};
|
||||
|
||||
@ -93,7 +96,9 @@ void tst_QRawFont::initTestCase()
|
||||
testFont = QFINDTESTDATA("testfont.ttf");
|
||||
testFontBoldItalic = QFINDTESTDATA("testfont_bold_italic.ttf");
|
||||
testFontOs2V1 = QFINDTESTDATA("testfont_os2_v1.ttf");
|
||||
if (testFont.isEmpty() || testFontBoldItalic.isEmpty())
|
||||
testFontNoEmSquare = QFINDTESTDATA("testfont_zeroem.ttf");
|
||||
|
||||
if (testFont.isEmpty() || testFontBoldItalic.isEmpty() || testFontNoEmSquare.isEmpty())
|
||||
QFAIL("qrawfont unittest font files not found!");
|
||||
|
||||
if (QFontDatabase::families().size() == 0)
|
||||
@ -1079,6 +1084,12 @@ void tst_QRawFont::qtbug65923_partal_clone()
|
||||
QVERIFY(!outerFont.boundingRect(42).isEmpty());
|
||||
}
|
||||
|
||||
void tst_QRawFont::zeroEmSquare()
|
||||
{
|
||||
QRawFont rawFont(testFontNoEmSquare, 12);
|
||||
QVERIFY(!rawFont.isValid() || rawFont.unitsPerEm() > 0);
|
||||
}
|
||||
|
||||
#endif // QT_NO_RAWFONT
|
||||
|
||||
QTEST_MAIN(tst_QRawFont)
|
||||
|
Loading…
x
Reference in New Issue
Block a user