Skip to content

[ttx_diff] Match fontc's logic for detecting variable vs static sources#2018

Merged
anthrotype merged 1 commit into
mainfrom
fix-source-is-variable
May 19, 2026
Merged

[ttx_diff] Match fontc's logic for detecting variable vs static sources#2018
anthrotype merged 1 commit into
mainfrom
fix-source-is-variable

Conversation

@anthrotype
Copy link
Copy Markdown
Member

@anthrotype anthrotype commented May 18, 2026

ttx_diff was using source/master count to decide whether to tell fontmake to build variable or static. fontc uses a different criterion: whether any axis has a non-zero range (min != default or max != default), or in other words it's not a "point" axis.

This caused ttx_diff to instruct fontmake to build static for single-source designspaces that declare axis ranges, while fontc built them as variable (arguably degenerate having a single master, but GIGO), making the comparison meaningless.

I changed ttx_diff to use fontc's axis-range check for both .designspace and .glyphs sources.

For .glyphs, axis ranges need to be computed from master axis values plus virtual master positions, matching fontc's ir_axes() logic and glyphsLib/builder/axes.py.

I verified that NotoSerifMakasar (1 source, wght 400-700) now produces "output is identical".
Mingzat (1 source, 3 axes, 2 point) now produces a comparable variable build (the remaining fvar/STAT/HVAR/name diffs are #1814: fontc drops point axes that the designspace explicitly declares).

Supersedes #1422.
Fixes #1860

ttx_diff was using source/master count to decide whether to tell
fontmake to build variable or static. fontc uses a different criterion:
whether any axis has a range (min != default or max != default). This
caused ttx_diff to instruct fontmake to build static for single-source
designspaces that declare axis ranges, while fontc built them as
variable — making the comparison meaningless.

Use fontc's axis-range check for both .designspace and .glyphs sources.
For .glyphs, axis ranges are computed from master axis values plus
virtual master positions, matching fontc's ir_axes() logic.

Verified: NotoSerifMakasar (1 source, wght 400-700) now produces
"output is identical". Mingzat (1 source, 3 axes, 2 point) now
produces a comparable variable build (remaining fvar/STAT/HVAR/name
diffs are #1814 — fontc drops point axes that the designspace
explicitly declares).

Supersedes #1422.
Fixes #1860
if path.suffix == ".glyphs" or path.suffix == ".glyphspackage":
font = GSFont(path)
return len(font.masters) > 1
# Virtual masters can extend axis min/max beyond what real masters define
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been working on font compilers for over a year and I don't know what this means, what's a "virtual master"?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A single master font may actually be variable; it could vary with a bracket layer, or via feature variation substitutions. Glyphs doesn't define axis ranges up-front, so a virtual master tells the compiler about the range of variation.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it could vary with a bracket layer

a brace (intermediate) layer you mean. That's exactly what Virtual Masters are for. Extend the axis range to allow intermediate layers in specific glyphs to be defined along axis coordinates that extend beyond the range of the font-wide masters'.

@anthrotype anthrotype added this pull request to the merge queue May 19, 2026
Merged via the queue into main with commit 1a0a752 May 19, 2026
8 checks passed
@anthrotype anthrotype deleted the fix-source-is-variable branch May 19, 2026 15:38
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.

Inconsistency in how we decide to build variable tables

3 participants