diff options
author | Tor Arne Vestbø <tor.arne.vestbo@theqtcompany.com> | 2015-08-27 18:27:57 +0200 |
---|---|---|
committer | Tor Arne Vestbø <tor.arne.vestbo@theqtcompany.com> | 2015-09-22 21:19:12 +0000 |
commit | 9c71f55ef9575c0168bf8d0b305ec9591a61999d (patch) | |
tree | 9666eec06cefd62d2bddd850c5ae38a945e71831 /src/gui/text | |
parent | 5f3529be32df3cce81e77c3dbb76cfda7feb320c (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')
-rw-r--r-- | src/gui/text/qfontengine.cpp | 74 |
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) |