Skip to content

Conversation

@Hoolean
Copy link
Contributor

@Hoolean Hoolean commented May 6, 2025

Some of the larger diffs on crater come from designspaces that ttx_diff.py is instructing fontmake to build as statics, but which fontc will always build as variable (e.g. docrepair-fonts/bacasime-antique-fonts). This PR brings the condition in ttx_diff.py in line with the one in fontc, which resolves these.

Trade-off

Any designspace that is single source is probably being instructed to be built as static by gftools. This means that after the change, the TTFs on crater would be less representative of those produced by gftools in the real world, even if as a superset of the tables and data that would be included in the statics. (UFOs are unaffected)

The alternative to this PR would be either:

  1. Add a fontc argument that requests a static be built, irrespective of the sources and axes (undesirable); or
  2. Implement in gftools the ability to instantiate the final statics from a variable TTF when buildStatics is enabled.

@anthrotype
Copy link
Member

arguably the opposite should happen. A font with only one source can't ever be variable so whatever variable tables fontc they must all be empty and no-op.

@anthrotype
Copy link
Member

i checked the docrepair-fonts/bacasime-antique-fonts source you mentioned, and it defines some wdth axis with min != default != max but then it only defines one source (at the default location) so that axis isn't actually "variable". The entire .designspace file is technically useless.

@rsheeter
Copy link
Contributor

rsheeter commented May 7, 2025

What is the expected outcome of such a designspace? An inert variable font?

@anthrotype
Copy link
Member

currently in the python toolchain, it depends on what the user asks. If fontmake -o variable, you'd get the dummy variable tables, if fontmake -o ttf, you get one static font.

@anthrotype
Copy link
Member

however, in this particular case, where there is only one source, it's clear that you can't make a meaningful variable font from just one source, so you may argue the expected outcome is a static font.

@rsheeter
Copy link
Contributor

rsheeter commented May 7, 2025

fontc is variable first so I think I would expect the fontmake -o variable outcome. To me that's what the source actually says (have an axis, I just didn't define any behavior for it [yet]).

@Hoolean
Copy link
Contributor Author

Hoolean commented May 7, 2025

Ta both for taking a look :) Agreed that producing a VF with empty variable tables does not respect the intent of these sources, and that we should avoid this; with that said, a few reasons are persuading me that the place for this logic is not inside of the fontc binary itself:

The Glyphs file-format is high-level, and it is expected that building a variable or static is determined with a heuristic. On the other hand, the designspace and UFO formats are expected to authoritatively build whatever is contained within them, even when overriding conventional default engineering. To this end, I would expect fontc to always produce an fvar table for a designspace that contained explicit axes, and avoid additional processing.

As a fallback, the user has the option to pass the single UFO it contains instead to produce a static build. There are potentially niche engineering uses for the limited VFs too, e.g., a per-script sub-subfamily that can match the axes of its wider parent family even for a writing system that can only vary a subset of them.

@Hoolean
Copy link
Contributor Author

Hoolean commented May 7, 2025

after writing, I am now thinking there might be a Plan C for crater/ttx_diff and gftools; if the designspace only has a single source, we pass that UFO through to fontc directly instead?

@anthrotype
Copy link
Member

if the designspace is modified such that the axis min==default==max, then fontc also builds a static font:

 <axes>
  <axis default="100" name="width" maximum="100" tag="wdth" minimum="100">
   <labelname xml:lang="en">Width</labelname>
  </axis>
 </axes>

so if we want the logic in ttx_diff.py to match fontc's "variable first" approach, it's not sufficient that you count the number of axes > 0. You want to check that all the axes are not "point" axes (i.e. their min != default or default != max). fontc counts only the variable axes thus defined.

And actually, len(axes) == 0 is not even a valid designspace, even fontmake rejects it.

@anthrotype
Copy link
Member

But if we were to take the font developer's intentions into account (which I believe we should), ttx_diff.py should read the config.yaml file (if present) and check for the presence of buildVariable: true|false to determine if a source was meant to be build as variable or not.
In this particular example, despite the width axis definition extending beyond the default location, the buildVariable is set to false (that's almost always the case when you've got only one source).

@rsheeter
Copy link
Contributor

rsheeter commented May 8, 2025

config.yaml is Google-only and probably not appropriate to read from a general purpose compiler? - certainly whatever our replacement for gftools ends up being could do so.

@anthrotype
Copy link
Member

of course, I didn't mean fontc should check config.yaml, but that ttx_diff.py does that in order to decide whether to build a variable or static font

@rsheeter
Copy link
Contributor

Crater produced this command based on the config.yaml: python resources/scripts/ttx_diff.py 'https://github.com/docrepair-fonts/bacasime-antique-fonts#sources/Bacasime-Antique-Regular.designspace'.

I don't think it makes sense for ttx_diff to turn around and reparse config.yaml so perhaps we should add flags for crater to advise it. I suppose we would then need the ability for fontc to be specifically advised to not build a variable font even if the source appears to suggest it. Which is ... weird.

...are we sure this isn't a source issue? Why does it make sense for BacasimeAntique to specify variable width if it doesn't actually want that?

 <axes>
  <axis default="100" name="width" maximum="220" tag="wdth" minimum="80">
   <labelname xml:lang="en">Width</labelname>
   <map output="80" input="80"/>
   <map output="100" input="100"/>
   <map output="300" input="220"/>
  </axis>
 </axes>

@anthrotype
Copy link
Member

...are we sure this isn't a source issue? Why does it make sense for BacasimeAntique to specify variable width if it doesn't actually want that?

it doesn't make sense, in fact I initially commented that "the entire .designspace file is technically useless". Yes, I agree this is a source issue and can and should be fixed there, to align the source data with the expected result (a static font).

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.

3 participants