fontations icon indicating copy to clipboard operation
fontations copied to clipboard

[read-fonts] Add per-table feature flags

Open nicoburns opened this issue 3 months ago • 11 comments

This dramatically reduces compile times for read-fonts in cases where only a few tables are needed. Examples of cases where this applies include fontdb and fontique which only need to read high-level metadata and don't need to access details like glyph outlines, shaping, or hinting data.

Notes:

  • This was also surprisingly easy to do (the tables' implementation were mostly already independent of each other.
  • It would be relatively easy to further reduce the dependencies between modules: many of the dependencies are "trivial" dependencies that only need one or two types from the module they depend on. We could pull these types out into a shared module to remove the dependency
  • I have added a CI job using "cargo hack" that runs cargo check with each feature flag to ensure that they all compile independently of each other.

nicoburns avatar Sep 13 '25 23:09 nicoburns

Any reason not to include gdef in layout?

behdad avatar Sep 13 '25 23:09 behdad

Any reason not to include gdef in layout?

It's perhaps not obvious from the names, but "layout" is actually support code tables that deal with layout rather than the group of tables that deal with layout (the feature names match file/module names the read-fonts/tables directory).

Perhaps we should make that clearer by suffixing the names with _support or _base or similar. And consider adding actual meta-features for table groups.

nicoburns avatar Sep 13 '25 23:09 nicoburns

It's perhaps not obvious from the names, but "layout" is actually support code tables that deal with layout rather than the group of tables that deal with layout (the feature names match file/module names the read-fonts/tables directory).

I suspected that. Thanks for clarifying. I think it's fine.

behdad avatar Sep 13 '25 23:09 behdad

I feel like this isn’t going to be much of a win in practice. Doing anything useful with a font is going to require at least one of skrifa or harfrust, both of which need all of the expensive-to-compile tables.

dfrg avatar Sep 19 '25 12:09 dfrg

I feel like this isn’t going to be much of a win in practice. Doing anything useful with a font is going to require at least one of skrifa or harfrust, both of which need all of the expensive-to-compile tables.

There are alternatives to these, so it could be that you combine a subset of read-fonts with ttf_parser or the C FreeType/HarfBuzz. This may be important for adoption of Fontique (although I suspect HarfRust is going to sway people to depend on read-fonts anyway). It could also be useful for things like WOFF encoding that only need to read the header + 3 or 4 tables (the rest being passed through as byte slices).


Something else I'm looking at is the possibility of splitting things up into crates. The benefit there would that it would allow tables to compile in parallel (it's possible that it also reduces overall type checking time as I believe that rustc has superlinear scaling with respect to crate size).

See (for example) the waterfall graph for the fontations port of resvg. It's compile times are completely dominated by the single-core build time of read-fonts (and to a lesser extent: skrifa, harfrust and read-fonts proc_macro deps):

Screenshot 2025-09-19 at 13 12 23

nicoburns avatar Sep 19 '25 12:09 nicoburns

Seems suspicious that we enable the traversal feature by default: https://github.com/googlefonts/fontations/blob/237e69658be195a73a27c0dab576fee6fddddcde/skrifa/Cargo.toml#L19

Does disabling that have any measurable impact on compile times?

dfrg avatar Sep 19 '25 12:09 dfrg

Seems suspicious that we enable the traversal feature by default:

https://github.com/googlefonts/fontations/blob/237e69658be195a73a27c0dab576fee6fddddcde/skrifa/Cargo.toml#L19

Does disabling that have any measurable impact on compile times?

I'm seeing a bit of variance (cargo clean && cargo build -rp skrifa --timings), but that seems to shave off about 2 (out of 8) seconds on average. Which is not bad at all for such a small fix.

nicoburns avatar Sep 19 '25 12:09 nicoburns

With traversal:

Screenshot 2025-09-19 at 13 47 01

Without traversal:

Screenshot 2025-09-19 at 13 47 11

nicoburns avatar Sep 19 '25 12:09 nicoburns

Nice! I suggest we start by removing that as a default feature and then looking for ways to improve codegen before we start cutting up the code with features or crate splitting.

dfrg avatar Sep 19 '25 12:09 dfrg

Examples of cases where this applies include fontdb and fontique which only need to read high-level metadata and don't need to access details like glyph outlines, shaping, or hinting data.

I'm curious, are there users that only need these? - the consumers that come to mind for me would also typically need at least one of shaping, subsetting, and access to outlines.

rsheeter avatar Sep 19 '25 16:09 rsheeter

looking for ways to improve codegen before we start cutting up the code with features or crate splitting.

vigorous +1, lets push on this first. Reminds me, I'm curious if anyone observes a measurable improvement from https://github.com/googlefonts/fontations/pull/1661? - wasn't a clear win when I tried it.

rsheeter avatar Sep 19 '25 16:09 rsheeter