2024Q4 Fonts Hangout
Or How I spent my time so far this quarter…
behdad
Boring Expansion
The Boring Expansion set of proposals that I initially circulated back in 2022 (Slides / Video) found their way through the ISO OpenFontFormat standardization process, currently at the CD (Committee Draft) stage, to become part of the standard if not challenged through DIS (Draft International Standard)..
Variable Components Yak Shaving
Variable Components are a proposed OpenType extension akin to the Glyphs app smart components. Originally, in my set of proposals, the Variable Components feature was baked into the glyf table. Adobe opposed that design and requested a separate table. Because if I implemented the feature in a new table, then the CFF2 fonts will automatically get the feature as well. I agree that is a desirable outcome, so I moved the feature into a VARC table, reusing the existing glyf/gvar or CFF2 tables for outline representation. Only the variable-component specifications for variable-composite glyphs will be encoded in the VARC table.
Testing
For testing the designs I used two proprietary Google Sans CJK font sources in the Fontra-specific rcjk source format:
Hangul
Hanzi
I used the above for testing the size & speed measurements I performed.
There exists another Hanzi source design that is more complicated, Google Sans Flex CJK. Building that one has proved to be a challenge as I will get into soon.
Compilers
I wrote a compiler for the rcjk format into a VARC table, in this project. Just van Rossum has also added his own VARC compiler using his pre-existing infrastructure. This means that we have two compilers already, to experiment with and compare notes.
Snag: gvar limitation
When Just tried to compile the more complicated Hanzi design to a TrueType-flavored VARC font, they hit a hard limit in gvar where each glyph’s header size is limited to 65,535 bytes. While that looks like a lot for a glyph’s variations header, for the font at hand, they hit it. It is not possible to work around this limit. So this was a deadend. It would require a gvar replacement to lift it. HVAC is such a replacement experiment (more later), as is Apple's still undocumented HVF table.
I’m proposing to lift this limit in the GVAR table that is in the ISO process now to enable 24bit glyph indices. FontTools PR. HarfBuzz PR. varc-rcjk compiler branch.
Make CFF2 Great Again
The CFF2 font sub-format of OpenType / OpenFontFormat was standardized in 2016. Considered dead on arrival by many, the format did not make much of an impact in the marketplace. Well, in 2024, the underdog subformat also had a comeback!
As a TrueType-flavored (ie. glyf/gvar) VARC font proved to be impossible for the complicated design, I suggested that Just tries building a VARC+CFF2 font instead. They hit a different limit of 65,535 bytes again, this time in the uint16 length member of the VariationStore data structure of the CFF2 table. This limitation however, is quite unnecessary, so I proposed lifting it.
To lift the limit, I patched FontTools (merged) and wrote a patch for OTS. All major systems seem to work when using such fonts, except that it’s possible that the Windows font installer fails the font. Using the same font as an in-memory font seems to work with DirectWrite. For that reason, Jonathan Kew is against lifting the limit in OTS unconditionally. So work remains, to add compatibility-level control in OTS, such that eg. we can say “test against OpenType 1.9” or “test against Windows 10”.
With these changes, Just was able to build a VARC+CFF2 font of the complicated Hanzi design that works with the experimental builds of HarfBuzz.
TTGlyphSet Support
Turns out the FontTools glyph drawing API didn’t support VARC+CFF2. So I fixed that.
Specializer Fix
While building the above font, Just and I also found that the operand stack use of the generated font is way above the maximum stack size allowed by the spec. For this reason, the font still failed the OTS sanitizer tool (rightfully so). I tracked down the bug to when CFF2 support was added to my CFF specializer, and fixed it.
Subroutinizer Support
For fairly comparing the file-size performance of the VARC+CFF2 font, we would need to subroutinize the resulting CFF2 table since that would typically reduce the file size, sometimes drastically. That said, in the past we have found that unsubroutinized CFF fonts compress better using WOFF2 than subroutinized. So, unsubroutinized font might be more suitable for over-the-wire delivery, while subroutinized fonts will take less disk space for system fonts.
There are two commonly used subroutinizers:
Adobe’s fast, linear-time, implementation in cffsubr,
Our compreffor, which is much slower, but typically compresses the font better.
Neither worked on the test font successfully:
For cffsubr, I first had to patch the AFDKO tx command to lift the above-mentioned limitation. Even after that, the subroutinizer failed with something about a wrong CharString.
Compreffor does not support CFF2 in fact: it was never updated. So I crudely patched it to do so. After running for 13 minutes, it tried saving the font and failed in a CharString processing stage as well.
I am not sure what’s going on. To be investigated.
Errata
While dealing with CFF2, I made a list of proposed changes. The simpler ones are progressing through the ISO standardization process already, while allowing vsindex more freely is considered a bigger architectural change that has to be done more carefully, if ever.
HVAC Experiment
The HVAC experiment was some work I did trying to speed up the loading performance of VARC fonts, by replacing the gvar table. Detailed explanation and results can be found here.
Acknowledgements
I like to thank Google Fonts for financially supporting this work. While at it, I have some spare time for new clients. Give me a shout if you need me.