[repacker] add the ability to move subgraphs from a shared space into their own space.
Used to resolve overflows during manual resolution.
diff --git a/src/hb-repacker.hh b/src/hb-repacker.hh
index dfe9c44..0273325 100644
--- a/src/hb-repacker.hh
+++ b/src/hb-repacker.hh
@@ -166,6 +166,7 @@
positions_invalid (true),
successful (true)
{
+ num_roots_for_space.push (1);
bool removed_nil = false;
for (unsigned i = 0; i < objects.length; i++)
{
@@ -386,7 +387,6 @@
if (!roots) return false;
- unsigned space = 0;
while (roots)
{
unsigned next = HB_SET_VALUE_INVALID;
@@ -395,11 +395,14 @@
hb_set_t connected_roots;
find_connected_nodes (next, roots, visited, connected_roots);
- space++;
+
+ unsigned next_space = this->next_space ();
+ num_roots_for_space.push (0);
for (unsigned root : connected_roots)
{
- DEBUG_MSG (SUBSET_REPACK, nullptr, "Subgraph %u gets space %u", root, space);
- vertices_[root].space = space;
+ DEBUG_MSG (SUBSET_REPACK, nullptr, "Subgraph %u gets space %u", root, next_space);
+ vertices_[root].space = next_space;
+ num_roots_for_space[next_space] = num_roots_for_space[next_space] + 1;
distance_invalid = true;
positions_invalid = true;
}
@@ -654,16 +657,58 @@
const auto& parent = vertices_[o.parent];
const auto& child = vertices_[o.child];
DEBUG_MSG (SUBSET_REPACK, nullptr,
- " overflow from %d (%d in, %d out) => %d (%d in, %d out)",
+ " overflow from "
+ "%4d (%4d in, %4d out, space %2d) => "
+ "%4d (%4d in, %4d out, space %2d)",
o.parent,
parent.incoming_edges (),
parent.obj.links.length,
+ space_for (o.parent),
o.child,
child.incoming_edges (),
- child.obj.links.length);
+ child.obj.links.length,
+ space_for (o.child));
}
}
+ unsigned num_roots_in_space (unsigned space) const
+ {
+ return num_roots_for_space[space];
+ }
+
+ unsigned next_space () const
+ {
+ return num_roots_for_space.length;
+ }
+
+ void move_to_new_space (unsigned index)
+ {
+ auto& node = vertices_[index];
+ num_roots_for_space.push (1);
+ num_roots_for_space[node.space] = num_roots_for_space[node.space] - 1;
+ node.space = num_roots_for_space.length - 1;
+ }
+
+ unsigned space_for (unsigned index, unsigned* root = nullptr) const
+ {
+ const auto& node = vertices_[index];
+ if (node.space)
+ {
+ if (root != nullptr)
+ *root = index;
+ return node.space;
+ }
+
+ if (!node.parents)
+ {
+ if (root)
+ *root = index;
+ return 0;
+ }
+
+ return space_for (node.parents[0], root);
+ }
+
void err_other_error () { this->successful = false; }
private:
@@ -976,8 +1021,34 @@
bool distance_invalid;
bool positions_invalid;
bool successful;
+ hb_vector_t<unsigned> num_roots_for_space;
};
+static bool _try_isolating_subgraphs (const hb_vector_t<graph_t::overflow_record_t>& overflows,
+ graph_t& sorted_graph)
+{
+ for (int i = overflows.length - 1; i >= 0; i--)
+ {
+ const graph_t::overflow_record_t& r = overflows[i];
+ unsigned root = 0;
+ unsigned space = sorted_graph.space_for (r.parent, &root);
+ if (!space) continue;
+ if (sorted_graph.num_roots_in_space (space) <= 1) continue;
+
+ DEBUG_MSG (SUBSET_REPACK, nullptr, "Overflow in space %d moving subgraph %d to space %d.",
+ space,
+ root,
+ sorted_graph.next_space ());
+
+ hb_set_t roots;
+ roots.add (root);
+ sorted_graph.isolate_subgraph (roots);
+ sorted_graph.move_to_new_space (root);
+ return true;
+ }
+ return false;
+}
+
static bool _process_overflows (const hb_vector_t<graph_t::overflow_record_t>& overflows,
hb_set_t& priority_bumped_parents,
graph_t& sorted_graph)
@@ -1071,10 +1142,14 @@
sorted_graph.print_overflows (overflows);
hb_set_t priority_bumped_parents;
- if (!_process_overflows (overflows, priority_bumped_parents, sorted_graph))
+
+ if (!_try_isolating_subgraphs (overflows, sorted_graph))
{
- DEBUG_MSG (SUBSET_REPACK, nullptr, "No resolution available :(");
- break;
+ if (!_process_overflows (overflows, priority_bumped_parents, sorted_graph))
+ {
+ DEBUG_MSG (SUBSET_REPACK, nullptr, "No resolution available :(");
+ break;
+ }
}
sorted_graph.sort_shortest_distance ();