googlefonts / googlefonts/fontc
fontc ignores declared filter ordering from source, runs propagateAnchors before decomposeTransformedComponents
- Dominant language
- Rust
- Stars
- 193
- Forks
- 21
- Avg merge
- 1d 20h
- Merged PRs (30d)
- 60
Description
fontc hardcodes the order of operations for ufo2ft filters rather than respecting the ordering declared in the source's `com.github.googlei18n.ufo2ft.filters` lib key. In particular, `propagateAnchors` always runs before `decomposeTransformedComponents`, regardless of what the source says.
GoogleSans declares `[decomposeTransformedComponents, propagateAnchors, flattenComponents]` and fontmake runs them in that order, but fontc runs `propagateAnchors` first. This produces different GPOS output for composite glyphs that contain transformed components.
In `fontir/src/glyph.rs`, `propagate_all_anchors` is called at line 799
https://github.com/googlefonts/fontc/blob/1a0a7526afaed77638f0d3d3d4f1a69940b06c81/fontir/src/glyph.rs#L795-L800
while `apply_optional_transformations` (which handles `DECOMPOSE_TRANSFORMED_COMPONENTS` and `FLATTEN_COMPONENTS`) runs later [at line 885](https://github.com/googlefonts/fontc/blob/1a0a7526afaed77638f0d3d3d4f1a69940b06c81/fontir/src/glyph.rs#L885). fontc reads which filters are enabled from the source, but ignores their relative ordering.
For example, GoogleSans-Italic has three Ethiopic composite glyphs (`hoa-ethiopic`/U+1207, `koa-ethiopic`/U+12AF, `oaGlottal-ethiopic`/U+2D8A) where this matters. Each is a composite of:
- One untransformed component with a `top` anchor (e.g. `ho-ethiopic`)
- One 180°-rotated component (e.g. `_geez-part-11` with transform `[-1, 0, 0, -1, dx, dy]`)
With the source's declared order (decompose first):
1. `decomposeTransformedComponents` fully decomposes the composite (mixed contour+component not allowed)
2. `propagateAnchors` sees no components → no `top` anchor propagated → no MarkToBase rule
With fontc's hardcoded order (propagate first):
1. `propagateAnchors` sees the original composite → propagates `top` from `ho-ethiopic` → MarkToBase rule emitted
2. `decomposeTransformedComponents` decomposes later (anchors already propagated)
This accounts for 3 extra MarkToBase base glyphs in fontc's GPOS that fontmake doesn't produce.
Swapping the filter order in the source to `[propagateAnchors, decomposeTransformedComponents, ...]` makes both compilers agree.
One may argue that in general it's more correct to propagate anchors for composite glyphs before decomposing them, so the anchors don't get lost in the decomposition (and the inline comment from the code referenced above says exactly that).
And for the particular glyphs affected fontc produces a better output (more mark attachments than fontmake), and the relative ordering might not have been set intentionally by the font developers. We just don't know.
At this stage, I'm just filing this for future reference in case we find similar issues in other fonts, but I don't think it should be a blocker for fontc 1.0.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.