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); } 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); 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 004cdf93..ba6c7428 100644 --- a/src/tables/vhea.js +++ b/src/tables/vhea.js @@ -1,8 +1,9 @@ import * as r from 'restructure'; +import { version16Dot16 } from '../utils'; // Vertical Header Table export default new r.Struct({ - version: r.uint16, // 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();