From c4a882018a80038e556e3bb4b7674f829856c0ea Mon Sep 17 00:00:00 2001 From: Vsevolod Volkov Date: Sun, 26 Mar 2023 20:50:41 +0300 Subject: [PATCH 1/4] Fix `VHEA` table structure Signed-off-by: Vsevolod Volkov --- src/tables/vhea.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tables/vhea.js b/src/tables/vhea.js index 004cdf93..c0f4ddd4 100644 --- a/src/tables/vhea.js +++ b/src/tables/vhea.js @@ -2,7 +2,8 @@ import * as r from 'restructure'; // Vertical Header Table export default new r.Struct({ - version: r.uint16, // Version number of the Vertical Header Table + majorVersion: r.uint16, // Major version number of the Vertical Header Table + minorVersion: r.uint16, // Minor version number of the Vertical Header Table ascent: r.int16, // The vertical typographic ascender for this font descent: r.int16, // The vertical typographic descender for this font lineGap: r.int16, // The vertical typographic line gap for this font From 7c7e6ac889056bb09e39b46e2950a906df3f9fc7 Mon Sep 17 00:00:00 2001 From: Vsevolod Volkov Date: Fri, 7 Apr 2023 18:34:02 +0300 Subject: [PATCH 2/4] Fix loading non-existent data from `glyf` table Signed-off-by: Vsevolod Volkov --- src/glyph/TTFGlyph.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/glyph/TTFGlyph.js b/src/glyph/TTFGlyph.js index 8dc1c75b..4a001be7 100644 --- a/src/glyph/TTFGlyph.js +++ b/src/glyph/TTFGlyph.js @@ -74,8 +74,16 @@ export default class TTFGlyph extends Glyph { return this.path.cbox; } + let glyfPos = this._font.loca.offsets[this.id]; + let nextPos = this._font.loca.offsets[this.id + 1]; + + // No data for this glyph (space?) + if (glyfPos === nextPos) { + return super._getCBox(); + } + let stream = this._font._getTableStream('glyf'); - stream.pos += this._font.loca.offsets[this.id]; + stream.pos += glyfPos; let glyph = GlyfHeader.decode(stream); let cbox = new BBox(glyph.xMin, glyph.yMin, glyph.xMax, glyph.yMax); From 6b9538a158af66758590c5d028b9d9a6669d5730 Mon Sep 17 00:00:00 2001 From: Vsevolod Volkov Date: Fri, 7 Apr 2023 18:35:25 +0300 Subject: [PATCH 3/4] Setting zero coordinates for empty glyphs (space) Signed-off-by: Vsevolod Volkov --- src/glyph/Path.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/glyph/Path.js b/src/glyph/Path.js index a119fb28..5396b088 100644 --- a/src/glyph/Path.js +++ b/src/glyph/Path.js @@ -63,6 +63,14 @@ export default class Path { } } + if (this.commands.length === 0) { + // No content, put 0 instead of Infinity + cbox.minX = 0; + cbox.minY = 0; + cbox.maxX = 0; + cbox.maxY = 0; + } + this._cbox = Object.freeze(cbox); } @@ -172,6 +180,14 @@ export default class Path { } } + if (this.commands.length === 0) { + // No content, put 0 instead of Infinity + bbox.minX = 0; + bbox.minY = 0; + bbox.maxX = 0; + bbox.maxY = 0; + } + return this._bbox = Object.freeze(bbox); } From 30acdf8424eb3b1dfc659f7a9f4bb130ddfc94dd Mon Sep 17 00:00:00 2001 From: Vsevolod Volkov Date: Mon, 10 Apr 2023 16:32:22 +0300 Subject: [PATCH 4/4] Handling `maxp`, `post, `vhea` versions as Version16Dot16 Signed-off-by: Vsevolod Volkov --- src/tables/maxp.js | 3 ++- src/tables/post.js | 3 ++- src/tables/vhea.js | 4 ++-- src/utils.js | 36 ++++++++++++++++++++++++++++++++++++ 4 files changed, 42 insertions(+), 4 deletions(-) diff --git a/src/tables/maxp.js b/src/tables/maxp.js index 3e211388..b85f17aa 100644 --- a/src/tables/maxp.js +++ b/src/tables/maxp.js @@ -1,8 +1,9 @@ import * as r from 'restructure'; +import { version16Dot16 } from '../utils'; // maxiumum profile export default new r.Struct({ - version: r.int32, + version: version16Dot16, numGlyphs: r.uint16, // The number of glyphs in the font maxPoints: r.uint16, // Maximum points in a non-composite glyph maxContours: r.uint16, // Maximum contours in a non-composite glyph diff --git a/src/tables/post.js b/src/tables/post.js index 04fdeabe..d03da1db 100644 --- a/src/tables/post.js +++ b/src/tables/post.js @@ -1,7 +1,8 @@ import * as r from 'restructure'; +import { version16Dot16 } from '../utils'; // PostScript information -export default new r.VersionedStruct(r.fixed32, { +export default new r.VersionedStruct(version16Dot16, { header: { // these fields exist at the top of all versions italicAngle: r.fixed32, // Italic angle in counter-clockwise degrees from the vertical. underlinePosition: r.int16, // Suggested distance of the top of the underline from the baseline diff --git a/src/tables/vhea.js b/src/tables/vhea.js index c0f4ddd4..ba6c7428 100644 --- a/src/tables/vhea.js +++ b/src/tables/vhea.js @@ -1,9 +1,9 @@ import * as r from 'restructure'; +import { version16Dot16 } from '../utils'; // Vertical Header Table export default new r.Struct({ - majorVersion: r.uint16, // Major version number of the Vertical Header Table - minorVersion: r.uint16, // Minor version number of the Vertical Header Table + version: version16Dot16, ascent: r.int16, // The vertical typographic ascender for this font descent: r.int16, // The vertical typographic descender for this font lineGap: r.int16, // The vertical typographic line gap for this font diff --git a/src/utils.js b/src/utils.js index 72db5760..2389c9d2 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,3 +1,5 @@ +import { DecodeStream, EncodeStream } from 'restructure'; + export function binarySearch(arr, cmp) { let min = 0; let max = arr.length - 1; @@ -60,3 +62,37 @@ export function decodeBase64(base64) { return bytes; } + +export class Version16Dot16 { + fromBuffer(buffer) { + let stream = new DecodeStream(buffer); + return this.decode(stream); + } + + toBuffer(value) { + let size = this.size(value); + let buffer = new Uint8Array(size); + let stream = new EncodeStream(buffer); + this.encode(stream, value); + return buffer; + } + + size() { + return 4; + } + + decode(stream) { + let major = stream.readUInt16BE(); + let minor = stream.readUInt16BE() >> 12; + return major + minor / 10; + } + + encode(stream, val) { + let major = Math.trunc(val); + let minor = (val - major) * 10; + stream.writeUInt16BE(major); + return stream.writeUInt16BE(minor << 12); + } +} + +export const version16Dot16 = new Version16Dot16();