diff --git a/src/glyph/TTFGlyph.js b/src/glyph/TTFGlyph.js index 8dc1c75b..43329e66 100644 --- a/src/glyph/TTFGlyph.js +++ b/src/glyph/TTFGlyph.js @@ -74,8 +74,14 @@ 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]; + + // Return an empty bounding box if there is no data for this glyph + if (glyfPos === nextPos) { return Object.freeze(new BBox(0, 0, 0, 0)); } + 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/test/issues.js b/test/issues.js index ed3d5d5f..66e40e8e 100644 --- a/test/issues.js +++ b/test/issues.js @@ -1,4 +1,5 @@ import * as fontkit from 'fontkit'; +import assert from 'assert'; describe('issues', function () { describe('#282 - ReferenceError: Cannot access \'c3x\' before initialization', function () { @@ -10,4 +11,20 @@ describe('issues', function () { glyph.path; }); }); + + describe('#353 - reading the cbox of an empty glyph', function () { + it('returns an empty box instead of reading past the glyph data', function () { + let font = fontkit.openSync(new URL('data/OpenSans/OpenSans-Regular.ttf', import.meta.url)); + + let glyph = font.glyphForCodePoint(0x20); // space: no outline, empty glyf entry + + // Before the fix this read the following glyph's header (a positive-area + // box), or ran past the buffer for a trailing empty glyph. An empty + // glyph has no extent. Asserting "no positive extent" rather than exact + // zeros so the test holds whether the empty box is (0,0,0,0) or the + // BBox sentinel. + let cbox = glyph.cbox; + assert.ok(cbox.width <= 0 && cbox.height <= 0); + }); + }); });