From ac1e87d9f373ad649d989f254b37d2f29ddf25fe Mon Sep 17 00:00:00 2001 From: Konstantin Tokarev Date: Wed, 3 Aug 2016 15:45:02 +0300 Subject: Added capHeight() to QRawFont and QFontMetrics(F) Cap height is an important metric of font, in particular it is required to make decent implementation of "initial-letter" CSS property in QtWebKit. Note that some fonts lack cap height metadata, so we need to fall back to measuring H letter height. Change-Id: Icf69d92159d070889085e20d31f2e397d796d940 Reviewed-by: Eskil Abrahamsen Blomfeldt --- src/gui/text/qfontengine.cpp | 15 ++++++ src/gui/text/qfontengine_ft.cpp | 13 +++++ src/gui/text/qfontengine_ft_p.h | 1 + src/gui/text/qfontengine_p.h | 4 ++ src/gui/text/qfontengine_qpf2.cpp | 5 ++ src/gui/text/qfontengine_qpf2_p.h | 1 + src/gui/text/qfontmetrics.cpp | 36 ++++++++++++++ src/gui/text/qfontmetrics.h | 2 + src/gui/text/qrawfont.cpp | 17 +++++++ src/gui/text/qrawfont.h | 1 + .../fontdatabases/mac/qfontengine_coretext.mm | 13 +++++ .../fontdatabases/mac/qfontengine_coretext_p.h | 1 + .../platforms/windows/qwindowsfontengine.cpp | 57 ++++++++++++++++++++++ src/plugins/platforms/windows/qwindowsfontengine.h | 1 + .../windows/qwindowsfontenginedirectwrite.cpp | 12 +++++ .../windows/qwindowsfontenginedirectwrite.h | 2 + 16 files changed, 181 insertions(+) (limited to 'src') diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp index adc8f634dc..dbd47151bd 100644 --- a/src/gui/text/qfontengine.cpp +++ b/src/gui/text/qfontengine.cpp @@ -418,6 +418,13 @@ glyph_metrics_t QFontEngine::boundingBox(glyph_t glyph, const QTransform &matrix return metrics; } +QFixed QFontEngine::calculatedCapHeight() const +{ + const glyph_t glyph = glyphIndex('H'); + glyph_metrics_t bb = const_cast(this)->boundingBox(glyph); + return bb.height; +} + QFixed QFontEngine::xHeight() const { const glyph_t glyph = glyphIndex('x'); @@ -1703,6 +1710,11 @@ QFixed QFontEngineBox::ascent() const return _size; } +QFixed QFontEngineBox::capHeight() const +{ + return _size; +} + QFixed QFontEngineBox::descent() const { return 0; @@ -2163,6 +2175,9 @@ glyph_metrics_t QFontEngineMulti::boundingBox(glyph_t glyph) QFixed QFontEngineMulti::ascent() const { return engine(0)->ascent(); } +QFixed QFontEngineMulti::capHeight() const +{ return engine(0)->capHeight(); } + QFixed QFontEngineMulti::descent() const { return engine(0)->descent(); } diff --git a/src/gui/text/qfontengine_ft.cpp b/src/gui/text/qfontengine_ft.cpp index 51b1418bc3..b79fa6e9db 100644 --- a/src/gui/text/qfontengine_ft.cpp +++ b/src/gui/text/qfontengine_ft.cpp @@ -414,6 +414,7 @@ QFontEngine::Properties QFreetypeFace::properties() const p.italicAngle = 0; p.capHeight = p.ascent; p.lineWidth = face->underline_thickness; + return p; } @@ -1299,6 +1300,18 @@ QFixed QFontEngineFT::ascent() const return v; } +QFixed QFontEngineFT::capHeight() const +{ + TT_OS2 *os2 = (TT_OS2 *)FT_Get_Sfnt_Table(freetype->face, ft_sfnt_os2); + if (os2 && os2->version >= 2) { + lockFace(); + QFixed answer = QFixed::fromFixed(FT_MulFix(os2->sCapHeight, freetype->face->size->metrics.y_scale)); + unlockFace(); + return answer; + } + return calculatedCapHeight(); +} + QFixed QFontEngineFT::descent() const { QFixed v = QFixed::fromFixed(-metrics.descender); diff --git a/src/gui/text/qfontengine_ft_p.h b/src/gui/text/qfontengine_ft_p.h index 3cdf0cda47..5ca3721c71 100644 --- a/src/gui/text/qfontengine_ft_p.h +++ b/src/gui/text/qfontengine_ft_p.h @@ -209,6 +209,7 @@ private: int synthesized() const Q_DECL_OVERRIDE; QFixed ascent() const Q_DECL_OVERRIDE; + QFixed capHeight() const Q_DECL_OVERRIDE; QFixed descent() const Q_DECL_OVERRIDE; QFixed leading() const Q_DECL_OVERRIDE; QFixed xHeight() const Q_DECL_OVERRIDE; diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h index f3eeddab41..69331cb0bb 100644 --- a/src/gui/text/qfontengine_p.h +++ b/src/gui/text/qfontengine_p.h @@ -211,6 +211,7 @@ public: glyph_metrics_t tightBoundingBox(const QGlyphLayout &glyphs); virtual QFixed ascent() const = 0; + virtual QFixed capHeight() const = 0; virtual QFixed descent() const = 0; virtual QFixed leading() const = 0; virtual QFixed xHeight() const; @@ -348,6 +349,7 @@ protected: QFixed lastRightBearing(const QGlyphLayout &glyphs, bool round = false); inline void setUserData(const QVariant &userData) { m_userData = userData; } + QFixed calculatedCapHeight() const; private: struct GlyphCacheEntry { @@ -414,6 +416,7 @@ public: virtual QFontEngine *cloneWithSize(qreal pixelSize) const Q_DECL_OVERRIDE; virtual QFixed ascent() const Q_DECL_OVERRIDE; + virtual QFixed capHeight() const Q_DECL_OVERRIDE; virtual QFixed descent() const Q_DECL_OVERRIDE; virtual QFixed leading() const Q_DECL_OVERRIDE; virtual qreal maxCharWidth() const Q_DECL_OVERRIDE; @@ -451,6 +454,7 @@ public: virtual void getGlyphBearings(glyph_t glyph, qreal *leftBearing = 0, qreal *rightBearing = 0) Q_DECL_OVERRIDE; virtual QFixed ascent() const Q_DECL_OVERRIDE; + virtual QFixed capHeight() const Q_DECL_OVERRIDE; virtual QFixed descent() const Q_DECL_OVERRIDE; virtual QFixed leading() const Q_DECL_OVERRIDE; virtual QFixed xHeight() const Q_DECL_OVERRIDE; diff --git a/src/gui/text/qfontengine_qpf2.cpp b/src/gui/text/qfontengine_qpf2.cpp index 2e4af09550..110d512d39 100644 --- a/src/gui/text/qfontengine_qpf2.cpp +++ b/src/gui/text/qfontengine_qpf2.cpp @@ -459,6 +459,11 @@ QFixed QFontEngineQPF2::ascent() const return QFixed::fromReal(extractHeaderField(fontData, Tag_Ascent).value()); } +QFixed QFontEngineQPF2::capHeight() const +{ + return calculatedCapHeight(); +} + QFixed QFontEngineQPF2::descent() const { return QFixed::fromReal(extractHeaderField(fontData, Tag_Descent).value()); diff --git a/src/gui/text/qfontengine_qpf2_p.h b/src/gui/text/qfontengine_qpf2_p.h index 50aac245c1..e5c38ffbaf 100644 --- a/src/gui/text/qfontengine_qpf2_p.h +++ b/src/gui/text/qfontengine_qpf2_p.h @@ -172,6 +172,7 @@ public: glyph_metrics_t boundingBox(glyph_t glyph) Q_DECL_OVERRIDE; QFixed ascent() const Q_DECL_OVERRIDE; + QFixed capHeight() const Q_DECL_OVERRIDE; QFixed descent() const Q_DECL_OVERRIDE; QFixed leading() const Q_DECL_OVERRIDE; qreal maxCharWidth() const Q_DECL_OVERRIDE; diff --git a/src/gui/text/qfontmetrics.cpp b/src/gui/text/qfontmetrics.cpp index 2189923b25..aca59d0288 100644 --- a/src/gui/text/qfontmetrics.cpp +++ b/src/gui/text/qfontmetrics.cpp @@ -274,6 +274,24 @@ int QFontMetrics::ascent() const return qRound(engine->ascent()); } +/*! + Returns the cap height of the font. + + \since 5.8 + + The cap height of a font is the height of a capital letter above + the baseline. It specifically is the height of capital letters + that are flat - such as H or I - as opposed to round letters such + as O, or pointed letters like A, both of which may display overshoot. + + \sa ascent() +*/ +int QFontMetrics::capHeight() const +{ + QFontEngine *engine = d->engineForScript(QChar::Script_Common); + Q_ASSERT(engine != 0); + return qRound(engine->capHeight()); +} /*! Returns the descent of the font. @@ -1138,6 +1156,24 @@ qreal QFontMetricsF::ascent() const return engine->ascent().toReal(); } +/*! + Returns the cap height of the font. + + \since 5.8 + + The cap height of a font is the height of a capital letter above + the baseline. It specifically is the height of capital letters + that are flat - such as H or I - as opposed to round letters such + as O, or pointed letters like A, both of which may display overshoot. + + \sa ascent() +*/ +qreal QFontMetricsF::capHeight() const +{ + QFontEngine *engine = d->engineForScript(QChar::Script_Common); + Q_ASSERT(engine != 0); + return engine->capHeight().toReal(); +} /*! Returns the descent of the font. diff --git a/src/gui/text/qfontmetrics.h b/src/gui/text/qfontmetrics.h index 22e51f29f7..3eac309092 100644 --- a/src/gui/text/qfontmetrics.h +++ b/src/gui/text/qfontmetrics.h @@ -73,6 +73,7 @@ public: { qSwap(d, other.d); } int ascent() const; + int capHeight() const; int descent() const; int height() const; int leading() const; @@ -146,6 +147,7 @@ public: void swap(QFontMetricsF &other) { qSwap(d, other.d); } qreal ascent() const; + qreal capHeight() const; qreal descent() const; qreal height() const; qreal leading() const; diff --git a/src/gui/text/qrawfont.cpp b/src/gui/text/qrawfont.cpp index 19ac4f1dbc..1fbe0ce9d1 100644 --- a/src/gui/text/qrawfont.cpp +++ b/src/gui/text/qrawfont.cpp @@ -324,6 +324,23 @@ qreal QRawFont::ascent() const return d->isValid() ? d->fontEngine->ascent().toReal() : 0.0; } +/*! + Returns the cap height of this QRawFont in pixel units. + + \since 5.8 + + The cap height of a font is the height of a capital letter above + the baseline. It specifically is the height of capital letters + that are flat - such as H or I - as opposed to round letters such + as O, or pointed letters like A, both of which may display overshoot. + + \sa QFontMetricsF::capHeight() +*/ +qreal QRawFont::capHeight() const +{ + return d->isValid() ? d->fontEngine->capHeight().toReal() : 0.0; +} + /*! Returns the descent of this QRawFont in pixel units. diff --git a/src/gui/text/qrawfont.h b/src/gui/text/qrawfont.h index 5791c6af16..0252e62370 100644 --- a/src/gui/text/qrawfont.h +++ b/src/gui/text/qrawfont.h @@ -118,6 +118,7 @@ public: QFont::HintingPreference hintingPreference() const; qreal ascent() const; + qreal capHeight() const; qreal descent() const; qreal leading() const; qreal xHeight() const; diff --git a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm index 339212db25..646212124b 100644 --- a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm +++ b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm @@ -378,6 +378,19 @@ QFixed QCoreTextFontEngine::ascent() const ? QFixed::fromReal(CTFontGetAscent(ctfont)).round() : QFixed::fromReal(CTFontGetAscent(ctfont)); } + +QFixed QCoreTextFontEngine::capHeight() const +{ + QFixed c = QFixed::fromReal(CTFontGetCapHeight(ctfont)); + if (c <= 0) + return calculatedCapHeight(); + + if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) + c = c.round(); + + return c; +} + QFixed QCoreTextFontEngine::descent() const { QFixed d = QFixed::fromReal(CTFontGetDescent(ctfont)); diff --git a/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h b/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h index b7c9edc528..d9ffbb5697 100644 --- a/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h +++ b/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h @@ -78,6 +78,7 @@ public: glyph_metrics_t boundingBox(glyph_t glyph) Q_DECL_OVERRIDE; QFixed ascent() const Q_DECL_OVERRIDE; + QFixed capHeight() const Q_DECL_OVERRIDE; QFixed descent() const Q_DECL_OVERRIDE; QFixed leading() const Q_DECL_OVERRIDE; QFixed xHeight() const Q_DECL_OVERRIDE; diff --git a/src/plugins/platforms/windows/qwindowsfontengine.cpp b/src/plugins/platforms/windows/qwindowsfontengine.cpp index 744d882bb2..12340182af 100644 --- a/src/plugins/platforms/windows/qwindowsfontengine.cpp +++ b/src/plugins/platforms/windows/qwindowsfontengine.cpp @@ -192,6 +192,7 @@ void QWindowsFontEngine::getCMap() lineWidth = otm->otmsUnderscoreSize; fsType = otm->otmfsType; free(otm); + } else { unitsPerEm = tm.tmHeight; } @@ -540,6 +541,62 @@ QFixed QWindowsFontEngine::leading() const return tm.tmExternalLeading; } +namespace { +# pragma pack(1) + + struct OS2Table + { + quint16 version; + qint16 avgCharWidth; + quint16 weightClass; + quint16 widthClass; + quint16 type; + qint16 subscriptXSize; + qint16 subscriptYSize; + qint16 subscriptXOffset; + qint16 subscriptYOffset; + qint16 superscriptXSize; + qint16 superscriptYSize; + qint16 superscriptXOffset; + qint16 superscriptYOffset; + qint16 strikeOutSize; + qint16 strikeOutPosition; + qint16 familyClass; + quint8 panose[10]; + quint32 unicodeRanges[4]; + quint8 vendorID[4]; + quint16 selection; + quint16 firstCharIndex; + quint16 lastCharIndex; + qint16 typoAscender; + qint16 typoDescender; + qint16 typoLineGap; + quint16 winAscent; + quint16 winDescent; + quint32 codepageRanges[2]; + qint16 height; + qint16 capHeight; + quint16 defaultChar; + quint16 breakChar; + quint16 maxContext; + }; + +# pragma pack() +} + +QFixed QWindowsFontEngine::capHeight() const +{ + const QByteArray tableData = getSfntTable(MAKE_TAG('O', 'S', '/', '2')); + if (tableData.size() >= sizeof(OS2Table)) { + const OS2Table *table = reinterpret_cast(tableData.constData()); + if (qFromBigEndian(table->version) >= 2) { + qint16 capHeight = qFromBigEndian(table->capHeight); + if (capHeight > 0) + return QFixed(capHeight) / designToDevice; + } + } + return calculatedCapHeight(); +} QFixed QWindowsFontEngine::xHeight() const { diff --git a/src/plugins/platforms/windows/qwindowsfontengine.h b/src/plugins/platforms/windows/qwindowsfontengine.h index 921351a4b0..b63d8fd282 100644 --- a/src/plugins/platforms/windows/qwindowsfontengine.h +++ b/src/plugins/platforms/windows/qwindowsfontengine.h @@ -103,6 +103,7 @@ public: QFixed descent() const Q_DECL_OVERRIDE; QFixed leading() const Q_DECL_OVERRIDE; QFixed xHeight() const Q_DECL_OVERRIDE; + QFixed capHeight() const Q_DECL_OVERRIDE; QFixed averageCharWidth() const Q_DECL_OVERRIDE; qreal maxCharWidth() const Q_DECL_OVERRIDE; qreal minLeftBearing() const Q_DECL_OVERRIDE; diff --git a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp index 5408ff41e5..18be3b0ce6 100644 --- a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp +++ b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.cpp @@ -208,6 +208,7 @@ QWindowsFontEngineDirectWrite::QWindowsFontEngineDirectWrite(IDWriteFontFace *di , m_lineThickness(-1) , m_unitsPerEm(-1) , m_ascent(-1) + , m_capHeight(-1) , m_descent(-1) , m_xHeight(-1) , m_lineGap(-1) @@ -244,6 +245,7 @@ void QWindowsFontEngineDirectWrite::collectMetrics() m_lineThickness = DESIGN_TO_LOGICAL(metrics.underlineThickness); m_ascent = DESIGN_TO_LOGICAL(metrics.ascent); + m_capHeight = DESIGN_TO_LOGICAL(metrics.capHeight); m_descent = DESIGN_TO_LOGICAL(metrics.descent); m_xHeight = DESIGN_TO_LOGICAL(metrics.xHeight); m_lineGap = DESIGN_TO_LOGICAL(metrics.lineGap); @@ -461,6 +463,16 @@ QFixed QWindowsFontEngineDirectWrite::ascent() const : m_ascent; } +QFixed QWindowsFontEngineDirectWrite::capHeight() const +{ + if (m_capHeight <= 0) + return calculatedCapHeight(); + + return fontDef.styleStrategy & QFont::ForceIntegerMetrics + ? m_capHeight.round() + : m_capHeight; +} + QFixed QWindowsFontEngineDirectWrite::descent() const { return fontDef.styleStrategy & QFont::ForceIntegerMetrics diff --git a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h index f038dcfde4..fb2df00b7e 100644 --- a/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h +++ b/src/plugins/platforms/windows/qwindowsfontenginedirectwrite.h @@ -87,6 +87,7 @@ public: const QTransform &matrix, GlyphFormat) Q_DECL_OVERRIDE; QFixed ascent() const Q_DECL_OVERRIDE; + QFixed capHeight() const Q_DECL_OVERRIDE; QFixed descent() const Q_DECL_OVERRIDE; QFixed leading() const Q_DECL_OVERRIDE; QFixed xHeight() const Q_DECL_OVERRIDE; @@ -122,6 +123,7 @@ private: QFixed m_underlinePosition; int m_unitsPerEm; QFixed m_ascent; + QFixed m_capHeight; QFixed m_descent; QFixed m_xHeight; QFixed m_lineGap; -- cgit v1.2.3