Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

fonttools' special handling of standard axis names leads to name table diffs vs fontc #1020

Open
anthrotype opened this issue Oct 10, 2024 · 4 comments
Labels
bug Something isn't working
Milestone

Comments

@anthrotype
Copy link
Member

anthrotype commented Oct 10, 2024

fontTools.varLib (used by fontmake to build VFs) contains a hardcoded set of axis names that receive special treatment, see:

https://github.com/fonttools/fonttools/blob/afceebcda515b779faabe0acdec13018bab0c246/Lib/fontTools/varLib/__init__.py#L890-L921

this is a remnant of the days when Designspace document did not yet have an explicit <axes> element defining the set of axes used therein, with attributes such as the name used internally to reference them from locations, the four-letter tag to use in fvar, or more recently labelname elements with human-readable localized strings for UI use.

There were designspaces containing axes with the name attribute set to "weight", "width", "slant", "optical" and "italic" (in lowercase following a convention probably coming from MutatorMath), and varLib would assign these special group of axes a four-letter tag and UI label to store in the name table. Note that any other axis was not even supported at that stage.

    standard_axis_map = OrderedDict(
        [
            ("weight", ("wght", {"en": "Weight"})),
            ("width", ("wdth", {"en": "Width"})),
            ("slant", ("slnt", {"en": "Slant"})),
            ("optical", ("opsz", {"en": "Optical Size"})),
            ("italic", ("ital", {"en": "Italic"})),
        ]
    )

Even after <axes> element was spec'ed and implemented (at some point it became even required, forgot exactly when), these "standard" axes continued to be handled specially as you can see from the above linked code.
Probably this was done to continue supporting old files with fewer or no modifications, I don't exactly remember.

Note in particular this bit below.

        if axis_name in standard_axis_map:
            if axis.tag is None:
                axis.tag = standard_axis_map[axis_name][0]
            if not axis.labelNames:
                axis.labelNames.update(standard_axis_map[axis_name][1])

So, if an axis name was "weight" (lowercase) - thus one of the standard axis names - and it didn't also define explicit labelname sub-elements (these are usually omitted unless non-english localised strings for axis names are desired), the required English string used to show the axis in UI would be "Weight" (title case); "width" => "Width", ..., "optical" => "Optical Size", etc.
Whereas for axes whose name is not in that standard set, the English UI label name would simply be the same as the name attribute, so no special handling.

(But what if I really want to name my axis "optical" all lowercase?! Well you can't, unless you add a labelname element with xml:lang="en" attribute, which most don't (glyphsLib does not)).

Now I actually stumbled on sources out there, e.g. https://github.com/weiweihuanghuang/Work-Sans, in which the axis is called "weight" in lowercase, but fontmake (via fontTools.varLib) would actually assign "Weight" as its UI label string (using the standard_axis_map above), whereas fontc just uses the axis name as the UI label (it cannot read labelname elements either, that's a DSv5 feature I believe #837), so fontc' name table entry ends up being "weight" in lowercase. E.g.:

--- /Users/clupo/oss/fontc/build/gftools/fontc.name.ttx	2024-10-10 17:36:57
+++ /Users/clupo/oss/fontc/build/gftools/fontmake.name.ttx	2024-10-10 17:36:57
@@ -24,7 +24,7 @@
       Text
     </namerecord>
     <namerecord nameID="256" platformID="3" platEncID="1" langID="0x409">
-      weight
+      Weight
     </namerecord>
   </name>

Similar diffs would also pop up in related tables like fvar and STAT in which the same axis name strings are also used.

One could argue this is "legacy" and we might not bother supporting it, it does't take much effort to go and modify the axis name in the source from "weight" to "Weight" or from "optical" to "Optical Size" etc.

"Fixing" fonttools to no longer treat these specially could open other cans of worms, so I'm inclined to keep it as is.

IMO fontc should just do whatever fonttools does, citing "history" as the reason why some axis names are more special than others.

@anthrotype
Copy link
Member Author

Here's another test font, which defines one axis named "optical" with two masters, Text and Display:

StandardAxisNames.glyphs.zip

glyphsLib would generate a .designspace containing the following axes element (no mention of 'Optical Size' anywhere, just name="optical" attribute)

  <axes>
    <axis tag="opsz" name="optical" minimum="14" maximum="24" default="14"/>
  </axes>

but when compiling this, the name table would contain "Optical Size" label string:

--- /Users/clupo/oss/fontc/build/gftools/fontc.name.ttx	2024-10-10 17:52:53
+++ /Users/clupo/oss/fontc/build/gftools/fontmake.name.ttx	2024-10-10 17:52:53
@@ -24,7 +24,7 @@
       Text
     </namerecord>
     <namerecord nameID="256" platformID="3" platEncID="1" langID="0x409">
-      optical
+      Optical Size
     </namerecord>
   </name>

@behdad
Copy link

behdad commented Oct 10, 2024

The history bit sounds about right.

Can we add deprecation warnings to fonttools when these codepaths are used, and ask that the .ds file be amended with labels? Not sure what's best. Replicating in fontc sounds safest indeed.

@rsheeter
Copy link
Contributor

+1 to replicate in fontc, citing the existing code

@anthrotype
Copy link
Member Author

anthrotype commented Oct 14, 2024

the <labelname> element of axis is not a DSv5 feature but it has long existed. It's unclear to me how many DS-based projects make use of it (and as far as I am aware Glyphs.app does not currently support defining localised names for axes, see https://forum.glyphsapp.com/t/localisable-axis-names/19028).

norad doesn't even read these, and I got stuck trying to convince quick-xml and serde parse them: linebender/norad#323

For now, to better match fonttools, I will just do the standard axis names remapping for the 5 hard-coded values. To match it 100% we would also need to parse the axis labelnames and use the xml:lang="en" entry therein.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants