googlefonts/oxidize

font graph structure & packing

Closed this issue · 7 comments

cmyr commented

So I've been digging into compilation, and I'm trying to get a better understanding of the structure of the graph in various tables.

In particular, I'm trying to figure out where we can define independent sub-graphs; that is, where in the font file we can define barriers across which sharing does not occur.

What are some of the more complicated/densely connected graphs? In hb-repacker, is it common for subtables to share a child? (for instance a coverage table?) Are there other examples of sibling tables sharing a child, in such a way that they refer to it with different relative offsets? (As opposed to, say, cmap, where multiple records might point to the same subtable, but with the same relative offset.)

cc @garretrieger, who is probably best equipped to answer this question?

In hb-repacker, is it common for subtables to share a child? (for instance a coverage table?) Are there other examples of sibling tables sharing a child, in such a way that they refer to it with different relative offsets?

Yes, in tables that are designed in the style of GSUB/GPOS/GDEF/BASE/JSTF, any byte-sharing is allowed by way of relative offsets as long as the compiler can figure it out. Note that the objects of different types can be shared as well, if they refer to the same bytes. For example, an empty ScriptList, FeatureList, and LookupList, all can be represented by just '\00\00' and as such can be shared.

Harfbuzz and fonttools both attempt to maximize sharing and will by default share any subtable's it's able too. During overflow resolution we may disable some sharing (on a per subtable basis) if needed to fix overflows.

In harfbuzz sharing is resolved every time a subtable is added to the serialization buffer. If the buffer already contains a duplicate subtable the one being added will instead re-use the existing subtable.

cmyr commented

Okay thanks, I will treat actual top-level table boundaries as the only hard barrier for sharing.

There is one case to be aware of that needs special handling: in Ligature subtables the coverage table must always be packed last. The reason for this is that some old versions of windows 7 will fail to render the font if it's not. See: harfbuzz/harfbuzz@49c9392 in harfbuzz we handle this by adding virtual links that enforce the desired ordering. These virtual links are treated as offsets by the repacker and thus it will make sure and children of a virtual link are placed after the parent of that link.

FontTools also implements this fix: https://github.com/fonttools/fonttools/blob/main/Lib/fontTools/ttLib/tables/otBase.py#L380

Is this question adequately answered? Should we summarize the rules to an md then close?

cmyr commented

This is answered, yes. Not sure where this should live, I could imagine mentioning it in https://github.com/harfbuzz/harfbuzz/blob/main/docs/repacker.md?