-
Notifications
You must be signed in to change notification settings - Fork 94
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 two problems: non-determinism and incorrect rule application in instanciator #689
Fix two problems: non-determinism and incorrect rule application in instanciator #689
Conversation
…nd incorrect application of rules in the instancer
@anthrotype I mis-clicked to publish the PR before I had time to write the description, I wanted to make sure you got a notification now that I'm done writing. @LettError I think you wrote Thanks in advance for your advice. |
Thanks Jany! I may not have time to look into this until the second week of September when I'll be back from holidays. From a very quick check, I find a bit surprising that the dict keys are non deterministic, my understanding was that in Python >= 3.6 dictionaries keep items in insertion order. /cc @madig who authored this particular piece of code in fontmake |
hm, this for loop that populates self.glyph_mutators iterates over a set (whose order is random even in python 3): fontmake/Lib/fontmake/instantiator.py Line 248 in f07b193
The glyph_names set is created here fontmake/Lib/fontmake/instantiator.py Line 199 in f07b193
|
processRules's docstrings emphasizes that "rules order matters", but I don't see why the order of the glyphNames should |
Yes, I think the random ordering is purely a fontmake problem and has nothing to do with processRules()... I think I will fix the randomness here and also implement an alternative version of processRules here so that we can see how it could be different and comment on it, and later we can discuss if the alternative implementation should be upstreamed to designspaceLib somehow. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this looks good to me
Ideally we'd also have your processRulesSwaps in the upstream designspaceLib -- but I don't think that should block this. I think ufoProcessor suffers from the same issue because it uses the current processRules where the order of glyphNames matters, however this glyphNames is created by turning a set into a list (hence order is random). /cc @LettError |
What do you propose? |
the proposed |
Should I merge this? |
Oh actually I can't merge on this repository sorry! Please do if you're happy. |
I just sent you an invite, please try again then -- thanks |
Hello, I pushed here a test that reproduces a bug with the instanciator when several designspace rules touch the same glyphs. I wrote a test designspace and a description of what should happen in the docstring of the test.
Instead of the expected result, there are two problems I would like to address in this PR:
The misbehaved code is below:
fontmake/Lib/fontmake/instantiator.py
Lines 376 to 383 in f07b193
Here is what I get if I put a breakpoint after line 380:
As you can see from the contents of
glyph_names_list
andglyph_names_list_renamed
, thefor
loop will perform the following swaps:Initial
Step 1
Step 2
Step 3 = final
The end result is not right, because what we would want is that the Q gets the outlines of Q.ss01.alt.
And if you run the command again you get a different result, because
glyph_name_list
is keys from a dictcomes from aset()
at some point, so the order is random, see example below:Thinking about this by hand, here is what I think would make sense as a series of swaps (which is basically applying the designspace rules one after the other in order):
Initial
Apply rule 1: Q <-> Q.alt
Apply rule 2: Q.ss01 <-> Q.ss01.alt
Apply rule 3: Q <-> Q.ss01 and Q.alt <-> Q.ss01.alt
This gives a satisfying result for the main case (Q has the outlines of Q.ss01.alt) and also for the others, I feel, since the final swaps make sense (the style is changed so the ss01 has been swapped, and the weight is bold enough so the alt have been swapped). Do you agree that I should implement this result?
Next question: if I want to implement the result above, I need more information than what
designspaceLib.processRules()
returns, so I would need either to modify what that function returns (is that alright? Do other libraries rely on the previous output? I guess yes) or introduce another functions that returns what I want.@anthrotype what do you think? Sorry for the long explanation!