[repacker] Add test for virtual links in the repacker.
diff --git a/src/hb-serialize.hh b/src/hb-serialize.hh
index f4c8fab..328c7b4 100644
--- a/src/hb-serialize.hh
+++ b/src/hb-serialize.hh
@@ -364,6 +364,30 @@
       assert (packed.tail ()->head == tail);
   }
 
+  void add_link (VirtualOffset &ofs, objidx_t objidx)
+  {
+    // This link is not associated with an actual offset and exists merely to enforce
+    // an ordering constraint.
+    if (unlikely (in_error ())) return;
+
+    if (!objidx)
+      return;
+
+    assert (current);
+    assert (current->head <= (const char *) &ofs);
+
+    auto& link = *current->links.push ();
+    if (current->links.in_error ())
+      err (HB_SERIALIZE_ERROR_OTHER);
+
+    link.width = 0;
+    link.objidx = objidx;
+    link.is_signed = 0;
+    link.whence = 0;
+    link.position = 0;
+    link.bias = 0;
+  }
+
   template <typename T>
   void add_link (T &ofs, objidx_t objidx,
 		 whence_t whence = Head,
diff --git a/src/test-repacker.cc b/src/test-repacker.cc
index aa48725..66e5aa1 100644
--- a/src/test-repacker.cc
+++ b/src/test-repacker.cc
@@ -97,6 +97,13 @@
   free (out_buffer);
 }
 
+static void add_virtual_offset (unsigned id,
+                                hb_serialize_context_t* c)
+{
+  VirtualOffset* offset = c->start_embed<VirtualOffset> ();
+  c->add_link (*offset, id);
+}
+
 static void
 populate_serializer_simple (hb_serialize_context_t* c)
 {
@@ -748,6 +755,33 @@
   c->end_serialize();
 }
 
+static void
+populate_serializer_virtual_link (hb_serialize_context_t* c)
+{
+  c->start_serialize<char> ();
+
+  unsigned obj_d = add_object ("d", 1, c);
+
+  start_object ("b", 1, c);
+  add_offset (obj_d, c);
+  unsigned obj_b = c->pop_pack ();
+
+  start_object ("e", 1, c);
+  add_virtual_offset (obj_b, c);
+  unsigned obj_e = c->pop_pack();
+
+  start_object ("c", 1, c);
+  add_offset (obj_e, c);
+  unsigned obj_c = c->pop_pack ();
+
+  start_object ("a", 1, c);
+  add_offset (obj_b, c);
+  add_offset (obj_c, c);
+  c->pop_pack ();
+
+  c->end_serialize();
+}
+
 static void test_sort_kahn_1 ()
 {
   size_t buffer_size = 100;
@@ -1186,7 +1220,32 @@
                              1);
   free (buffer);
   free (expected_buffer);
+}
 
+static void test_virtual_link ()
+{
+  size_t buffer_size = 100;
+  void* buffer = malloc (buffer_size);
+  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_resolve_overflows (c.object_graph (), HB_TAG_NONE, &out);
+  assert (!out.offset_overflow ());
+
+  hb_bytes_t result = out.copy_bytes ();
+  assert (result.length == 5 + 4 * 2);
+  assert (result[0]  == 'a');
+  assert (result[5]  == 'c');
+  assert (result[8]  == 'e');
+  assert (result[9]  == 'b');
+  assert (result[12] == 'd');
+
+  result.fini ();
+  free (buffer);
+  free (out_buffer);
 }
 
 // TODO(garretrieger): update will_overflow tests to check the overflows array.
@@ -1214,4 +1273,5 @@
   test_resolve_overflows_via_splitting_spaces_2 ();
   test_duplicate_leaf ();
   test_duplicate_interior ();
+  test_virtual_link ();
 }