diff --git a/src/hb-repacker.hh b/src/hb-repacker.hh index 4bc9e12f4..97b902ab0 100644 --- a/src/hb-repacker.hh +++ b/src/hb-repacker.hh @@ -336,12 +336,16 @@ struct graph_t bool made_changes = false; hb_set_t target_links; unsigned root_index = root_idx (); - for (unsigned i = 0; i < root_index; i++) + for (unsigned i = 0; i <= root_index; i++) { + if (i == root_index && root_idx () > i) + // root index may have moved due to graph modifications. + i = root_idx (); + for (auto& l : vertices_[i].obj.links) { if (l.width == 4 && !l.is_signed) - made_changes = made_changes || isolate_subgraph (l.objidx); + made_changes = isolate_subgraph (l.objidx) || made_changes; } } return made_changes; @@ -414,6 +418,8 @@ struct graph_t unsigned duplicate (unsigned node_idx) { positions_invalid = true; + distance_invalid = true; + // TODO(grieger): compute new distance instead of invalidation. auto* clone = vertices_.push (); auto& child = vertices_[node_idx]; diff --git a/src/test-repacker.cc b/src/test-repacker.cc index b06e96523..4d2f3471a 100644 --- a/src/test-repacker.cc +++ b/src/test-repacker.cc @@ -56,6 +56,14 @@ static void add_offset (unsigned id, c->add_link (*offset, id); } +static void add_wide_offset (unsigned id, + hb_serialize_context_t* c) +{ + OT::Offset32* offset = c->start_embed (); + c->extend_min (offset); + c->add_link (*offset, id); +} + static void populate_serializer_simple (hb_serialize_context_t* c) { @@ -111,6 +119,30 @@ populate_serializer_with_dedup_overflow (hb_serialize_context_t* c) c->end_serialize(); } +static void +populate_serializer_with_isolation_overflow (hb_serialize_context_t* c) +{ + std::string large_string(70000, 'a'); + c->start_serialize (); + + unsigned obj_4 = add_object ("4", 1, c); + + start_object (large_string.c_str(), 60000, c); + add_offset (obj_4, c); + unsigned obj_3 = c->pop_pack (); + + start_object (large_string.c_str(), 10000, c); + add_offset (obj_4, c); + unsigned obj_2 = c->pop_pack (); + + start_object ("1", 1, c); + add_wide_offset (obj_3, c); + add_offset (obj_2, c); + c->pop_pack (); + + c->end_serialize(); +} + static void populate_serializer_complex_1 (hb_serialize_context_t* c) { @@ -464,6 +496,30 @@ static void test_resolve_overflows_via_duplication () free (out_buffer); } + +static void test_resolve_overflows_via_isolation () +{ + size_t buffer_size = 160000; + void* buffer = malloc (buffer_size); + hb_serialize_context_t c (buffer, buffer_size); + populate_serializer_with_isolation_overflow (&c); + graph_t graph (c.object_graph ()); + + void* out_buffer = malloc (buffer_size); + hb_serialize_context_t out (out_buffer, buffer_size); + + assert (c.offset_overflow ()); + hb_resolve_overflows (c.object_graph (), HB_TAG ('G', 'S', 'U', 'B'), &out); + assert (!out.offset_overflow ()); + hb_bytes_t result = out.copy_bytes (); + assert (result.length == (1 + 10000 + 60000 + 1 + 1 + + 4 + 3 * 2)); + + result.fini (); + free (buffer); + free (out_buffer); +} + // TODO(garretrieger): update will_overflow tests to check the overflows array. // TODO(garretrieger): add a test(s) using a real font. // TODO(garretrieger): add tests for priority raising. @@ -480,6 +536,7 @@ main (int argc, char **argv) test_will_overflow_3 (); test_resolve_overflows_via_sort (); test_resolve_overflows_via_duplication (); + test_resolve_overflows_via_isolation (); test_duplicate_leaf (); test_duplicate_interior (); }