-
Notifications
You must be signed in to change notification settings - Fork 43
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
use instantiator when decomposing "sparse" composite glyphs #826
Merged
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
anthrotype
force-pushed
the
interpolatable-filters
branch
from
March 18, 2024 11:39
388cb9f
to
7fbaedc
Compare
…d with decomposing pen
anthrotype
force-pushed
the
interpolatable-filters
branch
4 times, most recently
from
March 19, 2024 14:14
b506ee3
to
6fec373
Compare
These filters take multiple glyphSets as input and zip through the glyphs with the same name, processing them as a group instead of one glyph at a time.
this will be used in filters that decompose composite glyphs, to make sure the latter appears the same after decomposition in situations where the composite glyph is defined at fewer source locations than some of its component glyphs.
anthrotype
force-pushed
the
interpolatable-filters
branch
2 times, most recently
from
March 20, 2024 13:36
38ad741
to
d499a31
Compare
also note the preProcess_test.py: previously if a glyph was marked non-export (e.g. _o.numero), we were decomposing it to contours as a whole alonside all of its nested components (e.g. 'o'), but that's unnecessary; now we only strictly decompose the components whose base glyph is marked as non-export, without recursing into their nested components, as there may still be a chance that after decomposing only those, the parent glyph can remain as a pure composite.
… in addition to bool this will simplify the OTFCompiler a bit
…ault TTF masters For TrueType only, when the glyphSet for a non default master contains composite glyphs that point to missing component base glyphs, we create and add empty glyphs so that the composite glyph is not dropped from the master TTF as invalid (i.e. pointing to nowhere); varLib will ignore those empty glyphs when building gvar variations, so the additional glyphs will not add extra masters. The glyph metrics (HVAR, VVAR) similarly will not have additional masters for the empty glyphs (we use a sentinel value understood by varLib 'skip me'). The composite glyph, on the other hand, will still be considered when building variations. One may use this technique to adjust the placement of components in a composite glyph, and/or its advance width/height, but only for some intermediate locations without requiring to define intermediate masters for the component glyphs themselves.
… of the default layer glyphs
Factored out some shared code from TTFInterpolatablePreProcessor into a new BaseInterpolatablePreProcessor, and defined a new OTFInterpolatablePreProcessor. The interpolatable pre-processors take an optional Instantiator instance, and pass that on to interpolatable filters so they can generate glyph instances on the fly. They also attempt to convert a list of non-interpolatable filters to an equivalent interpolatable filter (e.g. DecomposeTransformedComponentsFilters => DecomposeTransformedComponentsIFilter) so that client code (fontmake) that sets up filters doesn't need to change.
Thanks to our new shiny interpolatable DecomposeComponentsIFilter, our test variable CFF2 font looks as it should have been from day one! The test font contained a composite glyph 'edotabove' which used 'e' as one of its component, and the latter's glyph in turn defined one extra master at the middle (in a sparse layer); since in CFF fonts we have to decompose all composites, before we would simply ignore that 'e' had this intermediate master and the decomposed 'edotabove' would have one fewer set of deltas and thus look incorrectly and unlike 'e'. Now it is decomposed correctly, with the intermediate master 'bubbling up' from the 'e' component to the 'edotabove' composite glyph.
…sing At some point we decided to skip missing components when decomposing composites and just issue a logging warning. But that was not a good idea, as it hides other font bugs (or even code bugs), and it is no longer needed because we now support sparse composite glyphs. We may reintroduce the skip behavior as an option if need be.
and use design coordinates for source locations as well as interpolated layers, to aid debugging
anthrotype
force-pushed
the
interpolatable-filters
branch
from
March 20, 2024 17:39
d499a31
to
b2dbba4
Compare
this will exercise the interpolatable FlattenComponentsIFilter
anthrotype
force-pushed
the
interpolatable-filters
branch
from
March 20, 2024 17:39
b2dbba4
to
c921318
Compare
anthrotype
added a commit
to googlefonts/glyphsLib
that referenced
this pull request
Mar 25, 2024
ufo2ft can now interpolate components or composite glyphs as needed at build time while decomposing composites, as well as add empty component placeholders when keeping the glyphs as composites (as of googlefonts/ufo2ft#826). Therefore glyphsLib does not need any more to add intermediate layers to the component base glyphs when these are defined at fewer master locations than the composite glyphs they are referenced from.
schriftgestalt
pushed a commit
to googlefonts/glyphsLib
that referenced
this pull request
Oct 23, 2024
ufo2ft can now interpolate components or composite glyphs as needed at build time while decomposing composites, as well as add empty component placeholders when keeping the glyphs as composites (as of googlefonts/ufo2ft#826). Therefore glyphsLib does not need any more to add intermediate layers to the component base glyphs when these are defined at fewer master locations than the composite glyphs they are referenced from.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
googlefonts/glyphsLib#954
So.. In Glyphs.app there's a nifty feature which I'll call "sparse" composite glyph for lack of better name, whereby you can have a composite glyph that defines additional or fewer masters (sources, layers, whatever you call it) than some of its component glyphs.
Eg. imagine a font with 1 weight axis and 3 masters, Regular (default), Medium and Bold; the "Agrave" composite glyph references "A" and "gravecomb" as components; "A" and "gravecomb" are only defined for Regular and Bold, but not Medium; in the Medium master the "Agrave" glyph needed some adjustments to the component offsets (or maybe the advance width).
Or, another example, you could have the "Agrave" (composite) and "gravecomb" (component) only be defined for Regular and Bold masters, while "A" (component) is also defined in the Medium master (e.g. contours needed some adjustments), so you have a composite glyph "Agrave" defined in 2 masters using a component defined in 3 masters.
This usually works fine for TrueType fonts, however problems arise when you need to decompose the composite glyph (for CFF fonts, or for TTF when contours and components are mixed, or components have different 2x2 transforms across masters). If you decompose these sparse composite glyphs without taking into account the fact that they have incomplete or additional master definitions, you either end up with a decomposed simple glyph that doesn't look exactly as the composite did, or the compilation fails because some components appear to be missing in some masters...
In order to fix this, it is necessary to interpolate the glyphs for the missing locations while or just before decomposing the sparse composite glyph, which is why I added the new instantiator module originally in fontmake (#825).
More precisely, in the first case (composite with more masters than its components), we need to interpolate the component glyphs on-the-fly at the missing locations while decomposing the composite glyph.
For the second case (composite with fewer masters than its component[s]), we first traverse all the components across all masters and collect the set of locations in which they may be defined; then we interpolate our composite glyph at the new locations that it doesn't already define, and finally we proceed with decomposing it.
Right now, fontmake requires the font developer to manually ensure that all the composite glyphs and all their components are "aligned", i.e. are exactly defined for the same set of masters.
I hope you'll find this useful, as this is taking me more than I had anticipated. Initially I started with fixing it in glyphsLib, then of course I got tangled up in its complexity and decided I would rather fix in ufo2ft so this would work regardless of input source format.
Have a nice weekend!