[ttx_diff] Match fontc's logic for detecting variable vs static sources#2018
Merged
Conversation
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
rsheeter
reviewed
May 19, 2026
| 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 |
Contributor
There was a problem hiding this comment.
I've been working on font compilers for over a year and I don't know what this means, what's a "virtual master"?
Contributor
There was a problem hiding this comment.
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.
Member
Author
There was a problem hiding this comment.
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'.
rsheeter
approved these changes
May 19, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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