Skip to content

Corner component placement - #2223

Merged
cmyr merged 4 commits into
mainfrom
corner-component-placement
Oct 8, 2026
Merged

cmyr merged 4 commits into
mainfrom
corner-component-placement

Conversation

@cmyr

@cmyr cmyr commented Oct 7, 2026

Copy link
Copy Markdown
Member

this is the fontc side of googlefonts/glyphsLib#1203, which means we match Glyphs.app on all of our 177 test cases (two of which are allowed off-by-ones, presumably rounding differences).

This is a huge improvement from the previous implementation, which was matching on ~40 of 177 cases.

For visualization of the previously failing cases, see https://www.cmyr.net/artifacts/corner-components.html.

@cmyr
cmyr added this pull request to stack #2224 October 7, 2026 19:38
Base automatically changed from corner-component-tests to main October 8, 2026 09:40
cmyr added 2 commits October 8, 2026 10:40
Port of googlefonts/glyphsLib#1200 and its follow-up,
corner-component-more. We assumed every corner was drawn with its
first node on +y and its last on +x, and ignored left and right
anchors, so corners drawn any other way were misplaced, often badly
(Plex Sans KR, Alkatra, Aoboshi One, Iansui, Inconsolata).

With this patch we fit corners as Glyphs 3.5 does, quirks included,
and match it on all but one of the 177 test cases; real_aoboshi_g
needs open corners erased first. Only the first corner on a node is
applied, as in Glyphs, and a corner we can't apply, because its path
is missing or it sits on an off-curve node or a quadratic, is skipped
with a warning rather than failing the whole font, so Aoboshi One
loads.
Glyphs erases the open corners in all of a glyph's closed paths before
applying corners to it. Where a corner sits on the start of an open
corner's line, it ends up on the erased corner; where it sits on the
line's end, it's lost along with the node. We only erased open corners
later, in fontir.

With this patch we erase them first, as glyphsLib's
corner-component-more does, and match Glyphs on real_aoboshi_g. Of our
corner sources, only Aoboshi One's G ends up different; in Solway, the
open corners are just erased earlier.
@anthrotype
anthrotype force-pushed the corner-component-placement branch from 795e6a0 to 999319a Compare October 8, 2026 09:40
Comment thread glyphs-reader/src/corner_components.rs Outdated
Comment on lines +426 to +429
self.nodes.remove(p1.max(p2));
self.nodes.remove(p1.min(p2));
let idx = point_idx - removed_before;
self.nodes[idx].node_type = NodeType::Line;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This turns Libre Franklin Italic into a build failure. When the corner reaches past the start of the curve we drop both handles and make the node a Line, and that happens per master: in haabkhasian-cy it does in Bold Italic but not in Thin Italic, so the masters no longer have the same point structure and fontbe rejects the glyph ("'haabkhasian-cy.BRACKET.varAlt01' has interpolation-incompatible paths"). It compiles on main, and the target is "identical" in last night's crater.

glyphsLib fixed this in 10303a46 (part of googlefonts/glyphsLib#1203): keep the curve and put the handles on the line at 1/3 and 2/3 (otRound), so the outline is the same and the point structure doesn't change. Could you port that, along with its test_straightened_instroke_keeps_its_handles?

if corner_hints.is_empty() {
return Ok(());
}
let corner_hints = erase_open_corners(layer, corner_hints);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fontir erases open corners a second time after this; glyphsLib stops that in googlefonts/glyphsLib@bf46fb1e.

@anthrotype anthrotype left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM apart from the two above comments

cmyr added 2 commits October 8, 2026 10:56
Where a corner's cut runs past the start of a curved instroke, Glyphs
makes the instroke a line. When that happens in only some masters, as
in Libre Franklin Italic haabkhasian-cy, the masters end up with
different numbers of points and the variable build fails.

With this patch, we keep the stroke a curve that draws the same line,
with its handles at a third and two thirds of the way along, as
glyphsLib does (googlefonts/glyphsLib#1203).
Since the previous commits we erase open corners before applying
corners, as Glyphs does, but glyphs2fontir still erased them again
afterwards. That erases spurs that corners leave, but only in the
masters where the spur's neighbours cross enough to count as an open
corner, which breaks compatibility (Bellota m, n and p, Playfair Italic
Y, among others). Glyphs doesn't erase again once the corners are on.

With this patch, a layer records that its open corners were erased,
and glyphs2fontir leaves it alone, as glyphsLib does
(googlefonts/glyphsLib#1203).
@cmyr
cmyr added this pull request to the merge queue Oct 8, 2026
Merged via the queue into main with commit 7a48ea4 Oct 8, 2026
18 checks passed
@cmyr
cmyr deleted the corner-component-placement branch October 8, 2026 16:18
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

Successfully merging this pull request may close these issues.

2 participants