From 401066bf3d20bf8913d340811fd1c61ed65bb5f1 Mon Sep 17 00:00:00 2001 From: Garret Rieger Date: Wed, 6 Jul 2022 18:44:40 +0000 Subject: [PATCH] [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. --- src/graph/graph.hh | 73 ++++++++++++++++++++++++++++++++++++---------- src/hb-repacker.hh | 2 +- 2 files changed, 59 insertions(+), 16 deletions(-) diff --git a/src/graph/graph.hh b/src/graph/graph.hh index 52ca9dd14..88a9e4e60 100644 --- a/src/graph/graph.hh +++ b/src/graph/graph.hh @@ -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); diff --git a/src/hb-repacker.hh b/src/hb-repacker.hh index 683a441ec..57c063111 100644 --- a/src/hb-repacker.hh +++ b/src/hb-repacker.hh @@ -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 (); }