Skip to content

fix #353: guard empty glyph in TTFGlyph._getCBox#379

Open
gediz wants to merge 1 commit into
foliojs:masterfrom
gediz:fix/353-empty-glyph-cbox
Open

fix #353: guard empty glyph in TTFGlyph._getCBox#379
gediz wants to merge 1 commit into
foliojs:masterfrom
gediz:fix/353-empty-glyph-cbox

Conversation

@gediz

@gediz gediz commented Jun 10, 2026

Copy link
Copy Markdown

Fixes #353, #378, #303, #312 (the earliest report is #179).

The bug

TTFGlyph._getCBox always decodes a 10-byte GlyfHeader. A glyph with a
zero-length loca entry (space, NBSP, U+200D ZWJ, ideographic space) has no
glyf data. The decode then reads the next glyph's header, and when the empty
glyph is the last glyph the read runs past the end of the glyf table and
throws. _decode already guards this with glyfPos === nextPos. _getCBox
does not, and it runs for every glyph through _getMetrics (advance width,
layout).

Reproduction

Any font whose last glyph is empty. The repro in #353 uses Arimo
(github.com/Vikeo/pdfmake-buffer-error). On current master, reading the empty
trailing glyph's metrics throws:

RangeError: Offset is outside the bounds of the DataView
    at DataView.prototype.getInt16
    at DecodeStream.readInt16BE
    at NumberT.decode
    at Struct._parseFields
    at Struct.decode
    at TTFGlyph._getCBox
    at get cbox

Older builds report "Trying to access beyond buffer length" from the same line
(the text in #353); the message changed with the move to a native DataView. The
crash usually surfaces downstream when a subsetted font is embedded or laid out.

The fix

Add the same glyfPos === nextPos guard _decode already uses, returning an
empty bounding box. #378 proposes this same change. The box is
new BBox(0, 0, 0, 0) rather than the default new BBox(): the default is the
±Infinity sentinel, which _getMetrics turns into a non-finite topBearing, so
an explicit zero-area box keeps the metrics finite. The earlier PR #305 and
FreeType zero the empty-glyph box for the same reason.

Tests

Added a regression test in test/issues.js that reads the cbox of the OpenSans
space glyph and asserts it has no positive extent (before the fix it returned
the next glyph's box). npm test passes. The one failing test (i18n
default-language) fails on master too and is unrelated.

Related

  • Prior fix attempt: vhea and glyf fixes #305 adds the same loca guard but bundles several unrelated
    changes (vhea, maxp, post). This PR is the focused version.
  • Downstream reports of the same crash: pdf-lib#1551, pdfmake#2810,
    react-pdf#1055, svg-text-to-path#27.

Fixes foliojs#353.

_getCBox always decodes a 10-byte GlyfHeader. A glyph with a zero-length loca
entry (space, U+200D ZWJ, and similar) has no glyf data, so the decode reads
the following glyph's header. When that empty glyph is the last glyph, the read
runs past the end of the glyf table and throws "RangeError: Offset is outside
the bounds of the DataView" (older builds: "Trying to access beyond buffer
length").

This surfaces when embedding or laying out a subsetted font, where a trailing
empty glyph is common, and is reported downstream through pdf-lib and pdfmake.

Add the same glyfPos === nextPos guard that _decode already uses and return an
empty bounding box. The default new BBox() would set the Infinity sentinel,
which _getMetrics turns into a non-finite topBearing, so the guard returns an
explicit zero-area box.

Add a regression test in test/issues.js that reads the cbox of the OpenSans
space glyph and asserts it has no positive extent.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

"Trying to access beyond buffer length" Error when trying to create with specific font

1 participant