summaryrefslogtreecommitdiffstats
path: root/src/gui/text/qfontengine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/text/qfontengine.cpp')
-rw-r--r--src/gui/text/qfontengine.cpp112
1 files changed, 99 insertions, 13 deletions
diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp
index 2087bad9f6..f267b2d147 100644
--- a/src/gui/text/qfontengine.cpp
+++ b/src/gui/text/qfontengine.cpp
@@ -54,6 +54,7 @@
#include <private/qharfbuzz_p.h>
#include <algorithm>
+#include <limits.h>
QT_BEGIN_NAMESPACE
@@ -235,10 +236,14 @@ Q_AUTOTEST_EXPORT QList<QFontEngine *> QFontEngine_stopCollectingEngines()
// QFontEngine
+#define kBearingNotInitialized std::numeric_limits<qreal>::max()
+
QFontEngine::QFontEngine(Type type)
: m_type(type), ref(0),
font_(0), font_destroy_func(0),
- face_(0), face_destroy_func(0)
+ face_(0), face_destroy_func(0),
+ m_minLeftBearing(kBearingNotInitialized),
+ m_minRightBearing(kBearingNotInitialized)
{
faceData.user_data = this;
faceData.get_font_table = qt_get_font_table_default;
@@ -365,17 +370,15 @@ bool QFontEngine::supportsScript(QChar::Script script) const
return true;
}
-#ifdef Q_OS_MAC
- {
+#ifdef QT_ENABLE_HARFBUZZ_NG
+ if (qt_useHarfbuzzNG()) {
+#if defined(Q_OS_DARWIN)
// in AAT fonts, 'gsub' table is effectively replaced by 'mort'/'morx' table
uint len;
if (getSfntTableData(MAKE_TAG('m','o','r','t'), 0, &len) || getSfntTableData(MAKE_TAG('m','o','r','x'), 0, &len))
return true;
- }
#endif
-#ifdef QT_ENABLE_HARFBUZZ_NG
- if (qt_useHarfbuzzNG()) {
bool ret = false;
if (hb_face_t *face = hb_qt_face_get_for_engine(const_cast<QFontEngine *>(this))) {
hb_tag_t script_tag_1, script_tag_2;
@@ -562,11 +565,91 @@ void QFontEngine::getGlyphPositions(const QGlyphLayout &glyphs, const QTransform
void QFontEngine::getGlyphBearings(glyph_t glyph, qreal *leftBearing, qreal *rightBearing)
{
glyph_metrics_t gi = boundingBox(glyph);
- bool isValid = gi.isValid();
if (leftBearing != 0)
- *leftBearing = isValid ? gi.x.toReal() : 0.0;
+ *leftBearing = gi.leftBearing().toReal();
if (rightBearing != 0)
- *rightBearing = isValid ? (gi.xoff - gi.x - gi.width).toReal() : 0.0;
+ *rightBearing = gi.rightBearing().toReal();
+}
+
+qreal QFontEngine::minLeftBearing() const
+{
+ if (m_minLeftBearing == kBearingNotInitialized)
+ minRightBearing(); // Initializes both (see below)
+
+ return m_minLeftBearing;
+}
+
+#define q16Dot16ToFloat(i) ((i) / 65536.0)
+
+#define kMinLeftSideBearingOffset 12
+#define kMinRightSideBearingOffset 14
+
+qreal QFontEngine::minRightBearing() const
+{
+ if (m_minRightBearing == kBearingNotInitialized) {
+
+ // 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;
+ }
+
+ // Fallback in case of missing 'hhea' table (bitmap fonts e.g.) or broken 'hhea' values
+ if (m_minLeftBearing == kBearingNotInitialized || 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
+ };
+
+ // 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();
+
+ 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);
+
+ // 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)
+ qWarning() << "Failed to compute left/right minimum bearings for" << fontDef.family;
+ }
+
+ return m_minRightBearing;
}
glyph_metrics_t QFontEngine::tightBoundingBox(const QGlyphLayout &glyphs)
@@ -875,7 +958,8 @@ QImage QFontEngine::alphaMapForGlyph(glyph_t glyph)
pt.x = -glyph_x;
pt.y = -glyph_y; // the baseline
QPainterPath path;
- QImage im(glyph_width + 4, glyph_height, QImage::Format_ARGB32_Premultiplied);
+ path.setFillRule(Qt::WindingFill);
+ QImage im(glyph_width, glyph_height, QImage::Format_ARGB32_Premultiplied);
im.fill(Qt::transparent);
QPainter p(&im);
p.setRenderHint(QPainter::Antialiasing);
@@ -1469,8 +1553,7 @@ QFixed QFontEngine::lastRightBearing(const QGlyphLayout &glyphs, bool round)
glyph_t glyph = glyphs.glyphs[glyphs.numGlyphs - 1];
glyph_metrics_t gi = boundingBox(glyph);
if (gi.isValid())
- return round ? QFixed(qRound(gi.xoff - gi.x - gi.width))
- : QFixed(gi.xoff - gi.x - gi.width);
+ return round ? qRound(gi.rightBearing()) : gi.rightBearing();
}
return 0;
}
@@ -1752,7 +1835,10 @@ QFontEngine *QFontEngineMulti::loadEngine(int at)
request.family = fallbackFamilyAt(at - 1);
if (QFontEngine *engine = QFontDatabase::findFont(request, m_script)) {
- engine->fontDef = request;
+ if (request.weight > QFont::Normal)
+ engine->fontDef.weight = request.weight;
+ if (request.style > QFont::StyleNormal)
+ engine->fontDef.style = request.style;
return engine;
}