[repacker] add 'virtual links' to the serializer.

These aren't associated with an offset field, but instead exist solely to add an ordering constraint to the object graph.
diff --git a/src/hb-repacker.hh b/src/hb-repacker.hh
index 72b3185..26faa56 100644
--- a/src/hb-repacker.hh
+++ b/src/hb-repacker.hh
@@ -828,8 +828,9 @@
         if (visited[link.objidx]) continue;
 
         const auto& child = vertices_[link.objidx].obj;
+        unsigned link_width = link.width ? link.width : 4; // treat virtual offsets as 32 bits wide
         int64_t child_weight = (child.tail - child.head) +
-                               ((int64_t) 1 << (link.width * 8)) * (vertices_[link.objidx].space + 1);
+                               ((int64_t) 1 << (link_width * 8)) * (vertices_[link.objidx].space + 1);
         int64_t child_distance = next_distance + child_weight;
 
         if (child_distance < vertices_[link.objidx].distance)
@@ -874,6 +875,10 @@
   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)
@@ -966,6 +971,9 @@
   {
     switch (link.width)
     {
+    case 0:
+      // Virtual links aren't serialized.
+      return;
     case 4:
       if (link.is_signed)
       {
diff --git a/src/hb-serialize.hh b/src/hb-serialize.hh
index 7b83fe1..f4c8fab 100644
--- a/src/hb-serialize.hh
+++ b/src/hb-serialize.hh
@@ -51,6 +51,12 @@
 };
 HB_MARK_AS_FLAG_T (hb_serialize_error_t);
 
+// This is a 0 byte wide offset, used to add virtual links to the serializer object graph.
+// It does not correspond to a real offset and exists soley to enforce an ordering constraint
+// in the graph's packed order.
+struct VirtualOffset {
+};
+
 struct hb_serialize_context_t
 {
   typedef unsigned objidx_t;
@@ -376,11 +382,22 @@
       err (HB_SERIALIZE_ERROR_OTHER);
 
     link.width = sizeof (T);
+    link.objidx = objidx;
+    if (unlikely (!sizeof (T)))
+    {
+      // This link is not associated with an actual offset and exists merely to enforce
+      // an ordering constraint.
+      link.is_signed = 0;
+      link.whence = 0;
+      link.position = 0;
+      link.bias = 0;
+      return;
+    }
+
     link.is_signed = std::is_signed<hb_unwrap_type (T)>::value;
     link.whence = (unsigned) whence;
     link.position = (const char *) &ofs - current->head;
     link.bias = bias;
-    link.objidx = objidx;
   }
 
   unsigned to_bias (const void *base) const
@@ -402,6 +419,8 @@
     for (const object_t* parent : ++hb_iter (packed))
       for (const object_t::link_t &link : parent->links)
       {
+        if (unlikely (!link.width)) continue; // Don't need to resolve virtual offsets
+
 	const object_t* child = packed[link.objidx];
 	if (unlikely (!child)) { err (HB_SERIALIZE_ERROR_OTHER); return; }
 	unsigned offset = 0;