aboutsummaryrefslogtreecommitdiff
path: root/src/test-repacker.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/test-repacker.cc')
-rw-r--r--src/test-repacker.cc1218
1 files changed, 1040 insertions, 178 deletions
diff --git a/src/test-repacker.cc b/src/test-repacker.cc
index 4df063629..94ff0849a 100644
--- a/src/test-repacker.cc
+++ b/src/test-repacker.cc
@@ -28,17 +28,24 @@
#include "hb-repacker.hh"
#include "hb-open-type.hh"
+#include "graph/serialize.hh"
+
+static void extend (const char* value,
+ unsigned len,
+ hb_serialize_context_t* c)
+{
+ char* obj = c->allocate_size<char> (len);
+ hb_memcpy (obj, value, len);
+}
static void start_object(const char* tag,
unsigned len,
hb_serialize_context_t* c)
{
c->push ();
- char* obj = c->allocate_size<char> (len);
- strncpy (obj, tag, len);
+ extend (tag, len, c);
}
-
static unsigned add_object(const char* tag,
unsigned len,
hb_serialize_context_t* c)
@@ -56,6 +63,14 @@ static void add_offset (unsigned id,
c->add_link (*offset, id);
}
+static void add_24_offset (unsigned id,
+ hb_serialize_context_t* c)
+{
+ OT::Offset24* offset = c->start_embed<OT::Offset24> ();
+ c->extend_min (offset);
+ c->add_link (*offset, id);
+}
+
static void add_wide_offset (unsigned id,
hb_serialize_context_t* c)
{
@@ -64,37 +79,401 @@ static void add_wide_offset (unsigned id,
c->add_link (*offset, id);
}
+static void add_gsubgpos_header (unsigned lookup_list,
+ hb_serialize_context_t* c)
+{
+ char header[] = {
+ 0, 1, // major
+ 0, 0, // minor
+ 0, 0, // script list
+ 0, 0, // feature list
+ };
+
+ start_object (header, 8, c);
+ add_offset (lookup_list, c);
+ c->pop_pack (false);
+}
+
+static unsigned add_lookup_list (const unsigned* lookups,
+ char count,
+ hb_serialize_context_t* c)
+{
+ char lookup_count[] = {0, count};
+ start_object ((char *) &lookup_count, 2, c);
+
+ for (int i = 0; i < count; i++)
+ add_offset (lookups[i], c);
+
+ return c->pop_pack (false);
+}
+
+static void start_lookup (int8_t type,
+ int8_t num_subtables,
+ hb_serialize_context_t* c)
+{
+ char lookup[] = {
+ 0, (char)type, // type
+ 0, 0, // flag
+ 0, (char)num_subtables, // num subtables
+ };
+
+ start_object (lookup, 6, c);
+}
+
+static unsigned finish_lookup (hb_serialize_context_t* c)
+{
+ char filter[] = {0, 0};
+ extend (filter, 2, c);
+ return c->pop_pack (false);
+}
+
+static unsigned add_extension (unsigned child,
+ uint8_t type,
+ hb_serialize_context_t* c)
+{
+ char ext[] = {
+ 0, 1,
+ 0, (char) type,
+ };
+
+ start_object (ext, 4, c);
+ add_wide_offset (child, c);
+
+ return c->pop_pack (false);
+
+}
+
+// Adds coverage table fro [start, end]
+static unsigned add_coverage (unsigned start, unsigned end,
+ hb_serialize_context_t* c)
+{
+ if (end - start == 1)
+ {
+ uint8_t coverage[] = {
+ 0, 1, // format
+ 0, 2, // count
+
+ (uint8_t) ((start >> 8) & 0xFF),
+ (uint8_t) (start & 0xFF), // glyph[0]
+
+ (uint8_t) ((end >> 8) & 0xFF),
+ (uint8_t) (end & 0xFF), // glyph[1]
+ };
+ return add_object ((char*) coverage, 8, c);
+ }
+
+ uint8_t coverage[] = {
+ 0, 2, // format
+ 0, 1, // range count
+
+ (uint8_t) ((start >> 8) & 0xFF),
+ (uint8_t) (start & 0xFF), // start
+
+ (uint8_t) ((end >> 8) & 0xFF),
+ (uint8_t) (end & 0xFF), // end
+
+ 0, 0,
+ };
+ return add_object ((char*) coverage, 10, c);
+}
+
+
+template<typename It>
+static unsigned add_coverage (It it,
+ hb_serialize_context_t* c)
+{
+ c->push ();
+ OT::Layout::Common::Coverage_serialize (c, it);
+ return c->pop_pack (false);
+}
+
+// Adds a class that maps glyphs from [start_glyph, end_glyph)
+// to classes 1...n
+static unsigned add_class_def (uint16_t start_glyph,
+ uint16_t end_glyph,
+ hb_serialize_context_t* c)
+{
+ unsigned count = end_glyph - start_glyph;
+ uint8_t header[] = {
+ 0, 1, // format
+
+ (uint8_t) ((start_glyph >> 8) & 0xFF),
+ (uint8_t) (start_glyph & 0xFF), // start_glyph
+
+ (uint8_t) ((count >> 8) & 0xFF),
+ (uint8_t) (count & 0xFF), // count
+ };
+
+ start_object ((char*) header, 6, c);
+ for (uint16_t i = 1; i <= count; i++)
+ {
+ uint8_t class_value[] = {
+ (uint8_t) ((i >> 8) & 0xFF),
+ (uint8_t) (i & 0xFF), // count
+ };
+ extend ((char*) class_value, 2, c);
+ }
+
+ return c->pop_pack (false);
+}
+
+static unsigned add_pair_pos_1 (unsigned* pair_sets,
+ char count,
+ unsigned coverage,
+ hb_serialize_context_t* c)
+{
+ char format[] = {
+ 0, 1
+ };
+
+ start_object (format, 2, c);
+ add_offset (coverage, c);
+
+ char value_format[] = {
+ 0, 0,
+ 0, 0,
+ 0, count,
+ };
+ extend (value_format, 6, c);
+
+ for (char i = 0; i < count; i++)
+ add_offset (pair_sets[(unsigned) i], c);
+
+ return c->pop_pack (false);
+}
+
+static unsigned add_pair_pos_2 (unsigned starting_class,
+ unsigned coverage,
+ unsigned class_def_1, uint16_t class_def_1_count,
+ unsigned class_def_2, uint16_t class_def_2_count,
+ unsigned* device_tables,
+ hb_serialize_context_t* c)
+{
+ uint8_t format[] = {
+ 0, 2
+ };
+
+ start_object ((char*) format, 2, c);
+ add_offset (coverage, c);
+
+ unsigned num_values = 4;
+ uint8_t format1 = 0x01 | 0x02 | 0x08;
+ uint8_t format2 = 0x04;
+ if (device_tables) {
+ format2 |= 0x20;
+ num_values += 1;
+ }
+ uint8_t value_format[] = {
+ 0, format1,
+ 0, format2,
+ };
+
+ extend ((char*) value_format, 4, c);
+
+ add_offset (class_def_1, c);
+ add_offset (class_def_2, c);
+
+ uint8_t class_counts[] = {
+ (uint8_t) ((class_def_1_count >> 8) & 0xFF),
+ (uint8_t) (class_def_1_count & 0xFF),
+ (uint8_t) ((class_def_2_count >> 8) & 0xFF),
+ (uint8_t) (class_def_2_count & 0xFF),
+ };
+ extend ((char*) class_counts, 4, c);
+
+ unsigned num_bytes_per_record = class_def_2_count * num_values * 2;
+ uint8_t* record = (uint8_t*) calloc (1, num_bytes_per_record);
+ int device_index = 0;
+ for (uint16_t i = 0; i < class_def_1_count; i++)
+ {
+
+ for (uint16_t j = 0; j < class_def_2_count; j++)
+ {
+ for (int k = 0; k < 4; k++) {
+ uint8_t value[] = {
+ (uint8_t) (i + starting_class),
+ (uint8_t) (i + starting_class),
+ };
+ extend ((char*) value, 2, c);
+ }
+
+ if (device_tables) {
+ add_offset (device_tables[device_index++], c);
+ }
+ }
+ }
+ free (record);
+
+ return c->pop_pack (false);
+}
+
+static unsigned add_mark_base_pos_1 (unsigned mark_coverage,
+ unsigned base_coverage,
+ unsigned mark_array,
+ unsigned base_array,
+ unsigned class_count,
+ hb_serialize_context_t* c)
+{
+ uint8_t format[] = {
+ 0, 1
+ };
+
+ start_object ((char*) format, 2, c);
+ add_offset (mark_coverage, c);
+ add_offset (base_coverage, c);
+
+ uint8_t count[] = {
+ (uint8_t) ((class_count >> 8) & 0xFF),
+ (uint8_t) (class_count & 0xFF),
+ };
+ extend ((char*) count, 2, c);
+
+ add_offset (mark_array, c);
+ add_offset (base_array, c);
+
+ return c->pop_pack (false);
+}
+
+template<int mark_count,
+ int class_count,
+ int base_count,
+ int table_count>
+struct MarkBasePosBuffers
+{
+ unsigned base_anchors[class_count * base_count];
+ unsigned mark_anchors[mark_count];
+ uint8_t anchor_buffers[class_count * base_count + 100];
+ uint8_t class_buffer[class_count * 2];
+
+ MarkBasePosBuffers(hb_serialize_context_t* c)
+ {
+ for (unsigned i = 0; i < sizeof(anchor_buffers) / 2; i++)
+ {
+ OT::HBUINT16* value = (OT::HBUINT16*) (&anchor_buffers[2*i]);
+ *value = i;
+ }
+
+ for (unsigned i = 0; i < class_count * base_count; i++)
+ {
+ base_anchors[i] = add_object ((char*) &anchor_buffers[i], 100, c);
+ if (i < class_count) {
+ class_buffer[i*2] = (uint8_t) ((i >> 8) & 0xFF);
+ class_buffer[i*2 + 1] = (uint8_t) (i & 0xFF);
+ }
+ }
+
+ for (unsigned i = 0; i < mark_count; i++)
+ {
+ mark_anchors[i] = add_object ((char*) &anchor_buffers[i], 4, c);
+ }
+ }
+
+ unsigned create_mark_base_pos_1 (unsigned table_index, hb_serialize_context_t* c)
+ {
+ unsigned class_per_table = class_count / table_count;
+ unsigned mark_per_class = mark_count / class_count;
+ unsigned start_class = class_per_table * table_index;
+ unsigned end_class = class_per_table * (table_index + 1) - 1;
+
+ // baseArray
+ uint8_t base_count_buffer[] = {
+ (uint8_t) ((base_count >> 8) & 0xFF),
+ (uint8_t) (base_count & 0xFF),
+
+ };
+ start_object ((char*) base_count_buffer, 2, c);
+ for (unsigned base = 0; base < base_count; base++)
+ {
+ for (unsigned klass = start_class; klass <= end_class; klass++)
+ {
+ unsigned i = base * class_count + klass;
+ add_offset (base_anchors[i], c);
+ }
+ }
+ unsigned base_array = c->pop_pack (false);
+
+ // markArray
+ unsigned num_marks = class_per_table * mark_per_class;
+ uint8_t mark_count_buffer[] = {
+ (uint8_t) ((num_marks >> 8) & 0xFF),
+ (uint8_t) (num_marks & 0xFF),
+ };
+ start_object ((char*) mark_count_buffer, 2, c);
+ for (unsigned mark = 0; mark < mark_count; mark++)
+ {
+ unsigned klass = mark % class_count;
+ if (klass < start_class || klass > end_class) continue;
+ klass -= start_class;
+
+ extend ((char*) &class_buffer[2 * klass], 2, c);
+ add_offset (mark_anchors[mark], c);
+ }
+ unsigned mark_array = c->pop_pack (false);
+
+ // markCoverage
+ auto it =
+ + hb_range ((hb_codepoint_t) mark_count)
+ | hb_filter ([&] (hb_codepoint_t mark) {
+ unsigned klass = mark % class_count;
+ return klass >= class_per_table * table_index &&
+ klass < class_per_table * (table_index + 1);
+ })
+ ;
+ unsigned mark_coverage = add_coverage (it, c);
+
+ // baseCoverage
+ unsigned base_coverage = add_coverage (10, 10 + base_count - 1, c);
+
+ return add_mark_base_pos_1 (mark_coverage,
+ base_coverage,
+ mark_array,
+ base_array,
+ class_per_table,
+ c);
+ }
+};
+
+
+
+
+
static void run_resolve_overflow_test (const char* name,
hb_serialize_context_t& overflowing,
hb_serialize_context_t& expected,
- unsigned num_iterations = 0)
+ unsigned num_iterations = 0,
+ bool recalculate_extensions = false,
+ hb_tag_t tag = HB_TAG ('G', 'S', 'U', 'B'))
{
printf (">>> Testing overflowing resolution for %s\n",
name);
graph_t graph (overflowing.object_graph ());
-
- unsigned buffer_size = overflowing.end - overflowing.start;
- void* out_buffer = malloc (buffer_size);
- hb_serialize_context_t out (out_buffer, buffer_size);
-
- assert (overflowing.offset_overflow ());
- hb_resolve_overflows (overflowing.object_graph (), HB_TAG ('G', 'S', 'U', 'B'), &out, num_iterations);
- assert (!out.offset_overflow ());
- hb_bytes_t result = out.copy_bytes ();
-
- assert (!expected.offset_overflow ());
- hb_bytes_t expected_result = expected.copy_bytes ();
-
- assert (result.length == expected_result.length);
- for (unsigned i = 0; i < expected_result.length; i++)
+ graph_t expected_graph (expected.object_graph ());
+ if (graph::will_overflow (expected_graph))
{
- assert (result[i] == expected_result[i]);
+ expected_graph.assign_spaces ();
+ expected_graph.sort_shortest_distance ();
}
- result.fini ();
- expected_result.fini ();
- free (out_buffer);
+ // Check that overflow resolution succeeds
+ assert (overflowing.offset_overflow ());
+ assert (hb_resolve_graph_overflows (tag,
+ num_iterations,
+ recalculate_extensions,
+ graph));
+
+ // Check the graphs can be serialized.
+ hb_blob_t* out = graph::serialize (graph);
+ assert (out);
+ hb_blob_destroy (out);
+ out = graph::serialize (expected_graph);
+ assert (out);
+ hb_blob_destroy (out);
+
+ // Check the graphs are equivalent
+ graph.normalize ();
+ expected_graph.normalize ();
+ assert (graph == expected_graph);
}
static void add_virtual_offset (unsigned id,
@@ -139,6 +518,58 @@ populate_serializer_with_overflow (hb_serialize_context_t* c)
}
static void
+populate_serializer_with_priority_overflow (hb_serialize_context_t* c)
+{
+ std::string large_string(50000, 'a');
+ c->start_serialize<char> ();
+
+ unsigned obj_e = add_object ("e", 1, c);
+ unsigned obj_d = add_object ("d", 1, c);
+
+ start_object (large_string.c_str (), 50000, c);
+ add_offset (obj_e, c);
+ unsigned obj_c = c->pop_pack (false);
+
+ start_object (large_string.c_str (), 20000, c);
+ add_offset (obj_d, c);
+ unsigned obj_b = c->pop_pack (false);
+
+ start_object ("a", 1, c);
+ add_offset (obj_b, c);
+ add_offset (obj_c, c);
+ c->pop_pack (false);
+
+ c->end_serialize();
+}
+
+static void
+populate_serializer_with_priority_overflow_expected (hb_serialize_context_t* c)
+{
+ std::string large_string(50000, 'a');
+ c->start_serialize<char> ();
+
+ unsigned obj_e = add_object ("e", 1, c);
+
+ start_object (large_string.c_str (), 50000, c);
+ add_offset (obj_e, c);
+ unsigned obj_c = c->pop_pack (false);
+
+ unsigned obj_d = add_object ("d", 1, c);
+
+ start_object (large_string.c_str (), 20000, c);
+ add_offset (obj_d, c);
+ unsigned obj_b = c->pop_pack (false);
+
+ start_object ("a", 1, c);
+ add_offset (obj_b, c);
+ add_offset (obj_c, c);
+ c->pop_pack (false);
+
+ c->end_serialize();
+}
+
+
+static void
populate_serializer_with_dedup_overflow (hb_serialize_context_t* c)
{
std::string large_string(70000, 'a');
@@ -679,26 +1110,6 @@ populate_serializer_with_split_spaces_expected_2 (hb_serialize_context_t* c)
}
static void
-populate_serializer_complex_1 (hb_serialize_context_t* c)
-{
- c->start_serialize<char> ();
-
- unsigned obj_4 = add_object ("jkl", 3, c);
- unsigned obj_3 = add_object ("ghi", 3, c);
-
- start_object ("def", 3, c);
- add_offset (obj_3, c);
- unsigned obj_2 = c->pop_pack (false);
-
- start_object ("abc", 3, c);
- add_offset (obj_2, c);
- add_offset (obj_4, c);
- c->pop_pack (false);
-
- c->end_serialize();
-}
-
-static void
populate_serializer_complex_2 (hb_serialize_context_t* c)
{
c->start_serialize<char> ();
@@ -763,84 +1174,297 @@ populate_serializer_virtual_link (hb_serialize_context_t* c)
start_object ("b", 1, c);
add_offset (obj_d, c);
- unsigned obj_b = c->pop_pack ();
+ unsigned obj_b = c->pop_pack (false);
start_object ("e", 1, c);
add_virtual_offset (obj_b, c);
- unsigned obj_e = c->pop_pack();
+ unsigned obj_e = c->pop_pack (false);
start_object ("c", 1, c);
add_offset (obj_e, c);
- unsigned obj_c = c->pop_pack ();
+ unsigned obj_c = c->pop_pack (false);
start_object ("a", 1, c);
add_offset (obj_b, c);
add_offset (obj_c, c);
- c->pop_pack ();
+ c->pop_pack (false);
c->end_serialize();
}
-static void test_sort_kahn_1 ()
+static void
+populate_serializer_with_24_and_32_bit_offsets (hb_serialize_context_t* c)
{
- size_t buffer_size = 100;
- void* buffer = malloc (buffer_size);
- hb_serialize_context_t c (buffer, buffer_size);
- populate_serializer_complex_1 (&c);
+ std::string large_string(60000, 'a');
+ c->start_serialize<char> ();
- graph_t graph (c.object_graph ());
- graph.sort_kahn ();
+ unsigned obj_f = add_object ("f", 1, c);
+ unsigned obj_g = add_object ("g", 1, c);
+ unsigned obj_j = add_object ("j", 1, c);
+ unsigned obj_k = add_object ("k", 1, c);
+
+ start_object (large_string.c_str (), 40000, c);
+ add_offset (obj_f, c);
+ unsigned obj_c = c->pop_pack (false);
- assert(strncmp (graph.object (3).head, "abc", 3) == 0);
- assert(graph.object (3).links.length == 2);
- assert(graph.object (3).links[0].objidx == 2);
- assert(graph.object (3).links[1].objidx == 1);
+ start_object (large_string.c_str (), 40000, c);
+ add_offset (obj_g, c);
+ unsigned obj_d = c->pop_pack (false);
- assert(strncmp (graph.object (2).head, "def", 3) == 0);
- assert(graph.object (2).links.length == 1);
- assert(graph.object (2).links[0].objidx == 0);
+ start_object (large_string.c_str (), 40000, c);
+ add_offset (obj_j, c);
+ unsigned obj_h = c->pop_pack (false);
- assert(strncmp (graph.object (1).head, "jkl", 3) == 0);
- assert(graph.object (1).links.length == 0);
+ start_object (large_string.c_str (), 40000, c);
+ add_offset (obj_k, c);
+ unsigned obj_i = c->pop_pack (false);
- assert(strncmp (graph.object (0).head, "ghi", 3) == 0);
- assert(graph.object (0).links.length == 0);
+ start_object ("e", 1, c);
+ add_wide_offset (obj_h, c);
+ add_wide_offset (obj_i, c);
+ unsigned obj_e = c->pop_pack (false);
- free (buffer);
+ start_object ("b", 1, c);
+ add_24_offset (obj_c, c);
+ add_24_offset (obj_d, c);
+ add_24_offset (obj_e, c);
+ unsigned obj_b = c->pop_pack (false);
+
+ start_object ("a", 1, c);
+ add_24_offset (obj_b, c);
+ c->pop_pack (false);
+
+ c->end_serialize();
}
-static void test_sort_kahn_2 ()
+static void
+populate_serializer_with_extension_promotion (hb_serialize_context_t* c,
+ int num_extensions = 0)
{
- size_t buffer_size = 100;
- void* buffer = malloc (buffer_size);
- hb_serialize_context_t c (buffer, buffer_size);
- populate_serializer_complex_2 (&c);
+ constexpr int num_lookups = 5;
+ constexpr int num_subtables = num_lookups * 2;
+ unsigned int lookups[num_lookups];
+ unsigned int subtables[num_subtables];
+ unsigned int extensions[num_subtables];
- graph_t graph (c.object_graph ());
- graph.sort_kahn ();
+ std::string large_string(60000, 'a');
+ c->start_serialize<char> ();
- assert(strncmp (graph.object (4).head, "abc", 3) == 0);
- assert(graph.object (4).links.length == 3);
- assert(graph.object (4).links[0].objidx == 3);
- assert(graph.object (4).links[1].objidx == 0);
- assert(graph.object (4).links[2].objidx == 2);
+ for (int i = num_subtables - 1; i >= 0; i--)
+ subtables[i] = add_object(large_string.c_str (), 15000, c);
- assert(strncmp (graph.object (3).head, "def", 3) == 0);
- assert(graph.object (3).links.length == 1);
- assert(graph.object (3).links[0].objidx == 1);
+ for (int i = num_subtables - 1;
+ i >= (num_lookups - num_extensions) * 2;
+ i--)
+ {
+ unsigned ext_index = i - (num_lookups - num_extensions) * 2;
+ unsigned subtable_index = num_subtables - ext_index - 1;
+ extensions[i] = add_extension (subtables[subtable_index], 5, c);
+ }
- assert(strncmp (graph.object (2).head, "mn", 2) == 0);
- assert(graph.object (2).links.length == 0);
+ for (int i = num_lookups - 1; i >= 0; i--)
+ {
+ bool is_ext = (i >= (num_lookups - num_extensions));
- assert(strncmp (graph.object (1).head, "ghi", 3) == 0);
- assert(graph.object (1).links.length == 1);
- assert(graph.object (1).links[0].objidx == 0);
+ start_lookup (is_ext ? (char) 7 : (char) 5,
+ 2,
+ c);
- assert(strncmp (graph.object (0).head, "jkl", 3) == 0);
- assert(graph.object (0).links.length == 0);
+ if (is_ext) {
+ add_offset (extensions[i * 2], c);
+ add_offset (extensions[i * 2 + 1], c);
+ } else {
+ add_offset (subtables[i * 2], c);
+ add_offset (subtables[i * 2 + 1], c);
+ }
- free (buffer);
+ lookups[i] = finish_lookup (c);
+ }
+
+ unsigned lookup_list = add_lookup_list (lookups, num_lookups, c);
+
+ add_gsubgpos_header (lookup_list, c);
+
+ c->end_serialize();
+}
+
+template<int num_pair_pos_1, int num_pair_set>
+static void
+populate_serializer_with_large_pair_pos_1 (hb_serialize_context_t* c,
+ bool as_extension = false)
+{
+ std::string large_string(60000, 'a');
+ c->start_serialize<char> ();
+
+ constexpr int total_pair_set = num_pair_pos_1 * num_pair_set;
+ unsigned pair_set[total_pair_set];
+ unsigned coverage[num_pair_pos_1];
+ unsigned pair_pos_1[num_pair_pos_1];
+
+ for (int i = num_pair_pos_1 - 1; i >= 0; i--)
+ {
+ for (int j = (i + 1) * num_pair_set - 1; j >= i * num_pair_set; j--)
+ pair_set[j] = add_object (large_string.c_str (), 30000 + j, c);
+
+ coverage[i] = add_coverage (i * num_pair_set,
+ (i + 1) * num_pair_set - 1, c);
+
+ pair_pos_1[i] = add_pair_pos_1 (&pair_set[i * num_pair_set],
+ num_pair_set,
+ coverage[i],
+ c);
+ }
+
+ unsigned pair_pos_2 = add_object (large_string.c_str(), 200, c);
+
+ if (as_extension) {
+ pair_pos_2 = add_extension (pair_pos_2, 2, c);
+ for (int i = num_pair_pos_1 - 1; i >= 0; i--)
+ pair_pos_1[i] = add_extension (pair_pos_1[i], 2, c);
+ }
+
+ start_lookup (as_extension ? 9 : 2, 1 + num_pair_pos_1, c);
+
+ for (int i = 0; i < num_pair_pos_1; i++)
+ add_offset (pair_pos_1[i], c);
+ add_offset (pair_pos_2, c);
+
+ unsigned lookup = finish_lookup (c);
+
+ unsigned lookup_list = add_lookup_list (&lookup, 1, c);
+
+ add_gsubgpos_header (lookup_list, c);
+
+ c->end_serialize();
+}
+
+template<int num_pair_pos_2, int num_class_1, int num_class_2>
+static void
+populate_serializer_with_large_pair_pos_2 (hb_serialize_context_t* c,
+ bool as_extension = false,
+ bool with_device_tables = false,
+ bool extra_table = true)
+{
+ std::string large_string(100000, 'a');
+ c->start_serialize<char> ();
+
+ unsigned coverage[num_pair_pos_2];
+ unsigned class_def_1[num_pair_pos_2];
+ unsigned class_def_2[num_pair_pos_2];
+ unsigned pair_pos_2[num_pair_pos_2];
+
+ unsigned* device_tables = (unsigned*) calloc (num_pair_pos_2 * num_class_1 * num_class_2,
+ sizeof(unsigned));
+
+ // Total glyphs = num_class_1 * num_pair_pos_2
+ for (int i = num_pair_pos_2 - 1; i >= 0; i--)
+ {
+ unsigned start_glyph = 5 + i * num_class_1;
+ if (num_class_2 >= num_class_1)
+ {
+ class_def_2[i] = add_class_def (11,
+ 10 + num_class_2, c);
+ class_def_1[i] = add_class_def (start_glyph + 1,
+ start_glyph + num_class_1,
+ c);
+ } else {
+ class_def_1[i] = add_class_def (start_glyph + 1,
+ start_glyph + num_class_1,
+ c);
+ class_def_2[i] = add_class_def (11,
+ 10 + num_class_2, c);
+ }
+
+ coverage[i] = add_coverage (start_glyph,
+ start_glyph + num_class_1 - 1,
+ c);
+
+ if (with_device_tables)
+ {
+ for(int j = (i + 1) * num_class_1 * num_class_2 - 1;
+ j >= i * num_class_1 * num_class_2;
+ j--)
+ {
+ uint8_t table[] = {
+ (uint8_t) ((j >> 8) & 0xFF),
+ (uint8_t) (j & 0xFF),
+ };
+ device_tables[j] = add_object ((char*) table, 2, c);
+ }
+ }
+
+ pair_pos_2[i] = add_pair_pos_2 (1 + i * num_class_1,
+ coverage[i],
+ class_def_1[i], num_class_1,
+ class_def_2[i], num_class_2,
+ with_device_tables
+ ? &device_tables[i * num_class_1 * num_class_2]
+ : nullptr,
+ c);
+ }
+
+
+ unsigned pair_pos_1 = 0;
+ if (extra_table) pair_pos_1 = add_object (large_string.c_str(), 100000, c);
+
+ if (as_extension) {
+ for (int i = num_pair_pos_2 - 1; i >= 0; i--)
+ pair_pos_2[i] = add_extension (pair_pos_2[i], 2, c);
+
+ if (extra_table)
+ pair_pos_1 = add_extension (pair_pos_1, 2, c);
+ }
+
+ start_lookup (as_extension ? 9 : 2, 1 + num_pair_pos_2, c);
+
+ if (extra_table)
+ add_offset (pair_pos_1, c);
+
+ for (int i = 0; i < num_pair_pos_2; i++)
+ add_offset (pair_pos_2[i], c);
+
+ unsigned lookup = finish_lookup (c);
+
+ unsigned lookup_list = add_lookup_list (&lookup, 1, c);
+
+ add_gsubgpos_header (lookup_list, c);
+
+ c->end_serialize();
+
+ free (device_tables);
+}
+
+template<int mark_count,
+ int class_count,
+ int base_count,
+ int table_count>
+static void
+populate_serializer_with_large_mark_base_pos_1 (hb_serialize_context_t* c)
+{
+ c->start_serialize<char> ();
+
+ MarkBasePosBuffers<mark_count, class_count, base_count, table_count> buffers (c);
+
+ unsigned mark_base_pos[table_count];
+ for (unsigned i = 0; i < table_count; i++)
+ mark_base_pos[i] = buffers.create_mark_base_pos_1 (i, c);
+
+ for (int i = 0; i < table_count; i++)
+ mark_base_pos[i] = add_extension (mark_base_pos[i], 4, c);
+
+ start_lookup (9, table_count, c);
+
+ for (int i = 0; i < table_count; i++)
+ add_offset (mark_base_pos[i], c);
+
+ unsigned lookup = finish_lookup (c);
+
+ unsigned lookup_list = add_lookup_list (&lookup, 1, c);
+
+ add_gsubgpos_header (lookup_list, c);
+
+ c->end_serialize();
}
static void test_sort_shortest ()
@@ -852,26 +1476,27 @@ static void test_sort_shortest ()
graph_t graph (c.object_graph ());
graph.sort_shortest_distance ();
+ assert (!graph.in_error ());
assert(strncmp (graph.object (4).head, "abc", 3) == 0);
- assert(graph.object (4).links.length == 3);
- assert(graph.object (4).links[0].objidx == 2);
- assert(graph.object (4).links[1].objidx == 0);
- assert(graph.object (4).links[2].objidx == 3);
+ assert(graph.object (4).real_links.length == 3);
+ assert(graph.object (4).real_links[0].objidx == 2);
+ assert(graph.object (4).real_links[1].objidx == 0);
+ assert(graph.object (4).real_links[2].objidx == 3);
assert(strncmp (graph.object (3).head, "mn", 2) == 0);
- assert(graph.object (3).links.length == 0);
+ assert(graph.object (3).real_links.length == 0);
assert(strncmp (graph.object (2).head, "def", 3) == 0);
- assert(graph.object (2).links.length == 1);
- assert(graph.object (2).links[0].objidx == 1);
+ assert(graph.object (2).real_links.length == 1);
+ assert(graph.object (2).real_links[0].objidx == 1);
assert(strncmp (graph.object (1).head, "ghi", 3) == 0);
- assert(graph.object (1).links.length == 1);
- assert(graph.object (1).links[0].objidx == 0);
+ assert(graph.object (1).real_links.length == 1);
+ assert(graph.object (1).real_links[0].objidx == 0);
assert(strncmp (graph.object (0).head, "jkl", 3) == 0);
- assert(graph.object (0).links.length == 0);
+ assert(graph.object (0).real_links.length == 0);
free (buffer);
}
@@ -887,27 +1512,27 @@ static void test_duplicate_leaf ()
graph.duplicate (4, 1);
assert(strncmp (graph.object (5).head, "abc", 3) == 0);
- assert(graph.object (5).links.length == 3);
- assert(graph.object (5).links[0].objidx == 3);
- assert(graph.object (5).links[1].objidx == 4);
- assert(graph.object (5).links[2].objidx == 0);
+ assert(graph.object (5).real_links.length == 3);
+ assert(graph.object (5).real_links[0].objidx == 3);
+ assert(graph.object (5).real_links[1].objidx == 4);
+ assert(graph.object (5).real_links[2].objidx == 0);
assert(strncmp (graph.object (4).head, "jkl", 3) == 0);
- assert(graph.object (4).links.length == 0);
+ assert(graph.object (4).real_links.length == 0);
assert(strncmp (graph.object (3).head, "def", 3) == 0);
- assert(graph.object (3).links.length == 1);
- assert(graph.object (3).links[0].objidx == 2);
+ assert(graph.object (3).real_links.length == 1);
+ assert(graph.object (3).real_links[0].objidx == 2);
assert(strncmp (graph.object (2).head, "ghi", 3) == 0);
- assert(graph.object (2).links.length == 1);
- assert(graph.object (2).links[0].objidx == 1);
+ assert(graph.object (2).real_links.length == 1);
+ assert(graph.object (2).real_links[0].objidx == 1);
assert(strncmp (graph.object (1).head, "jkl", 3) == 0);
- assert(graph.object (1).links.length == 0);
+ assert(graph.object (1).real_links.length == 0);
assert(strncmp (graph.object (0).head, "mn", 2) == 0);
- assert(graph.object (0).links.length == 0);
+ assert(graph.object (0).real_links.length == 0);
free (buffer);
}
@@ -923,32 +1548,32 @@ static void test_duplicate_interior ()
graph.duplicate (3, 2);
assert(strncmp (graph.object (6).head, "abc", 3) == 0);
- assert(graph.object (6).links.length == 3);
- assert(graph.object (6).links[0].objidx == 4);
- assert(graph.object (6).links[1].objidx == 2);
- assert(graph.object (6).links[2].objidx == 1);
+ assert(graph.object (6).real_links.length == 3);
+ assert(graph.object (6).real_links[0].objidx == 4);
+ assert(graph.object (6).real_links[1].objidx == 2);
+ assert(graph.object (6).real_links[2].objidx == 1);
assert(strncmp (graph.object (5).head, "jkl", 3) == 0);
- assert(graph.object (5).links.length == 1);
- assert(graph.object (5).links[0].objidx == 0);
+ assert(graph.object (5).real_links.length == 1);
+ assert(graph.object (5).real_links[0].objidx == 0);
assert(strncmp (graph.object (4).head, "def", 3) == 0);
- assert(graph.object (4).links.length == 1);
- assert(graph.object (4).links[0].objidx == 3);
+ assert(graph.object (4).real_links.length == 1);
+ assert(graph.object (4).real_links[0].objidx == 3);
assert(strncmp (graph.object (3).head, "ghi", 3) == 0);
- assert(graph.object (3).links.length == 1);
- assert(graph.object (3).links[0].objidx == 5);
+ assert(graph.object (3).real_links.length == 1);
+ assert(graph.object (3).real_links[0].objidx == 5);
assert(strncmp (graph.object (2).head, "jkl", 3) == 0);
- assert(graph.object (2).links.length == 1);
- assert(graph.object (2).links[0].objidx == 0);
+ assert(graph.object (2).real_links.length == 1);
+ assert(graph.object (2).real_links[0].objidx == 0);
assert(strncmp (graph.object (1).head, "mn", 2) == 0);
- assert(graph.object (1).links.length == 0);
+ assert(graph.object (1).real_links.length == 0);
assert(strncmp (graph.object (0).head, "opqrst", 6) == 0);
- assert(graph.object (0).links.length == 0);
+ assert(graph.object (0).real_links.length == 0);
free (buffer);
}
@@ -962,19 +1587,14 @@ test_serialize ()
populate_serializer_simple (&c1);
hb_bytes_t expected = c1.copy_bytes ();
- void* buffer_2 = malloc (buffer_size);
- hb_serialize_context_t c2 (buffer_2, buffer_size);
-
graph_t graph (c1.object_graph ());
- graph.serialize (&c2);
- hb_bytes_t actual = c2.copy_bytes ();
+ hb_blob_t* out = graph::serialize (graph);
+ free (buffer_1);
+ hb_bytes_t actual = out->as_bytes ();
assert (actual == expected);
-
- actual.fini ();
expected.fini ();
- free (buffer_1);
- free (buffer_2);
+ hb_blob_destroy (out);
}
static void test_will_overflow_1 ()
@@ -985,7 +1605,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);
}
@@ -998,7 +1618,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);
}
@@ -1011,7 +1631,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);
}
@@ -1024,17 +1644,13 @@ static void test_resolve_overflows_via_sort ()
populate_serializer_with_overflow (&c);
graph_t graph (c.object_graph ());
- void* out_buffer = malloc (buffer_size);
- hb_serialize_context_t out (out_buffer, buffer_size);
-
- hb_resolve_overflows (c.object_graph (), HB_TAG_NONE, &out);
- assert (!out.offset_overflow ());
- hb_bytes_t result = out.copy_bytes ();
+ hb_blob_t* out = hb_resolve_overflows (c.object_graph (), HB_TAG_NONE);
+ assert (out);
+ hb_bytes_t result = out->as_bytes ();
assert (result.length == (80000 + 3 + 3 * 2));
- result.fini ();
free (buffer);
- free (out_buffer);
+ hb_blob_destroy (out);
}
static void test_resolve_overflows_via_duplication ()
@@ -1045,17 +1661,13 @@ static void test_resolve_overflows_via_duplication ()
populate_serializer_with_dedup_overflow (&c);
graph_t graph (c.object_graph ());
- void* out_buffer = malloc (buffer_size);
- hb_serialize_context_t out (out_buffer, buffer_size);
-
- hb_resolve_overflows (c.object_graph (), HB_TAG_NONE, &out);
- assert (!out.offset_overflow ());
- hb_bytes_t result = out.copy_bytes ();
+ hb_blob_t* out = hb_resolve_overflows (c.object_graph (), HB_TAG_NONE);
+ assert (out);
+ hb_bytes_t result = out->as_bytes ();
assert (result.length == (10000 + 2 * 2 + 60000 + 2 + 3 * 2));
- result.fini ();
free (buffer);
- free (out_buffer);
+ hb_blob_destroy (out);
}
static void test_resolve_overflows_via_space_assignment ()
@@ -1085,19 +1697,15 @@ static void test_resolve_overflows_via_isolation ()
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, 0);
- assert (!out.offset_overflow ());
- hb_bytes_t result = out.copy_bytes ();
+ hb_blob_t* out = hb_resolve_overflows (c.object_graph (), HB_TAG ('G', 'S', 'U', 'B'), 0);
+ assert (out);
+ hb_bytes_t result = out->as_bytes ();
assert (result.length == (1 + 10000 + 60000 + 1 + 1
+ 4 + 3 * 2));
- result.fini ();
free (buffer);
- free (out_buffer);
+ hb_blob_destroy (out);
}
static void test_resolve_overflows_via_isolation_with_recursive_duplication ()
@@ -1164,21 +1772,207 @@ static void test_resolve_overflows_via_isolation_spaces ()
populate_serializer_with_isolation_overflow_spaces (&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, 0);
- assert (!out.offset_overflow ());
- hb_bytes_t result = out.copy_bytes ();
+ hb_blob_t* out = hb_resolve_overflows (c.object_graph (), HB_TAG ('G', 'S', 'U', 'B'), 0);
+ assert (out);
+ hb_bytes_t result = out->as_bytes ();
unsigned expected_length = 3 + 2 * 60000; // objects
expected_length += 2 * 4 + 2 * 2; // links
assert (result.length == expected_length);
- result.fini ();
free (buffer);
- free (out_buffer);
+ hb_blob_destroy (out);
+}
+
+static void test_resolve_mixed_overflows_via_isolation_spaces ()
+{
+ size_t buffer_size = 200000;
+ void* buffer = malloc (buffer_size);
+ hb_serialize_context_t c (buffer, buffer_size);
+ populate_serializer_with_24_and_32_bit_offsets (&c);
+ graph_t graph (c.object_graph ());
+
+ assert (c.offset_overflow ());
+ hb_blob_t* out = hb_resolve_overflows (c.object_graph (), HB_TAG ('G', 'S', 'U', 'B'), 0);
+ assert (out);
+ hb_bytes_t result = out->as_bytes ();
+
+ unsigned expected_length =
+ // Objects
+ 7 +
+ 4 * 40000;
+
+ expected_length +=
+ // Links
+ 2 * 4 + // 32
+ 4 * 3 + // 24
+ 4 * 2; // 16
+
+ assert (result.length == expected_length);
+
+ free (buffer);
+ hb_blob_destroy (out);
+}
+
+static void test_resolve_with_extension_promotion ()
+{
+ size_t buffer_size = 200000;
+ void* buffer = malloc (buffer_size);
+ assert (buffer);
+ hb_serialize_context_t c (buffer, buffer_size);
+ populate_serializer_with_extension_promotion (&c);
+
+ void* expected_buffer = malloc (buffer_size);
+ assert (expected_buffer);
+ hb_serialize_context_t e (expected_buffer, buffer_size);
+ populate_serializer_with_extension_promotion (&e, 3);
+
+ run_resolve_overflow_test ("test_resolve_with_extension_promotion",
+ c,
+ e,
+ 20,
+ true);
+ free (buffer);
+ free (expected_buffer);
+}
+
+static void test_resolve_with_basic_pair_pos_1_split ()
+{
+ size_t buffer_size = 200000;
+ void* buffer = malloc (buffer_size);
+ assert (buffer);
+ hb_serialize_context_t c (buffer, buffer_size);
+ populate_serializer_with_large_pair_pos_1 <1, 4>(&c);
+
+ void* expected_buffer = malloc (buffer_size);
+ assert (expected_buffer);
+ hb_serialize_context_t e (expected_buffer, buffer_size);
+ populate_serializer_with_large_pair_pos_1 <2, 2>(&e, true);
+
+ run_resolve_overflow_test ("test_resolve_with_basic_pair_pos_1_split",
+ c,
+ e,
+ 20,
+ true,
+ HB_TAG('G', 'P', 'O', 'S'));
+ free (buffer);
+ free (expected_buffer);
+}
+
+static void test_resolve_with_extension_pair_pos_1_split ()
+{
+ size_t buffer_size = 200000;
+ void* buffer = malloc (buffer_size);
+ assert (buffer);
+ hb_serialize_context_t c (buffer, buffer_size);
+ populate_serializer_with_large_pair_pos_1 <1, 4>(&c, true);
+
+ void* expected_buffer = malloc (buffer_size);
+ assert (expected_buffer);
+ hb_serialize_context_t e (expected_buffer, buffer_size);
+ populate_serializer_with_large_pair_pos_1 <2, 2>(&e, true);
+
+ run_resolve_overflow_test ("test_resolve_with_extension_pair_pos_1_split",
+ c,
+ e,
+ 20,
+ true,
+ HB_TAG('G', 'P', 'O', 'S'));
+ free (buffer);
+ free (expected_buffer);
+}
+
+static void test_resolve_with_basic_pair_pos_2_split ()
+{
+ size_t buffer_size = 300000;
+ void* buffer = malloc (buffer_size);
+ assert (buffer);
+ hb_serialize_context_t c (buffer, buffer_size);
+ populate_serializer_with_large_pair_pos_2 <1, 4, 3000>(&c);
+
+ void* expected_buffer = malloc (buffer_size);
+ assert (expected_buffer);
+ hb_serialize_context_t e (expected_buffer, buffer_size);
+ populate_serializer_with_large_pair_pos_2 <2, 2, 3000>(&e, true);
+
+ run_resolve_overflow_test ("test_resolve_with_basic_pair_pos_2_split",
+ c,
+ e,
+ 20,
+ true,
+ HB_TAG('G', 'P', 'O', 'S'));
+ free (buffer);
+ free (expected_buffer);
+}
+
+static void test_resolve_with_close_to_limit_pair_pos_2_split ()
+{
+ size_t buffer_size = 300000;
+ void* buffer = malloc (buffer_size);
+ assert (buffer);
+ hb_serialize_context_t c (buffer, buffer_size);
+ populate_serializer_with_large_pair_pos_2 <1, 1596, 10>(&c, true, false, false);
+
+ void* expected_buffer = malloc (buffer_size);
+ assert (expected_buffer);
+ hb_serialize_context_t e (expected_buffer, buffer_size);
+ populate_serializer_with_large_pair_pos_2 <2, 798, 10>(&e, true, false, false);
+
+ run_resolve_overflow_test ("test_resolve_with_close_to_limit_pair_pos_2_split",
+ c,
+ e,
+ 20,
+ true,
+ HB_TAG('G', 'P', 'O', 'S'));
+ free (buffer);
+ free (expected_buffer);
+}
+
+static void test_resolve_with_pair_pos_2_split_with_device_tables ()
+{
+ size_t buffer_size = 300000;
+ void* buffer = malloc (buffer_size);
+ assert (buffer);
+ hb_serialize_context_t c (buffer, buffer_size);
+ populate_serializer_with_large_pair_pos_2 <1, 4, 2000>(&c, false, true);
+
+ void* expected_buffer = malloc (buffer_size);
+ assert (expected_buffer);
+ hb_serialize_context_t e (expected_buffer, buffer_size);
+ populate_serializer_with_large_pair_pos_2 <2, 2, 2000>(&e, true, true);
+
+ run_resolve_overflow_test ("test_resolve_with_pair_pos_2_split_with_device_tables",
+ c,
+ e,
+ 20,
+ true,
+ HB_TAG('G', 'P', 'O', 'S'));
+ free (buffer);
+ free (expected_buffer);
+}
+
+static void test_resolve_with_basic_mark_base_pos_1_split ()
+{
+ size_t buffer_size = 200000;
+ void* buffer = malloc (buffer_size);
+ assert (buffer);
+ hb_serialize_context_t c (buffer, buffer_size);
+ populate_serializer_with_large_mark_base_pos_1 <40, 10, 110, 1>(&c);
+
+ void* expected_buffer = malloc (buffer_size);
+ assert (expected_buffer);
+ hb_serialize_context_t e (expected_buffer, buffer_size);
+ populate_serializer_with_large_mark_base_pos_1 <40, 10, 110, 2>(&e);
+
+ run_resolve_overflow_test ("test_resolve_with_basic_mark_base_pos_1_split",
+ c,
+ e,
+ 20,
+ true,
+ HB_TAG('G', 'P', 'O', 'S'));
+ free (buffer);
+ free (expected_buffer);
}
static void test_resolve_overflows_via_splitting_spaces ()
@@ -1221,6 +2015,26 @@ static void test_resolve_overflows_via_splitting_spaces_2 ()
free (expected_buffer);
}
+static void test_resolve_overflows_via_priority ()
+{
+ size_t buffer_size = 160000;
+ void* buffer = malloc (buffer_size);
+ hb_serialize_context_t c (buffer, buffer_size);
+ populate_serializer_with_priority_overflow (&c);
+
+ void* expected_buffer = malloc (buffer_size);
+ hb_serialize_context_t e (expected_buffer, buffer_size);
+ populate_serializer_with_priority_overflow_expected (&e);
+
+ run_resolve_overflow_test ("test_resolve_overflows_via_priority",
+ c,
+ e,
+ 3);
+ free (buffer);
+ free (expected_buffer);
+}
+
+
static void test_virtual_link ()
{
size_t buffer_size = 100;
@@ -1228,13 +2042,10 @@ static void test_virtual_link ()
hb_serialize_context_t c (buffer, buffer_size);
populate_serializer_virtual_link (&c);
- void* out_buffer = malloc (buffer_size);
- hb_serialize_context_t out (out_buffer, buffer_size);
+ hb_blob_t* out = hb_resolve_overflows (c.object_graph (), HB_TAG_NONE);
+ assert (out);
- hb_resolve_overflows (c.object_graph (), HB_TAG_NONE, &out);
- assert (!out.offset_overflow ());
-
- hb_bytes_t result = out.copy_bytes ();
+ hb_bytes_t result = out->as_bytes ();
assert (result.length == 5 + 4 * 2);
assert (result[0] == 'a');
assert (result[5] == 'c');
@@ -1242,11 +2053,47 @@ static void test_virtual_link ()
assert (result[9] == 'b');
assert (result[12] == 'd');
- result.fini ();
free (buffer);
- free (out_buffer);
+ hb_blob_destroy (out);
}
+static void
+test_shared_node_with_virtual_links ()
+{
+ size_t buffer_size = 100;
+ void* buffer = malloc (buffer_size);
+ hb_serialize_context_t c (buffer, buffer_size);
+
+ c.start_serialize<char> ();
+
+ unsigned obj_b = add_object ("b", 1, &c);
+ unsigned obj_c = add_object ("c", 1, &c);
+
+ start_object ("d", 1, &c);
+ add_virtual_offset (obj_b, &c);
+ unsigned obj_d_1 = c.pop_pack ();
+
+ start_object ("d", 1, &c);
+ add_virtual_offset (obj_c, &c);
+ unsigned obj_d_2 = c.pop_pack ();
+
+ assert (obj_d_1 == obj_d_2);
+
+ start_object ("a", 1, &c);
+ add_offset (obj_b, &c);
+ add_offset (obj_c, &c);
+ add_offset (obj_d_1, &c);
+ add_offset (obj_d_2, &c);
+ c.pop_pack ();
+ c.end_serialize ();
+
+ assert(c.object_graph() [obj_d_1]->virtual_links.length == 2);
+ assert(c.object_graph() [obj_d_1]->virtual_links[0].objidx == obj_b);
+ assert(c.object_graph() [obj_d_1]->virtual_links[1].objidx == obj_c);
+ free(buffer);
+}
+
+
// TODO(garretrieger): update will_overflow tests to check the overflows array.
// TODO(garretrieger): add tests for priority raising.
@@ -1254,14 +2101,13 @@ int
main (int argc, char **argv)
{
test_serialize ();
- test_sort_kahn_1 ();
- test_sort_kahn_2 ();
test_sort_shortest ();
test_will_overflow_1 ();
test_will_overflow_2 ();
test_will_overflow_3 ();
test_resolve_overflows_via_sort ();
test_resolve_overflows_via_duplication ();
+ test_resolve_overflows_via_priority ();
test_resolve_overflows_via_space_assignment ();
test_resolve_overflows_via_isolation ();
test_resolve_overflows_via_isolation_with_recursive_duplication ();
@@ -1270,7 +2116,23 @@ main (int argc, char **argv)
test_resolve_overflows_via_isolating_16bit_space_2 ();
test_resolve_overflows_via_splitting_spaces ();
test_resolve_overflows_via_splitting_spaces_2 ();
+ test_resolve_mixed_overflows_via_isolation_spaces ();
test_duplicate_leaf ();
test_duplicate_interior ();
test_virtual_link ();
+ test_shared_node_with_virtual_links ();
+ test_resolve_with_extension_promotion ();
+ test_resolve_with_basic_pair_pos_1_split ();
+ test_resolve_with_extension_pair_pos_1_split ();
+ test_resolve_with_basic_pair_pos_2_split ();
+ test_resolve_with_pair_pos_2_split_with_device_tables ();
+ test_resolve_with_close_to_limit_pair_pos_2_split ();
+ test_resolve_with_basic_mark_base_pos_1_split ();
+
+ // TODO(grieger): have run overflow tests compare graph equality not final packed binary.
+ // TODO(grieger): split test where multiple subtables in one lookup are split to test link ordering.
+ // TODO(grieger): split test where coverage table in subtable that is being split is shared.
+ // TODO(grieger): test with extensions already mixed in as well.
+ // TODO(grieger): test two layer ext promotion setup.
+ // TODO(grieger): test sorting by subtables per byte in ext. promotion.
}