googlefonts / googlefonts/fontc

Anchor propagation should skip Mark/Spacing glyphs matching Glyphs.app behavior

Open
#1,891 8 comments 0 reactions 0 assignees View on GitHub
Dominant language
Rust
Stars
193
Forks
21
Avg merge
1d 17h
Merged PRs (30d)
65

Description

After #1832 (move anchor propagation from glyphs-reader to fontir), spacing accent glyphs like acute, cedilla, tilde, ring, etc. get base anchors propagated from their combining counterparts and are then inferred as GDEF Base.

Both Glyphs.app and glyphsLib skip anchor propagation for all glyphs that already have some anchors and have category=Mark, regardless of the subcategory. So those spacing accent composite glyphs won't inherit the base anchors from their components and will not be classified as GDEF Base (nor as GDEF Mark, since they aren't combining).

fontc only skips for Mark/Nonspacing and Mark/SpacingCombining (the subcategories that map to GDEF Mark class), so Mark/Spacing glyphs fall through and anchors get propagated, leading to aforementioned diff in the GDEF.

The different GDEF classification for these glyphs often also means additional GPOS MarkToBase rules in the fontc font, corresponding to the propagated base anchors.

Example:

tilde (U+02DC) in BraahOne:
- GlyphData: category=Mark, subCategory=Spacing
- Source: composite of tildecomb, has explicit "_top" anchor, no explicit category
- tildecomb has both "_top" and "top" anchors
- Propagation copies top from tildecomb -> tilde now has a non-mark anchor -> inferred as GDEF Base

fontmake doesn't have this problem because glyphsLib checks category == "Mark" (any subcategory) to skip propagation.

The fontc crater run comparing pre- and post-merge shows about 26 (unique) fonts lost identical status. Analysis confirms 24 of these have Mark/Spacing glyphs wrongly classified as GDEF Base:

- Alata.glyphs
- BonaNova-Italic.glyphs
- BonaNova.glyphs
- BraahOne.glyphs
- Comme.glyphs
- Commissioner.glyphs
- EBGaramond-Italic.glyphs
- Gidole-Regular.glyphspackage
- Karla-Italic.glyphs
- Karla.glyphs
- Lora-Italic.glyphs
- Lora.glyphs
- Merriweather-Italic.glyphspackage
- NotoSerif-Italic.glyphspackage
- PontanoSans.glyphs
- RadioCanadaBig-Italic.glyphs
- RedditMono.glyphs
- Savate-Italic.glyphs
- Savate.glyphs
- SeymourOne.glyphs
- Tac.glyphs
- VictorMono-Italic.glyphs
- VictorMono.glyphs
- Young-Serif.glyphs

In fontir/src/propagate_anchors.rs, the early return that skips propagation for marks checks `is_mark`, which only covers GDEF Mark class (Nonspacing + SpacingCombining), because the source-level definition of category=Mark (which is entirely Glyphs-specific) is no longer available in the context of fontir, we have only access to Marks in the sense of GDEF (true combining marks).

```rust
if !existing_anchors.is_empty() && is_mark {
return origin_adjusted_anchors(existing_anchors).collect();
}
```

Glyphs.app and glyphsLib have the luxury of having access to source-level categories (and subCategories) and use the broader category == "Mark" check, which also covers Mark/Spacing. When anchor propagation was in glyphs-reader, fontc itself was doing the same, because in that context the category=Mark was readily available.

A possible fix could be to propagate the set of glyphs with source-level category=Mark through `PreliminaryGdefCategories` so that `propagate_all_anchors` can skip them, matching Glyphs.app behavior...
However this is ugly and introduces something that is source-format specific in the IR which is supposed to be source-format agnostic.

Another way to fix it is in glyphsLib itself (do like fontc, only skip if is both Mark _and_ Nonspacing+SpacingCombining) and accept that we'd diverge from Glyphs.app (supposedly the reference implementation) in this regard.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start in fontir/src/propagate_anchors.rs and trace propagate_all_anchors, focusing on the existing_anchors/is_mark early return and PreliminaryGdefCategories. Compare the behavior with the issue’s Glyphs.app and glyphsLib description, then verify that Mark/Spacing glyphs no longer receive propagated base anchors or produce the reported GDEF and GPOS differences.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers, devtools
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.