Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Fix "Axis Mappings" interpretation #1040

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open

Fix "Axis Mappings" interpretation #1040

wants to merge 4 commits into from

Conversation

simoncozens
Copy link
Collaborator

This fixes #993. We look at the file format version, app version and instance mapping to determine the correct interpretation of the "Axis Mappings" custom parameter.


def test_axis_mappings_different_interpretations(ufo_module, datadir):
# https://github.com/googlefonts/glyphsLib/issues/859
font = GSFont(datadir.join("gf", "Rubik.glyphs")) # Saved under Glyphs 3079
Copy link
Member

Choose a reason for hiding this comment

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

this Rubik.glyphs seems to already have a correct user->design mapping even if it was saved with an old version:

https://github.com/googlefonts/glyphsLib/blob/1cb4fc5ae2cf385df95d2b7768e7ab4eb60a5ac3/tests/data/gf/Rubik.glyphs#L49-L59

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Right, because it was a format 2 file.

Comment on lines 334 to 338
# We want to return a userspace->designspace map for our purposes
inverted = {v: k for k, v in mapping.items()}
if int(self.font.appVersion) >= 3168:
# Mapping is *definitely* designspace->userspace, invert
return inverted
Copy link
Member

@anthrotype anthrotype Oct 31, 2024

Choose a reason for hiding this comment

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

i'm confused, I thought older versions (< 3168?) would interpret it as design->user and thus require flip, whereas newer versions have aligned with fontmake's interpretation and already have user->design? This block seems to contradict my understanding, for it's using an inverted mapping if the version is more recent.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

"Interpret as" is perhaps not helpful here. :-) I just opened Nunito source, converted to Glyphs 3 file format and saved under Glyphs 3310. The custom parameter is stored as:

wght = {
42 = 200;
61 = 300;
81 = 400;
91 = 500;
101 = 600;
125 = 700;
151 = 800;
178 = 900;
208 = 1000;
};

i.e. designspace to userspace.

Copy link
Member

Choose a reason for hiding this comment

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

now I am extremely confused

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Thankfully the code has comments and the tests are passing. :-) (And I can compile fonts that were not compiling before.)

Copy link
Member

Choose a reason for hiding this comment

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

well, I for one don't understand this whole mess. It would be nice to have a recap.

Copy link
Member

@anthrotype anthrotype Oct 31, 2024

Choose a reason for hiding this comment

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

I can compile fonts that were not compiling before

good, what I'm worried about are the other fonts that were compiling before and may not after this.
Right now (tested with 3324) on a newly created glyphs3 file, the Axis Mappings is already stored in the source as user->design (or external->internal, as Glyphs calls them), so it is correct and matches fontmake. Wouldn't this PR invert it? I'm seeing

if int(self.font.appVersion) >= 3168:
    return inverted

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

You are going to love this.

Glyphs now stores user->design for new fonts, but it "upgrades" old fonts by simply inverting them. Take your new font, manually edit "appVersion" to (say) 3110, open it in Glyphs and save it again - the mappings will be flipped.

So I guess this means we can't trust the app version number, and we have to probe against the instance mapping.

Copy link
Collaborator

Choose a reason for hiding this comment

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

We could have went with my suggestion (back in #745) and made glyphsLib match (old) GlyphsApp behavior and fixed the few fonts that would have been broken by this. Now it is even a bigger mess...

Copy link
Collaborator Author

@simoncozens simoncozens Oct 31, 2024

Choose a reason for hiding this comment

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

I don't deny that it's stupid and wrong and there may have been questionable choices on both sides, but in 95% of cases the interpretation is completely obvious. Do you have a weight uservalue of 7? You did something wrong. Did all the master locations suddenly fall outside of the design space and you have no valid masters any more? You got the axis mappings backwards. Compare against the instance locations, because we know which way round they are, and if the ranges are wildly different, switch it. It's a mess, but it's not a hard mess to clean up.

if self.font.format_version != 3:
# Glyphs wasn't using this custom parameter, only we were
return mapping
# Let's get heuristical
Copy link
Member

Choose a reason for hiding this comment

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

hm i'm a bit skeptical we need to go "heuristical".. Can't we simply check the version and do accordingly? If the source file doesn't match the interpretation for the version it was saved with, we can say it's not our problem

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think there were some fonts that would set it "wrong" in Glyphs to make it work with fontMake.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Exactly.

Copy link
Member

Choose a reason for hiding this comment

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

how about fixing the actual sources instead?

@anthrotype
Copy link
Member

anthrotype commented Oct 31, 2024

we do already check the instances when there's no axis mappings nor axis location parameters to infer the master's user-space coordinates based on the instances, and that inference has already proved a bit brittle when the user reports unexpected "base master not fund" or weird interpolations because of unexpected mappings.
Now we are saying that Axis Mappings, which was supposed to give a full explicit definitions of the mappings, not tied to the masters or instances, can't be trusted and we'll still try to fix it by looking at the instances.. but the instances in a VF at least do not need to be there, nor they need to be defined at all the axes corners. Is there a chance that this new heuristic to fix up a few sources at compile time may end up screwing perfectly valid fonts?

@anthrotype
Copy link
Member

anthrotype commented Oct 31, 2024

(i hate when I forget a not and the whole sentence stops making sense)

@anthrotype
Copy link
Member

anthrotype commented Oct 31, 2024

besides, the inference of user->design mappings from the instances is only meant to work for weight and width, IIRC. And it's unlikely that these instances also have Axis Location custom parameter if there's already an Axis Mappings, which in theory trumps Axis Location as it's more general

@simoncozens
Copy link
Collaborator Author

Ok. So how would you like to fix the issue?

@schriftgestalt
Copy link
Collaborator

I would not add any axis mapping if there is nothing explicitly in the file. Maybe issue a warning.

@simoncozens
Copy link
Collaborator Author

That doesn't fix the problem. The problem is we can't build fonts because the Axis Mappings that are in the file aren't interpreted correctly.

@schriftgestalt
Copy link
Collaborator

There are only very few files that have those faulty axis mappings. That has to be caught in QA and fixed in the files.

@simoncozens
Copy link
Collaborator Author

faulty axis mappings

OK, one last time. These are not faulty for Glyphs.app users. Glyphs.app compiles these things just fine, and produces VFs with correct avar mappings. glyphsLib does not. A good example is Cormorant.glyphs.

The whole purpose of glyphsLib is to compile Glyphs files so we don't have to use Glyphs.app in an open source toolchain. I don't think we should decide that we're just not going to bother to compile valid Glyphs files that work fine in Glyphs.

@schriftgestalt
Copy link
Collaborator

Then misunderstood the problem. Sorry.
But Glyphs doesn’t export a working avar for Cormorant. It needs "Axis Location" parameters in the master settings.

@schriftgestalt
Copy link
Collaborator

As I understand it (and how Glyphs handles it) is such:
Use the axis range from the masters (either the coordinates or the axis locations; those are called internal and external coordinates in the Glyphs 4 API) for fvar and such.
Then use the "Axis Location" in the instances or "Axis Mapping" in the font to build a avar table.

@simoncozens
Copy link
Collaborator Author

Urgh, you're right.

@anthrotype
Copy link
Member

Cormorant.glyhps contains these incorrect mappings, with keys/values swapped:

{
name = "Axis Mappings";
value = {
wght = {
40 = 300;
48 = 400;
58 = 500;
69 = 600;
80 = 700;
};

Even Glyphs.app (version 3.3 build 3324) displays the first column (the keys) as "external" and the second column (the values) as "internal" (whereas it should be the other way around, but Glyphs.app is just reading what's in the source).

If I just look at the source, I could say with confidence that the source itself contains a bug. Maybe it was not set up like this by the font developer, and the source originally contained mappings in the order that fontmake expects but then got automatically "fixed" by Glyphs.app, I don't know. But it still remains buggy. And even Glyphs.app itself can't export a correct avar from this, not just fontmake.

The way I'd suggest fixing this is by modifying the custom parameter in the source, swapping the values with keys.

@anthrotype
Copy link
Member

anthrotype commented Nov 1, 2024

It needs "Axis Location" parameters in the master settings.

for fontmake at least, you don't need both Axis Mappings and Axis Locations because the former encompasses the latter and thus instead of risking duplicating the same information twice (or having them out of sync), we only look at Axis Mappings if present, otherwise we go find Axis Locations.

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.

Axis mappings completely upside down
4 participants