Account for rounding error when rounding height metrics
In Qt 5 we would ask FreeType for height metrics. FreeType always returns rounded metrics, so for e.g. DejaVu Sans at pixel size 21 it would return ascender=20 and descender=5, which is actually incorrect, since the actual ascender is 19.49. The descender is rounded correctly. This is likely due to the use of fixed point math internally. In Qt, we would account for this error by setting the leading to -1, so that the rounded height still becomes 24. (This is also technically incorrect, since the line gap of the font is 0.) In Qt 6, we got the same fixed point rounding error (so ascender becomes 20 instead of 19), but we didn't account for the error, so we would end up with lines that were 25 high instead of 24. To reduce the chance of getting this error, we do the full metrics calculation in floating point numbers instead. For the case in question, we will then get arounded ascender of 19 and descender of 5, giving us a height of 24. Fixed point numbers are still used for storing the results, so while it's less likely, we could still end up with the same error. Therefore, we also apply the same trick as in Qt 5 when this occurs: Adapting the leading of the font to account for the rounding error if it occurs. [ChangeLog][QtGui][Text] Fixed an issue where the line distance for hinted fonts would be off by one for specific sizes of some fonts. Fixes: QTBUG-134602 Pick-to: 6.8 Change-Id: I09f1806199b7b2b02a932bb65fe4da055bd60f51 Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io> (cherry picked from commit 3728032e03b3bf95daa7115c734173a0070d85c8) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
parent
6dc3e49b36
commit
a9418f0ab5
@ -400,15 +400,14 @@ bool QFontEngine::processHheaTable() const
|
||||
if (ascent == 0 && descent == 0)
|
||||
return false;
|
||||
|
||||
QFixed unitsPerEm = emSquareSize();
|
||||
const qreal unitsPerEm = emSquareSize().toReal();
|
||||
// Bail out if values are too large for QFixed
|
||||
const auto limitForQFixed = std::numeric_limits<int>::max() / (fontDef.pixelSize * 64);
|
||||
if (ascent > limitForQFixed || descent > limitForQFixed || leading > limitForQFixed)
|
||||
return false;
|
||||
m_ascent = QFixed::fromReal(ascent * fontDef.pixelSize) / unitsPerEm;
|
||||
m_descent = -QFixed::fromReal(descent * fontDef.pixelSize) / unitsPerEm;
|
||||
|
||||
m_leading = QFixed::fromReal(leading * fontDef.pixelSize) / unitsPerEm;
|
||||
m_ascent = QFixed::fromReal(ascent * fontDef.pixelSize / unitsPerEm);
|
||||
m_descent = -QFixed::fromReal(descent * fontDef.pixelSize / unitsPerEm);
|
||||
m_leading = QFixed::fromReal(leading * fontDef.pixelSize / unitsPerEm);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -430,9 +429,10 @@ void QFontEngine::initializeHeightMetrics() const
|
||||
processOS2Table();
|
||||
|
||||
if (!supportsSubPixelPositions()) {
|
||||
const QFixed actualHeight = m_ascent + m_descent + m_leading;
|
||||
m_ascent = m_ascent.round();
|
||||
m_descent = m_descent.round();
|
||||
m_leading = m_leading.round();
|
||||
m_leading = actualHeight.round() - m_ascent - m_descent;
|
||||
}
|
||||
}
|
||||
|
||||
@ -457,7 +457,7 @@ bool QFontEngine::processOS2Table() const
|
||||
quint16 winDescent = qFromBigEndian<quint16>(ptr + 76);
|
||||
|
||||
enum { USE_TYPO_METRICS = 0x80 };
|
||||
QFixed unitsPerEm = emSquareSize();
|
||||
const qreal unitsPerEm = emSquareSize().toReal();
|
||||
if (preferTypoLineMetrics() || fsSelection & USE_TYPO_METRICS) {
|
||||
// Some fonts may have invalid OS/2 data. We detect this and bail out.
|
||||
if (typoAscent == 0 && typoDescent == 0)
|
||||
@ -467,9 +467,9 @@ bool QFontEngine::processOS2Table() const
|
||||
if (typoAscent > limitForQFixed || typoDescent > limitForQFixed
|
||||
|| typoLineGap > limitForQFixed)
|
||||
return false;
|
||||
m_ascent = QFixed::fromReal(typoAscent * fontDef.pixelSize) / unitsPerEm;
|
||||
m_descent = -QFixed::fromReal(typoDescent * fontDef.pixelSize) / unitsPerEm;
|
||||
m_leading = QFixed::fromReal(typoLineGap * fontDef.pixelSize) / unitsPerEm;
|
||||
m_ascent = QFixed::fromReal(typoAscent * fontDef.pixelSize / unitsPerEm);
|
||||
m_descent = -QFixed::fromReal(typoDescent * fontDef.pixelSize / unitsPerEm);
|
||||
m_leading = QFixed::fromReal(typoLineGap * fontDef.pixelSize / unitsPerEm);
|
||||
} else {
|
||||
// Some fonts may have invalid OS/2 data. We detect this and bail out.
|
||||
if (winAscent == 0 && winDescent == 0)
|
||||
@ -477,8 +477,8 @@ bool QFontEngine::processOS2Table() const
|
||||
const auto limitForQFixed = std::numeric_limits<int>::max() / (fontDef.pixelSize * 64);
|
||||
if (winAscent > limitForQFixed || winDescent > limitForQFixed)
|
||||
return false;
|
||||
m_ascent = QFixed::fromReal(winAscent * fontDef.pixelSize) / unitsPerEm;
|
||||
m_descent = QFixed::fromReal(winDescent * fontDef.pixelSize) / unitsPerEm;
|
||||
m_ascent = QFixed::fromReal(winAscent * fontDef.pixelSize / unitsPerEm);
|
||||
m_descent = QFixed::fromReal(winDescent * fontDef.pixelSize / unitsPerEm);
|
||||
m_leading = QFixed{};
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user