Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A modest proposal for more sophisticated components handling #3181

Open
davelab6 opened this issue Feb 26, 2021 · 6 comments
Open

A modest proposal for more sophisticated components handling #3181

davelab6 opened this issue Feb 26, 2021 · 6 comments
Assignees

Comments

@davelab6
Copy link
Contributor

The GF API distinguishes between various user agents and returns different font binaries with UA specific optimizations.

It also mostly serve TrueType flavor OpenType fonts, and all the VFs are TTF flavor to date.

One of the differences between CFF and TTF is their handling of components and overlaps.

The "C" in CFF stands for Compressed, and that compression is partially due to "subroutinization" - reusing fragments of outline contours that are the same - and so in CFF (unlike CFF2) no overlaps are allowed, and no symbolic references to other glyphs are allowed. (@behdad 's https://github.com/googlefonts/compreffor is one python implementation of this, I believe there is another libre implementation in FDK but it might be in C.)

TTF is uncompressed (thus EOT/WOFF/2) but allows overlapping contours, components, overlapping components, but not a mix of contours and components; and it also allows nested components.

Usually the font editor allows font authors to mix contours and components, and then when compiling the font binary, will do the right thing for the flavor being compiled to.

However, there are rendering issues with nested components, and this has been an issue for variable fonts.

Amusingly @anthrotype said last November,

quite depressing that in 2020 we can't still have nested glyf components

#2961 (comment)

Potentially the API could be more sophisticated about this, and have the 'upstream' TTFs that FB checks be checked TO USE nested components, and then 'downstream' the API system could cut versions of the fonts that unnest the components, increasing the file size, but only serve them to the systems that need them to be that way (and can carry the file size increase), like the ZIP downloads which get installed and used locally, and to print things.

Since the 100s of upstream projects have a variety of approaches to components, I also wonder we could have a fonttools snippet (that maybe reuses parts of compreffor) to 're-nest' TTFs, resulting in decreased file sizes. @twardoch 's https://github.com/twardoch/ttfdiet was a similar tool that slims down file sizes with a different approach, but the same upstream/downstream sophistication remains potent potential.

But before thinking further, I realise there are a few things about this opportunity that can be quantified - e.g., I have no idea how many TTFs we have that use components at all, or use them but none are nested, or some are nested. Since @RosaWagner filed #2961 we have checks for some of this, but it would be helpful to understand the opportunity a bit deeper; e.g. of those 3 categories (none, some flat, some nested), what are the filesizes of the fonts and are there patterns there; and if we have a un-nest and re-nest tool (even if it isn't outputting production grade TTFs), what are the file sizes and are there patterns there.

Ultimately this can result in "WARN" style check results that warn type designers they might want to rethink their approach to components, and provide the dogma about what the tradeoffs are.

@davelab6 davelab6 added this to the 0.8.0 milestone Feb 26, 2021
@felipesanches
Copy link
Collaborator

if it is so nicely well-explained then it is not a dogma ;-)

I like the idea of generating a report of these things so that we have a better picture. I will try to come up with something

@felipesanches felipesanches self-assigned this Feb 26, 2021
@moyogo
Copy link
Contributor

moyogo commented Feb 26, 2021

Potentially the API could be more sophisticated about this, and have the 'upstream' TTFs that FB checks be checked TO USE nested components, and then 'downstream' the API system could cut versions of the fonts that unnest the components, increasing the file size, but only serve them to the systems that need them to be that way (and can carry the file size increase), like the ZIP downloads which get installed and used locally, and to print things.

This is a difficult one. Systems that don't handle nested components properly are typically printers.

@rsheeter
Copy link

Note that CFF tends to compress (woff2) worse when subroutinized; brotli does a better job than the subroutinizer.
What is the most efficient (preferably low cost) way to confirm/deny the impact increased use of components might have?

Do we have to alter designer behavior or can we just have a smarter compiler? - if a compiler can do it that's preferable even if it's significantly more work. One could imagine a model where GF ingresses sources rather than binaries and compiles all the variants it wants. Compiler gets smarter, everything improves.

@davelab6
Copy link
Contributor Author

davelab6 commented Mar 1, 2021

Systems that don't handle nested components properly are typically printers.

Right, that's why the downloaded ZIPs that are installed by end users would not include them, and file size doesn't matter in that case.

GF ingresses sources

We are slowly building towards being ready for this :)

@arrowtype
Copy link
Contributor

arrowtype commented Mar 10, 2021

I like this proposal in general, as I also wish that supporting printer software didn’t mean making web fonts bigger.

What is the most efficient (preferably low cost) way to confirm/deny the impact increased use of components might have?

If you compare Recursive releases for before/after nested & transformed components were decomposed (release 1.069 vs 1.070), there are a few data points:

  • For the full variable font as a woff2, the file size went from 577KB to 701KB
  • For the Google Fonts Latin Basic subset woff2, size went from 289KB to 292KB
  • For static woff2 files (full charset), sizes went from 92–114KB to 96–122KB
  • The full font, as an uncompressed TTF, went from 1.7MB to 2.3MB

The Inter project had something like a 25–40% size reduction after we fixed an overly-aggressive decomposition build step, when onboarding it for Google Fonts. That PR could be dug up, if relevant.

One could also run a FontTools script to decompose all components in TTFs (e.g. across the whole GF library), and see the size impacts.

Systems that don't handle nested components properly are typically printers.

A question: do we know whether nested components cause issues when printed from the web? I assume they would, as I doubt that something like decomposition happens in the printing process. But, maybe it could... Even if printing from the web isn’t that common, it’s common enough that I wouldn’t want it to be broken.

@Lorp
Copy link

Lorp commented Jun 1, 2021

In 2010 I wrote, as part of MyFonts’ webfont service, a TTF componentizer which included nesting. At that time no browser supported OTF, so we were converting OTF to TTF on the fly (and the tool we used for that was generating TTFs of simple glyphs). I was very pleased how the componentizer was working reliably to an unlimited nesting depth, but was soon surprised & disappointed to find that nesting was not supported on Apple OSes of the time. We disabled nesting, and found only only a small penalty in size: well under 5% IIRC.

@felipesanches felipesanches modified the milestones: 0.8.0, 0.8.1 Jul 21, 2021
@felipesanches felipesanches modified the milestones: 0.8.1, 0.8.2 Aug 12, 2021
@felipesanches felipesanches modified the milestones: 0.8.2, 0.8.6 Sep 1, 2021
@felipesanches felipesanches modified the milestones: 0.8.6, 0.8.10 Dec 15, 2021
@felipesanches felipesanches modified the milestones: 0.8.10, 0.8.17 Jun 24, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants