[subset] Prepare the repacker for handling 24bit offsets in GSUB/GPOS.

The boring expansion (https://github.com/be-fonts/boring-expansion-spec) plans to introduce 24bit offsets into GSUB/GPOS. This changes the repacker to treat 24 bit offsets similar to 32 bit offsets and assign the top level 24 bit offsets into spaces to improve packing.
This commit is contained in:
Garret Rieger 2022-07-06 18:44:40 +00:00
parent 3a722c5354
commit 401066bf3d
2 changed files with 59 additions and 16 deletions

View File

@ -264,29 +264,58 @@ struct graph_t
hb_swap (vertices_, sorted_graph);
}
/*
* Assign unique space numbers to each connected subgraph of 32 bit offset(s).
*/
bool assign_32bit_spaces ()
void find_space_roots (hb_set_t& visited, hb_set_t& roots)
{
unsigned root_index = root_idx ();
hb_set_t visited;
hb_set_t roots;
for (unsigned i = 0; i <= root_index; i++)
int root_index = (int) root_idx ();
for (int i = root_index; i >= 0; i--)
{
if (visited.has (i)) continue;
// Only real links can form 32 bit spaces
for (auto& l : vertices_[i].obj.real_links)
{
if (l.width == 4 && !l.is_signed)
if (l.is_signed || l.width < 3)
continue;
if (i == root_index && l.width == 3)
// Ignore 24bit links from the root node, this skips past the single 24bit
// pointer to the lookup list.
continue;
if (l.width == 3)
{
roots.add (l.objidx);
find_subgraph (l.objidx, visited);
// A 24bit offset forms a root, unless there is 32bit offsets somewhere
// in it's subgraph, then those become the roots instead.
hb_set_t sub_roots;
find_32bit_roots (l.objidx, sub_roots);
if (sub_roots) {
for (unsigned sub_root_idx : sub_roots) {
roots.add (sub_root_idx);
find_subgraph (sub_root_idx, visited);
}
continue;
}
}
roots.add (l.objidx);
find_subgraph (l.objidx, visited);
}
}
}
// Mark everything not in the subgraphs of 32 bit roots as visited.
// This prevents 32 bit subgraphs from being connected via nodes not in the 32 bit subgraphs.
/*
* Assign unique space numbers to each connected subgraph of 24 bit and/or 32 bit offset(s).
* Currently, this is implemented specifically tailored to the structure of a GPOS/GSUB
* (including with 24bit offsets) table.
*/
bool assign_spaces ()
{
hb_set_t visited;
hb_set_t roots;
find_space_roots (visited, roots);
// Mark everything not in the subgraphs of the roots as visited. This prevents
// subgraphs from being connected via nodes not in those subgraphs.
visited.invert ();
if (!roots) return false;
@ -422,6 +451,18 @@ struct graph_t
find_subgraph (link.objidx, subgraph);
}
void find_32bit_roots (unsigned node_idx, hb_set_t& found)
{
for (const auto& link : vertices_[node_idx].obj.all_links ())
{
if (!link.is_signed && link.width == 4) {
found.add (link.objidx);
continue;
}
find_32bit_roots (link.objidx, found);
}
}
/*
* duplicates all nodes in the subgraph reachable from node_idx. Does not re-assign
* links. index_map is updated with mappings from old id to new id. If a duplication has already
@ -622,7 +663,7 @@ struct graph_t
private:
/*
* Returns the numbers of incoming edges that are 32bits wide.
* Returns the numbers of incoming edges that are 24 or 32 bits wide.
*/
unsigned wide_parents (unsigned node_idx, hb_set_t& parents) const
{
@ -636,7 +677,9 @@ struct graph_t
// Only real links can be wide
for (const auto& l : vertices_[p].obj.real_links)
{
if (l.objidx == node_idx && l.width == 4 && !l.is_signed)
if (l.objidx == node_idx
&& (l.width == 3 || l.width == 4)
&& !l.is_signed)
{
count++;
parents.add (p);

View File

@ -172,7 +172,7 @@ hb_resolve_overflows (const T& packed,
&& will_overflow)
{
DEBUG_MSG (SUBSET_REPACK, nullptr, "Assigning spaces to 32 bit subgraphs.");
if (sorted_graph.assign_32bit_spaces ())
if (sorted_graph.assign_spaces ())
sorted_graph.sort_shortest_distance ();
}