From c8ba19cd1ba9c731fcaaa07aa31eab48b30fe411 Mon Sep 17 00:00:00 2001 From: Vsevolod Volkov Date: Fri, 7 Apr 2023 00:33:03 +0300 Subject: [PATCH] Added respect for the "useTypoMetrics" flag Signed-off-by: Vsevolod Volkov --- README.md | 1 + src/TTFFont.js | 53 +++++++++++++++++++++++++++++++++++++++++++--- src/glyph/Glyph.js | 17 +++------------ 3 files changed, 54 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 027b61ce..248bf3e5 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,7 @@ The following properties describe the general metrics of the font. See [here](ht * `underlinePosition` - the offset from the normal underline position that should be used * `underlineThickness` - the weight of the underline that should be used * `italicAngle` - if this is an italic font, the angle the cursor should be drawn at to match the font design +* `lineHeight` - is the vertical space between adjacent lines (their baselines) of text, also known as leading. See [here](https://en.wikipedia.org/wiki/Leading) for more details. * `capHeight` - the height of capital letters above the baseline. See [here](http://en.wikipedia.org/wiki/Cap_height) for more details. * `xHeight`- the height of lower case letters. See [here](http://en.wikipedia.org/wiki/X-height) for more details. * `bbox` - the font’s bounding box, i.e. the box that encloses all glyphs in the font diff --git a/src/TTFFont.js b/src/TTFFont.js index 6aa0937a..08483b4f 100644 --- a/src/TTFFont.js +++ b/src/TTFFont.js @@ -91,6 +91,44 @@ export default class TTFFont { return result; } + _getMetrics() { + if (this._metrics) { return this._metrics; } + + let { 'OS/2': os2, hhea } = this; + let useTypoMetrics = os2.fsSelection.useTypoMetrics; + let ascent, descent, lineGap, lineHeight; + + // Use the same approach as FreeType + // https://gitlab.freedesktop.org/freetype/freetype/-/blob/4d8db130ea4342317581bab65fc96365ce806b77/src/sfnt/sfobjs.c#L1310 + + if (useTypoMetrics) { + ascent = os2.typoAscender; + descent = os2.typoDescender; + lineGap = os2.typoLineGap; + lineHeight = ascent - descent + lineGap; + } else { + ascent = hhea.ascent; + descent = hhea.descent; + lineGap = hhea.lineGap; + lineHeight = ascent - descent + lineGap; + } + + if (!ascent || !descent) { + if (os2.typoAscender || os2.typoDescender) { + ascent = os2.typoAscender; + descent = os2.typoDescender; + lineGap = os2.typoLineGap; + lineHeight = ascent - descent + lineGap; + } else { + ascent = os2.winAscent; + descent = -os2.winDescent; + lineHeight = ascent - descent; + } + } + + return this._metrics = {ascent, descent, lineGap, lineHeight}; + } + /** * Gets a string from the font's `name` table * `lang` is a BCP-47 language code. @@ -166,7 +204,7 @@ export default class TTFFont { * @type {number} */ get ascent() { - return this.hhea.ascent; + return this._getMetrics().ascent; } /** @@ -174,7 +212,7 @@ export default class TTFFont { * @type {number} */ get descent() { - return this.hhea.descent; + return this._getMetrics().descent; } /** @@ -182,7 +220,7 @@ export default class TTFFont { * @type {number} */ get lineGap() { - return this.hhea.lineGap; + return this._getMetrics().lineGap; } /** @@ -209,6 +247,15 @@ export default class TTFFont { return this.post.italicAngle; } + /** + * The vertical space between adjacent lines (their baselines) of text. + * See [here](https://en.wikipedia.org/wiki/Leading) for more details. + * @type {number} + */ + get lineHeight() { + return this._getMetrics().lineHeight; + } + /** * The height of capital letters above the baseline. * See [here](https://en.wikipedia.org/wiki/Cap_height) for more details. diff --git a/src/glyph/Glyph.js b/src/glyph/Glyph.js index 3592150f..15e26c0e 100644 --- a/src/glyph/Glyph.js +++ b/src/glyph/Glyph.js @@ -64,23 +64,12 @@ export default class Glyph { let {advance:advanceWidth, bearing:leftBearing} = this._getTableMetrics(this._font.hmtx); - // For vertical metrics, use vmtx if available, or fall back to global data from OS/2 or hhea + // For vertical metrics, use vmtx if available, or fall back to global data if (this._font.vmtx) { var {advance:advanceHeight, bearing:topBearing} = this._getTableMetrics(this._font.vmtx); - } else { - let os2; - if (typeof cbox === 'undefined' || cbox === null) { ({ cbox } = this); } - - if ((os2 = this._font['OS/2']) && os2.version > 0) { - var advanceHeight = Math.abs(os2.typoAscender - os2.typoDescender); - var topBearing = os2.typoAscender - cbox.maxY; - - } else { - let { hhea } = this._font; - var advanceHeight = Math.abs(hhea.ascent - hhea.descent); - var topBearing = hhea.ascent - cbox.maxY; - } + var advanceHeight = Math.abs(this._font.ascent - this._font.descent); + var topBearing = this._font.ascent - cbox.maxY; } if (this._font._variationProcessor && this._font.HVAR) {