diff --git a/src/graph/graph.hh b/src/graph/graph.hh index 28d69c95c..ed37352e5 100644 --- a/src/graph/graph.hh +++ b/src/graph/graph.hh @@ -129,12 +129,6 @@ struct graph_t } }; - struct overflow_record_t - { - unsigned parent; - unsigned child; - }; - /* * A topological sorting of an object graph. Ordered * in reverse serialization order (first object in the @@ -548,36 +542,6 @@ struct graph_t return made_change; } - /* - * Will any offsets overflow on graph when it's serialized? - */ - bool will_overflow (hb_vector_t* overflows = nullptr) - { - if (overflows) overflows->resize (0); - update_positions (); - - for (int parent_idx = vertices_.length - 1; parent_idx >= 0; parent_idx--) - { - // Don't need to check virtual links for overflow - for (const auto& link : vertices_[parent_idx].obj.real_links) - { - int64_t offset = compute_offset (parent_idx, link); - if (is_valid_offset (offset, link)) - continue; - - if (!overflows) return true; - - overflow_record_t r; - r.parent = parent_idx; - r.child = link.objidx; - overflows->push (r); - } - } - - if (!overflows) return false; - return overflows->length; - } - void print_orphaned_nodes () { if (!DEBUG_ENABLED(SUBSET_REPACK)) return; @@ -594,35 +558,6 @@ struct graph_t } } - void print_overflows (const hb_vector_t& overflows) - { - if (!DEBUG_ENABLED(SUBSET_REPACK)) return; - - update_parents (); - int limit = 10; - for (const auto& o : overflows) - { - if (!limit--) break; - const auto& parent = vertices_[o.parent]; - const auto& child = vertices_[o.child]; - DEBUG_MSG (SUBSET_REPACK, nullptr, - " overflow from " - "%4d (%4d in, %4d out, space %2d) => " - "%4d (%4d in, %4d out, space %2d)", - o.parent, - parent.incoming_edges (), - parent.obj.real_links.length + parent.obj.virtual_links.length, - space_for (o.parent), - o.child, - child.incoming_edges (), - child.obj.real_links.length + child.obj.virtual_links.length, - space_for (o.child)); - } - if (overflows.length > 10) { - DEBUG_MSG (SUBSET_REPACK, nullptr, " ... plus %d more overflows.", overflows.length - 10); - } - } - unsigned num_roots_for_space (unsigned space) const { return num_roots_for_space_[space]; @@ -710,6 +645,7 @@ struct graph_t bool check_success (bool success) { return this->successful && (success || ((void) err_other_error (), false)); } + public: /* * Creates a map from objid to # of incoming edges. */ @@ -818,52 +754,7 @@ struct graph_t distance_invalid = false; } - int64_t compute_offset ( - unsigned parent_idx, - const hb_serialize_context_t::object_t::link_t& link) const - { - const auto& parent = vertices_[parent_idx]; - const auto& child = vertices_[link.objidx]; - int64_t offset = 0; - switch ((hb_serialize_context_t::whence_t) link.whence) { - case hb_serialize_context_t::whence_t::Head: - offset = child.start - parent.start; break; - case hb_serialize_context_t::whence_t::Tail: - offset = child.start - parent.end; break; - case hb_serialize_context_t::whence_t::Absolute: - offset = child.start; break; - } - - assert (offset >= link.bias); - offset -= link.bias; - return offset; - } - - bool is_valid_offset (int64_t offset, - const hb_serialize_context_t::object_t::link_t& link) const - { - if (unlikely (!link.width)) - // Virtual links can't overflow. - return link.is_signed || offset >= 0; - - if (link.is_signed) - { - if (link.width == 4) - return offset >= -((int64_t) 1 << 31) && offset < ((int64_t) 1 << 31); - else - return offset >= -(1 << 15) && offset < (1 << 15); - } - else - { - if (link.width == 4) - return offset >= 0 && offset < ((int64_t) 1 << 32); - else if (link.width == 3) - return offset >= 0 && offset < ((int32_t) 1 << 24); - else - return offset >= 0 && offset < (1 << 16); - } - } - + private: /* * Updates a link in the graph to point to a different object. Corrects the * parents vector on the previous and new child nodes. diff --git a/src/graph/serialize.hh b/src/graph/serialize.hh index 1c9abd157..ecc6cc5ae 100644 --- a/src/graph/serialize.hh +++ b/src/graph/serialize.hh @@ -29,6 +29,125 @@ namespace graph { +struct overflow_record_t +{ + unsigned parent; + unsigned child; +}; + +inline +int64_t compute_offset ( + const graph_t& graph, + unsigned parent_idx, + const hb_serialize_context_t::object_t::link_t& link) +{ + const auto& parent = graph.vertices_[parent_idx]; + const auto& child = graph.vertices_[link.objidx]; + int64_t offset = 0; + switch ((hb_serialize_context_t::whence_t) link.whence) { + case hb_serialize_context_t::whence_t::Head: + offset = child.start - parent.start; break; + case hb_serialize_context_t::whence_t::Tail: + offset = child.start - parent.end; break; + case hb_serialize_context_t::whence_t::Absolute: + offset = child.start; break; + } + + assert (offset >= link.bias); + offset -= link.bias; + return offset; +} + +inline +bool is_valid_offset (int64_t offset, + const hb_serialize_context_t::object_t::link_t& link) +{ + if (unlikely (!link.width)) + // Virtual links can't overflow. + return link.is_signed || offset >= 0; + + if (link.is_signed) + { + if (link.width == 4) + return offset >= -((int64_t) 1 << 31) && offset < ((int64_t) 1 << 31); + else + return offset >= -(1 << 15) && offset < (1 << 15); + } + else + { + if (link.width == 4) + return offset >= 0 && offset < ((int64_t) 1 << 32); + else if (link.width == 3) + return offset >= 0 && offset < ((int32_t) 1 << 24); + else + return offset >= 0 && offset < (1 << 16); + } +} + +/* + * Will any offsets overflow on graph when it's serialized? + */ +inline bool +will_overflow (graph_t& graph, + hb_vector_t* overflows = nullptr) +{ + if (overflows) overflows->resize (0); + graph.update_positions (); + + const auto& vertices = graph.vertices_; + for (int parent_idx = vertices.length - 1; parent_idx >= 0; parent_idx--) + { + // Don't need to check virtual links for overflow + for (const auto& link : vertices[parent_idx].obj.real_links) + { + int64_t offset = compute_offset (graph, parent_idx, link); + if (is_valid_offset (offset, link)) + continue; + + if (!overflows) return true; + + overflow_record_t r; + r.parent = parent_idx; + r.child = link.objidx; + overflows->push (r); + } + } + + if (!overflows) return false; + return overflows->length; +} + +inline +void print_overflows (graph_t& graph, + const hb_vector_t& overflows) +{ + if (!DEBUG_ENABLED(SUBSET_REPACK)) return; + + graph.update_parents (); + int limit = 10; + for (const auto& o : overflows) + { + if (!limit--) break; + const auto& parent = graph.vertices_[o.parent]; + const auto& child = graph.vertices_[o.child]; + DEBUG_MSG (SUBSET_REPACK, nullptr, + " overflow from " + "%4d (%4d in, %4d out, space %2d) => " + "%4d (%4d in, %4d out, space %2d)", + o.parent, + parent.incoming_edges (), + parent.obj.real_links.length + parent.obj.virtual_links.length, + graph.space_for (o.parent), + o.child, + child.incoming_edges (), + child.obj.real_links.length + child.obj.virtual_links.length, + graph.space_for (o.child)); + } + if (overflows.length > 10) { + DEBUG_MSG (SUBSET_REPACK, nullptr, " ... plus %d more overflows.", overflows.length - 10); + } +} + template inline void serialize_link_of_type (const hb_serialize_context_t::object_t::link_t& link, char* head, diff --git a/src/hb-repacker.hh b/src/hb-repacker.hh index f27bca581..683a441ec 100644 --- a/src/hb-repacker.hh +++ b/src/hb-repacker.hh @@ -43,7 +43,7 @@ using graph::graph_t; */ static inline -bool _try_isolating_subgraphs (const hb_vector_t& overflows, +bool _try_isolating_subgraphs (const hb_vector_t& overflows, graph_t& sorted_graph) { unsigned space = 0; @@ -51,7 +51,7 @@ bool _try_isolating_subgraphs (const hb_vector_t& ov for (int i = overflows.length - 1; i >= 0; i--) { - const graph_t::overflow_record_t& r = overflows[i]; + const graph::overflow_record_t& r = overflows[i]; unsigned root; unsigned overflow_space = sorted_graph.space_for (r.parent, &root); @@ -93,7 +93,7 @@ bool _try_isolating_subgraphs (const hb_vector_t& ov } static inline -bool _process_overflows (const hb_vector_t& overflows, +bool _process_overflows (const hb_vector_t& overflows, hb_set_t& priority_bumped_parents, graph_t& sorted_graph) { @@ -102,7 +102,7 @@ bool _process_overflows (const hb_vector_t& overflow // Try resolving the furthest overflows first. for (int i = overflows.length - 1; i >= 0; i--) { - const graph_t::overflow_record_t& r = overflows[i]; + const graph::overflow_record_t& r = overflows[i]; const auto& child = sorted_graph.vertices_[r.child]; if (child.is_shared ()) { @@ -161,14 +161,15 @@ hb_resolve_overflows (const T& packed, graph_t sorted_graph (packed); sorted_graph.sort_shortest_distance (); - if (!sorted_graph.will_overflow ()) + bool will_overflow = graph::will_overflow (sorted_graph); + if (!will_overflow) { return graph::serialize (sorted_graph); } if ((table_tag == HB_OT_TAG_GPOS || table_tag == HB_OT_TAG_GSUB) - && sorted_graph.will_overflow ()) + && will_overflow) { DEBUG_MSG (SUBSET_REPACK, nullptr, "Assigning spaces to 32 bit subgraphs."); if (sorted_graph.assign_32bit_spaces ()) @@ -176,13 +177,13 @@ hb_resolve_overflows (const T& packed, } unsigned round = 0; - hb_vector_t overflows; + hb_vector_t overflows; // TODO(garretrieger): select a good limit for max rounds. while (!sorted_graph.in_error () - && sorted_graph.will_overflow (&overflows) + && graph::will_overflow (sorted_graph, &overflows) && round++ < max_rounds) { DEBUG_MSG (SUBSET_REPACK, nullptr, "=== Overflow resolution round %d ===", round); - sorted_graph.print_overflows (overflows); + print_overflows (sorted_graph, overflows); hb_set_t priority_bumped_parents; @@ -204,7 +205,7 @@ hb_resolve_overflows (const T& packed, return nullptr; } - if (sorted_graph.will_overflow ()) + if (graph::will_overflow (sorted_graph)) { DEBUG_MSG (SUBSET_REPACK, nullptr, "Offset overflow resolution failed."); return nullptr; diff --git a/src/test-repacker.cc b/src/test-repacker.cc index 92727c834..69863b562 100644 --- a/src/test-repacker.cc +++ b/src/test-repacker.cc @@ -949,7 +949,7 @@ static void test_will_overflow_1 () populate_serializer_complex_2 (&c); graph_t graph (c.object_graph ()); - assert (!graph.will_overflow (nullptr)); + assert (!graph::will_overflow (graph, nullptr)); free (buffer); } @@ -962,7 +962,7 @@ static void test_will_overflow_2 () populate_serializer_with_overflow (&c); graph_t graph (c.object_graph ()); - assert (graph.will_overflow (nullptr)); + assert (graph::will_overflow (graph, nullptr)); free (buffer); } @@ -975,7 +975,7 @@ static void test_will_overflow_3 () populate_serializer_with_dedup_overflow (&c); graph_t graph (c.object_graph ()); - assert (graph.will_overflow (nullptr)); + assert (graph::will_overflow (graph, nullptr)); free (buffer); }