Skip to content

Fix left-side bearing for variable fonts#27

Merged
laurmaedje merged 1 commit into
mainfrom
fix-lsb
Jun 3, 2026
Merged

Fix left-side bearing for variable fonts#27
laurmaedje merged 1 commit into
mainfrom
fix-lsb

Conversation

@laurmaedje
Copy link
Copy Markdown
Member

When interjecting with skrifa, we now derive the LSB from the resulting bounding box rather than from the font's metrics, because the latter does not always agree with the xMin of the fresh outline we've generated. The OpenType spec heavily advises xMin and LSB to match (it actually requires it for variable fonts or when head.flags bit 1 is set).

If LSB != xMin, glyphs get repositioned by PDF readers (including hayro) and the kerning gets very wonky. In hayro, this happens because skrifa appears to shift the entire outline based on the delta between LSB and xMin. ttf-parser doesn't seem to care about LSB at all...

Previously, there was the following comment:

Note that for variable fonts, our left side bearing points don't seem to match the ones from fonttools (they use some different technique for deriving it which isn't reflected in skrifa's API), but I think that this shouldn't really be relevant in the context of PDF.

I updated the test references, but I'm not sure how to validate whether the output now matches fonttools...

In any case, here's an example of a before/after when integrated into Typst (with Mona Sans VF).

Before After
Bildschirmfoto 2026-06-03 um 12 36 47 Bildschirmfoto 2026-06-03 um 12 36 49

As for the implementation, I've rewired things a bit to avoid having to recompute the bounding box in horizontal_metrics. I'm not super happy with the fact that the custom_hmtx accumulation relies on subset_with being called in the correct order, but at the same time I tried to keep the fix minimally invasive. I'm open to suggestions.

@laurmaedje laurmaedje requested a review from LaurenzV June 3, 2026 10:42
@LaurenzV
Copy link
Copy Markdown
Collaborator

LaurenzV commented Jun 3, 2026

I think you just need to set this const FONT_TOOLS_REF: bool = false;

to true, and then rerun.

@laurmaedje
Copy link
Copy Markdown
Member Author

For Cantarell (CFF2), the values are still different. But fonttools subsetting also kept the CFF2 outlines while we converted to glyf, so I'm not sure we can expect them to be the same. The bounding box is a control point bounding box after all and CFF2 outlines work quite a bit differently.

Meanwhile, for Noto Sans Regular (glyf), the new values match the fonttools output. That seems like this change is on the right track!

Copy link
Copy Markdown
Collaborator

@LaurenzV LaurenzV left a comment

Choose a reason for hiding this comment

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

To be honest I don't really have the context on the whole xmin/lsb thing anymore, but since it makes PDFs work and also matches fonttools I think this should be the right thing to do!

@laurmaedje laurmaedje merged commit c1d3a1c into main Jun 3, 2026
6 checks passed
@laurmaedje laurmaedje deleted the fix-lsb branch June 4, 2026 10:44
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