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

Instantiator: rule substitutions behave differently than for OT feature variations #852

Open
madig opened this issue Jun 11, 2024 · 4 comments

Comments

@madig
Copy link
Collaborator

madig commented Jun 11, 2024

Rules that work for variable fonts may not work for instances, because varLib/feature variations and the instantiator work differently.

  • Expectation: I can reuse the Designspace with the rules that I made work for variable fonts.
  • Actually: I have to make a copy and write different rules to implement the same logic for instance generation.

The reproducers are described in more detail on https://github.com/daltonmaag/designspace-rules-reproducers.

What I expect (from instance-ref-stacked-high.ttf, made from in instance-reference.designspace, with the test string "Aa"):

image

What actually happens (in instance-test-stacked-high.ttf, made from instance-test.designspace):

image

The "a" is the original glyph rather than "a.break".

The rub lies in the way substitutions work:

  1. In feature variations, the shaper is expected to find the first condition set that matches and then stop there.
  2. The instantiator will collect all rules where the condition set matches and then swap glyph contents. On rule boundaries (like HGHT=750 for instance-test-stacked-high.ttf), when rules contain duplicate substitutions and start and end points overlap, it may collect two or more rules. Any duplicate substitutions can then cause a swap back and forth, undoing substitutions.
@arrowtype
Copy link

arrowtype commented Jan 15, 2025

I’m also running into what I think is this same issue, particularly “Any duplicate substitutions can then cause a swap back and forth, undoing substitutions.”

Repro case:
https://github.com/arrowtype/test-fontmake-rules-overlap

diagram of the issue

The above issues come from a rules element like this (which is what glyphsLib generated, based on bracket glyphs in a Glyphs source):

<rules>
    <rule name="BRACKET.Weight_650_800">
        <conditionset>
            <condition name="Weight" minimum="650" maximum="800"/>
        </conditionset>
        <sub name="Oslash" with="Oslash.BRACKET.varAlt01"/>
        <sub name="baht" with="baht.BRACKET.varAlt01"/>
        <sub name="dollar" with="dollar.BRACKET.varAlt01"/>
    </rule>
    <rule name="BRACKET.Weight_550_800">
        <conditionset>
            <condition name="Weight" minimum="550" maximum="800"/>
        </conditionset>
        <sub name="baht" with="baht.BRACKET.varAlt01"/>
        <sub name="dollar" with="dollar.BRACKET.varAlt01"/>
    </rule>
    <rule name="BRACKET.Weight_450_800">
        <conditionset>
            <condition name="Weight" minimum="450" maximum="800"/>
        </conditionset>
        <sub name="dollar" with="dollar.BRACKET.varAlt01"/>
    </rule>
</rules>

The “working” example comes from a rules element like this (with redundant rules removed):

<rules>
    <rule name="BRACKET.Weight_650_800">
        <conditionset>
        <condition name="Weight" minimum="650" maximum="800"/>
        </conditionset>
        <sub name="Oslash" with="Oslash.BRACKET.varAlt01"/>
        <!-- baht rule removed -->
        <!-- dollar rule removed -->
    </rule>
    <rule name="BRACKET.Weight_550_800">
        <conditionset>
        <condition name="Weight" minimum="550" maximum="800"/>
        </conditionset>
        <sub name="baht" with="baht.BRACKET.varAlt01"/>
        <!-- dollar rule removed -->
    </rule>
    <rule name="BRACKET.Weight_450_800">
        <conditionset>
        <condition name="Weight" minimum="450" maximum="800"/>
        </conditionset>
        <sub name="dollar" with="dollar.BRACKET.varAlt01"/>
    </rule>
</rules>

@madig
Copy link
Collaborator Author

madig commented Jan 16, 2025

I think the current solution is to write variable features manually. You may have to manually un-overlap effective regions however, essentially what https://github.com/fonttools/fonttools/blob/main/Lib/fontTools/varLib/featureVars.py#L122-L148 is doing.

@arrowtype
Copy link

Thanks for the quick reply and insight! I'll have to think about whether/how I could make an un-overlapping step within the build setting I'm using...

Are you writing the feature code in a fea file, or in a glyphs source, or in some other way? I haven't really written feature variations in the past, other than through DS rules and Glyphs bracket layers.

@madig
Copy link
Collaborator Author

madig commented Jan 17, 2025

You put them in a feature file. I think feaLib's syntax isn't standardized, so it will only work there.

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

No branches or pull requests

2 participants