Skip to content

Fix table cell font src inheriting an unrelated font family - #1770

Merged
blikblum merged 2 commits into
foliojs:masterfrom
MahathirMohammadShuvo:fix-table-font-family-leak
Aug 19, 2026
Merged

Fix table cell font src inheriting an unrelated font family#1770
blikblum merged 2 commits into
foliojs:masterfrom
MahathirMohammadShuvo:fix-table-font-family-leak

Conversation

@MahathirMohammadShuvo

Copy link
Copy Markdown
Contributor

Fixes #1746.

The bug

A table resolves each cell's font by merging the column, row and cell styles key
by key:

const font = deepMerge({}, colStyle.font, rowStyle.font, cell.font);

src and family do not survive that treatment, because they are not
independent settings: family names a subfamily/variation inside the given
src. When a row style supplies both and a cell overrides only src, the
row's family is carried over and doc.font(src, family) is handed a pair that
was never configured.

Two ways that goes wrong, both from the issue:

doc.table({ rowStyles: [{ font: { src: SOME_TTC_FONT, family: FONT_FAMILY } }] })
   .row([{ text: 'Hello World', font: { src: SOME_TTF_FONT } }]);
// Error: Variations require a font with the fvar, gvar and glyf, or CFF2 tables
doc.table({ rowStyles: [{ font: { src: SOME_TTC_FONT, family: FONT_FAMILY } }] })
   .row([{ text: 'foo' }, { text: 'bar', font: { src: SOME_TTF_FONT } }]);
// no error, but SOME_TTF_FONT is silently ignored - FONT_FAMILY is already
// cached against the first font, so the cell renders in the wrong typeface

Setting a font for a row and overriding it on one cell is ordinary use, and the
silent variant is the worse of the two: the document renders, just with the
wrong font.

The fix

Resolve the font by walking the levels from least to most specific and treating
src and family as one unit:

  • a level that sets src also resets family, so a stale family cannot
    outlive the font it belonged to;
  • a level that sets only family still refines the inherited src, so
    selecting a variation from a row or column font keeps working;
  • size is genuinely independent and continues to merge on its own.

Testing

Two tests added to tests/unit/table.spec.js, using the fonts already in the
repo. The first fails without the change with the exact error from the issue:

expected [Function] to not throw an error but
'Error: Variations require a font with the fvar, gvar and glyf, or CFF2 tables.' was thrown

The second covers the case that must keep working - a cell that overrides only
family still refines the row's src.

Full unit suite passes: 387/387. eslint and prettier clean.

@blikblum

Copy link
Copy Markdown
Member

This will fix #1743?

@MahathirMohammadShuvo

Copy link
Copy Markdown
Contributor Author

Yes - I tested it both ways rather than assume, and it does.

#1743 is the same line. deepMerge deep-clones every source, so a Buffer or
Uint8Array src came out the other side as a plain object of numeric keys,
which is why it stopped looking like a font. It is also why that merge was slow:
it was walking the whole font file byte by byte.

Same document, tests/fonts/Roboto-Regular.ttf read into a Buffer:

on master        Buffer src      -> Error: Not a supported font format or standard PDF font.
                 Uint8Array src  -> Error: Not a supported font format or standard PDF font.
on this branch   Buffer src      -> ok
                 Uint8Array src  -> ok

Replacing the merge with direct assignment means the src is never cloned, so it
arrives at doc.font() as the same object it went in as.

I have pushed a test covering it, which asserts identity (src === buffer) so a
future reintroduction of cloning fails loudly rather than silently. With
lib/table/normalize.js reverted to master both tests in that block fail:

a cell overriding only src does not inherit the row family
  -> Error: Variations require a font with the fvar, gvar and glyf, or CFF2 tables.
a binary font src is passed through untouched
  -> Error: Not a supported font format or standard PDF font.

Full unit suite passes: 388/388.

Happy to add Fixes #1743 to the description if you would like both closed by
this PR.

@blikblum

Copy link
Copy Markdown
Member

Many thanks.

@blikblum
blikblum merged commit e855e7f into foliojs:master Aug 19, 2026
3 checks passed
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.

Table falsely propagate font families when providing fonts in column/row style

2 participants