summaryrefslogtreecommitdiffstats
path: root/src/gui/text/qfontengine.cpp
diff options
context:
space:
mode:
authorTor Arne Vestbø <tor.arne.vestbo@theqtcompany.com>2015-08-27 18:27:57 +0200
committerTor Arne Vestbø <tor.arne.vestbo@theqtcompany.com>2015-09-22 21:19:12 +0000
commit9c71f55ef9575c0168bf8d0b305ec9591a61999d (patch)
tree9666eec06cefd62d2bddd850c5ae38a945e71831 /src/gui/text/qfontengine.cpp
parent5f3529be32df3cce81e77c3dbb76cfda7feb320c (diff)
QFontEngine: Read minimum left and right glyph bearings from 'hhea' table
This table has values precomputed based on every single glyph in the font, not just the subset we use as a fallback, which should improve both performance and correctness. The fallback codepath of computing the minimum values based on a subset of the characters in the font is left in, as we still need that for bitmap fonts, and some font tables that have invalid values. Change-Id: I71aac1e09c9f9de80446b023ba15a9e2afe7d226 Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@theqtcompany.com>
Diffstat (limited to 'src/gui/text/qfontengine.cpp')
-rw-r--r--src/gui/text/qfontengine.cpp74
1 files changed, 55 insertions, 19 deletions
diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp
index 102946b545..bef4dc5547 100644
--- a/src/gui/text/qfontengine.cpp
+++ b/src/gui/text/qfontengine.cpp
@@ -581,34 +581,70 @@ qreal QFontEngine::minLeftBearing() const
return m_minLeftBearing;
}
+#define q16Dot16ToFloat(i) ((i) / 65536.0)
+
+#define kMinLeftSideBearingOffset 12
+#define kMinRightSideBearingOffset 14
+
qreal QFontEngine::minRightBearing() const
{
if (m_minRightBearing == kBearingNotInitialized) {
- // To balance performance and correctness we only look at a subset of the
- // possible glyphs in the font, based on which characters are more likely
- // to have a left or right bearing.
- static const ushort characterSubset[] = {
- '(', 'C', 'F', 'K', 'V', 'X', 'Y', ']', '_', 'f', 'r', '|',
- 127, 205, 645, 884, 922, 1070, 12386
- };
+ // Try the 'hhea' font table first, which covers the entire font
+ QByteArray hheaTable = getSfntTable(MAKE_TAG('h', 'h', 'e', 'a'));
+ if (hheaTable.size() >= int(kMinRightSideBearingOffset + sizeof(qint16))) {
+ const uchar *tableData = reinterpret_cast<const uchar *>(hheaTable.constData());
+ Q_ASSERT(q16Dot16ToFloat(qFromBigEndian<quint32>(tableData)) == 1.0);
+
+ qint16 minLeftSideBearing = qFromBigEndian<qint16>(tableData + kMinLeftSideBearingOffset);
+ qint16 minRightSideBearing = qFromBigEndian<qint16>(tableData + kMinRightSideBearingOffset);
+
+ // The table data is expressed as FUnits, meaning we have to take the number
+ // of units per em into account. Since pixelSize already has taken DPI into
+ // account we can use that directly instead of the point size.
+ int unitsPerEm = emSquareSize().toInt();
+ qreal funitToPixelFactor = fontDef.pixelSize / unitsPerEm;
+
+ // Some fonts on OS X (such as Gurmukhi Sangam MN, Khmer MN, Lao Sangam MN, etc.), have
+ // invalid values for their NBSPACE left bearing, causing the 'hhea' minimum bearings to
+ // be way off. We detect this by assuming that the minimum bearsings are within a certain
+ // range of the em square size.
+ static const int largestValidBearing = 4 * unitsPerEm;
+
+ if (qAbs(minLeftSideBearing) < largestValidBearing)
+ m_minLeftBearing = minLeftSideBearing * funitToPixelFactor;
+ if (qAbs(minRightSideBearing) < largestValidBearing)
+ m_minRightBearing = minRightSideBearing * funitToPixelFactor;
+ }
- // The font may have minimum bearings larger than 0, so we have to start at the max
- m_minLeftBearing = m_minRightBearing = std::numeric_limits<qreal>::max();
+ // Fallback in case of missing 'hhea' table (bitmap fonts e.g.) or broken 'hhea' values
+ if (m_minLeftBearing == kBearingNotInitialized || m_minRightBearing == kBearingNotInitialized) {
- for (uint i = 0; i < (sizeof(characterSubset) / sizeof(ushort)); ++i) {
- const glyph_t glyph = glyphIndex(characterSubset[i]);
- if (!glyph)
- continue;
+ // To balance performance and correctness we only look at a subset of the
+ // possible glyphs in the font, based on which characters are more likely
+ // to have a left or right bearing.
+ static const ushort characterSubset[] = {
+ '(', 'C', 'F', 'K', 'V', 'X', 'Y', ']', '_', 'f', 'r', '|',
+ 127, 205, 645, 884, 922, 1070, 12386
+ };
- glyph_metrics_t glyphMetrics = const_cast<QFontEngine *>(this)->boundingBox(glyph);
+ // The font may have minimum bearings larger than 0, so we have to start at the max
+ m_minLeftBearing = m_minRightBearing = std::numeric_limits<qreal>::max();
- // Glyphs with no contours shouldn't contribute to bearings
- if (!glyphMetrics.width || !glyphMetrics.height)
- continue;
+ for (uint i = 0; i < (sizeof(characterSubset) / sizeof(ushort)); ++i) {
+ const glyph_t glyph = glyphIndex(characterSubset[i]);
+ if (!glyph)
+ continue;
+
+ glyph_metrics_t glyphMetrics = const_cast<QFontEngine *>(this)->boundingBox(glyph);
- m_minLeftBearing = qMin(m_minLeftBearing, glyphMetrics.leftBearing().toReal());
- m_minRightBearing = qMin(m_minRightBearing, glyphMetrics.rightBearing().toReal());
+ // Glyphs with no contours shouldn't contribute to bearings
+ if (!glyphMetrics.width || !glyphMetrics.height)
+ continue;
+
+ m_minLeftBearing = qMin(m_minLeftBearing, glyphMetrics.leftBearing().toReal());
+ m_minRightBearing = qMin(m_minRightBearing, glyphMetrics.rightBearing().toReal());
+ }
}
if (m_minLeftBearing == kBearingNotInitialized || m_minRightBearing == kBearingNotInitialized)