[repacker] add make_extension_context_t.
diff --git a/src/graph/graph.hh b/src/graph/graph.hh
index c9aaec1..0d09f33 100644
--- a/src/graph/graph.hh
+++ b/src/graph/graph.hh
@@ -24,6 +24,10 @@
  * Google Author(s): Garret Rieger
  */
 
+#include "hb-set.hh"
+#include "hb-priority-queue.hh"
+#include "hb-serialize.hh"
+
 #ifndef GRAPH_GRAPH_HH
 #define GRAPH_GRAPH_HH
 
diff --git a/src/graph/gsubgpos-graph.cc b/src/graph/gsubgpos-graph.cc
new file mode 100644
index 0000000..fefb0da
--- /dev/null
+++ b/src/graph/gsubgpos-graph.cc
@@ -0,0 +1,41 @@
+/*
+ * Copyright © 2022  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Garret Rieger
+ */
+
+#include "gsubgpos-graph.hh"
+
+namespace graph {
+
+unsigned make_extension_context_t::num_non_ext_subtables ()  {
+  unsigned count = 0;
+  for (auto l : lookups.values ())
+  {
+    if (l->is_extension (table_tag)) continue;
+    count += l->number_of_subtables ();
+  }
+  return count;
+}
+
+}
diff --git a/src/graph/gsubgpos-graph.hh b/src/graph/gsubgpos-graph.hh
index 27a1e5c..3ff9d3c 100644
--- a/src/graph/gsubgpos-graph.hh
+++ b/src/graph/gsubgpos-graph.hh
@@ -24,13 +24,13 @@
  * Google Author(s): Garret Rieger
  */
 
-#ifndef GRAPH_GSUBGPOS_GRAPH_HH
-#define GRAPH_GSUBGPOS_GRAPH_HH
-
 #include "graph.hh"
 #include "hb-ot-layout-gsubgpos.hh"
 #include "OT/Layout/GSUB/ExtensionSubst.hh"
 
+#ifndef GRAPH_GSUBGPOS_GRAPH_HH
+#define GRAPH_GSUBGPOS_GRAPH_HH
+
 namespace graph {
 
 struct Lookup;
@@ -69,10 +69,37 @@
       Lookup* lookup = (Lookup*) graph.object (lookup_idx).head;
       lookups.set (lookup_idx, lookup);
     }
-}
+  }
+};
 
+struct make_extension_context_t
+{
+  hb_tag_t table_tag;
+  graph_t& graph;
+  hb_vector_t<char> buffer;
+  GSTAR* gstar;
+  hb_hashmap_t<unsigned, graph::Lookup*> lookups;
 
+  make_extension_context_t (hb_tag_t table_tag_,
+                            graph_t& graph_)
+      : table_tag (table_tag_),
+        graph (graph_),
+        buffer (),
+        gstar (graph::GSTAR::graph_to_gstar (graph_)),
+        lookups ()
+  {
+    gstar->find_lookups (graph, lookups);
+    unsigned extension_size = OT::ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>::static_size;
+    buffer.alloc (num_non_ext_subtables () * extension_size);
+  }
 
+  bool in_error () const
+  {
+    return buffer.in_error ();
+  }
+
+ private:
+  unsigned num_non_ext_subtables ();
 };
 
 struct Lookup : public OT::Lookup
@@ -87,15 +114,13 @@
     return lookupType == extension_type (table_tag);
   }
 
-  bool make_extension (hb_tag_t table_tag,
-                       graph_t& graph,
-                       unsigned this_index,
-                       hb_vector_t<char>& buffer)
+  bool make_extension (make_extension_context_t& c,
+                       unsigned this_index)
   {
     // TODO: use a context_t?
     unsigned type = lookupType;
-    unsigned ext_type = extension_type (table_tag);
-    if (!ext_type || is_extension (table_tag))
+    unsigned ext_type = extension_type (c.table_tag);
+    if (!ext_type || is_extension (c.table_tag))
     {
       // NOOP
       printf("Already extension (obj %u).\n", this_index);
@@ -109,11 +134,10 @@
 
     for (unsigned i = 0; i < subTable.len; i++)
     {
-      unsigned subtable_index = graph.index_for_offset (this_index, &subTable[i]);
-      if (!make_subtable_extension (graph,
+      unsigned subtable_index = c.graph.index_for_offset (this_index, &subTable[i]);
+      if (!make_subtable_extension (c,
                                     this_index,
-                                    subtable_index,
-                                    buffer))
+                                    subtable_index))
         return false;
     }
 
@@ -121,23 +145,22 @@
     return true;
   }
 
-  bool make_subtable_extension (graph_t& graph,
+  bool make_subtable_extension (make_extension_context_t& c,
                                 unsigned lookup_index,
-                                unsigned subtable_index,
-                                hb_vector_t<char>& buffer)
+                                unsigned subtable_index)
   {
     printf("  Promoting subtable %u in lookup %u to extension.\n", subtable_index, lookup_index);
 
     unsigned type = lookupType;
     unsigned extension_size = OT::ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>::static_size;
-    unsigned start = buffer.length;
+    unsigned start = c.buffer.length;
     unsigned end = start + extension_size;
-    if (!buffer.resize (buffer.length + extension_size))
+    if (!c.buffer.resize (c.buffer.length + extension_size))
       // TODO: resizing potentially invalidates existing head/tail pointers.
       return false;
 
     OT::ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>* extension =
-        (OT::ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>*) &buffer[start];
+        (OT::ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>*) &c.buffer[start];
     extension->format = 1;
     extension->extensionLookupType = type;
     extension->extensionOffset = 0;
@@ -145,11 +168,11 @@
     unsigned type_prime = extension->extensionLookupType;
     printf("Assigned type %d to extension\n", type_prime);
 
-    unsigned ext_index = graph.new_node (&buffer.arrayZ[start],
-                                         &buffer.arrayZ[end]);
+    unsigned ext_index = c.graph.new_node (&c.buffer.arrayZ[start],
+                                           &c.buffer.arrayZ[end]);
     if (ext_index == (unsigned) -1) return false;
 
-    auto& lookup_vertex = graph.vertices_[lookup_index];
+    auto& lookup_vertex = c.graph.vertices_[lookup_index];
     for (auto& l : lookup_vertex.obj.real_links.writer ())
     {
       if (l.objidx == subtable_index)
@@ -161,9 +184,8 @@
     }
 
     // Make extension point at the subtable.
-    // TODO: update extension parents array.
-    auto& ext_vertex = graph.vertices_[ext_index];
-    auto& subtable_vertex = graph.vertices_[subtable_index];
+    auto& ext_vertex = c.graph.vertices_[ext_index];
+    auto& subtable_vertex = c.graph.vertices_[subtable_index];
     auto* l = ext_vertex.obj.real_links.push ();
 
     l->width = 4;
diff --git a/src/hb-repacker.hh b/src/hb-repacker.hh
index 545da7a..1d49c90 100644
--- a/src/hb-repacker.hh
+++ b/src/hb-repacker.hh
@@ -29,8 +29,6 @@
 
 #include "hb-open-type.hh"
 #include "hb-map.hh"
-#include "hb-priority-queue.hh"
-#include "hb-serialize.hh"
 #include "hb-vector.hh"
 #include "graph/graph.hh"
 #include "graph/gsubgpos-graph.hh"
@@ -44,35 +42,12 @@
  */
 
 static inline
-unsigned _num_non_ext_subtables (hb_tag_t table_tag,
-                                 const hb_hashmap_t<unsigned, graph::Lookup*>& lookups)
-{
-  unsigned count = 0;
-  for (auto l : lookups.values ())
-  {
-    if (l->is_extension (table_tag)) continue;
-    count += l->number_of_subtables ();
-  }
-  return count;
-}
-
-
-static inline
-bool _make_extensions (hb_tag_t table_tag, graph_t& sorted_graph, hb_vector_t<char>& buffer)
+bool _make_extensions (graph::make_extension_context_t& ext_context)
 {
   // TODO: Move this into graph or gsubgpos graph?
-  graph::GSTAR* gstar = graph::GSTAR::graph_to_gstar (sorted_graph);
-  hb_hashmap_t<unsigned, graph::Lookup*> lookups;
-  gstar->find_lookups (sorted_graph, lookups);
-
-  unsigned extension_size = OT::ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>::static_size;
-  if (!buffer.alloc (_num_non_ext_subtables (table_tag, lookups) * extension_size))
-    return false;
-
-
-  for (auto p : lookups.iter ())
+  for (auto p : ext_context.lookups.iter ())
   {
-    if (!p.second->make_extension (table_tag, sorted_graph, p.first, buffer))
+    if (!p.second->make_extension (ext_context, p.first))
       return false;
   }
   return true;
@@ -206,12 +181,15 @@
     return graph::serialize (sorted_graph);
   }
 
-  hb_vector_t<char> extension_buffer;
+  graph::make_extension_context_t ext_context (table_tag, sorted_graph);
+  if (ext_context.in_error ())
+    return nullptr;
+
   if ((table_tag == HB_OT_TAG_GPOS
        ||  table_tag == HB_OT_TAG_GSUB)
       && will_overflow)
   {
-    if (!_make_extensions (table_tag, sorted_graph, extension_buffer)) {
+    if (!_make_extensions (ext_context)) {
       printf("make extensions failed.\n");
       return nullptr;
     }
diff --git a/src/meson.build b/src/meson.build
index e336037..27c75e6 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -345,6 +345,7 @@
   'hb-subset-plan.cc',
   'hb-subset-plan.hh',
   'hb-subset-repacker.cc',
+  'graph/gsubgpos-graph.cc',
   'hb-subset.cc',
   'hb-subset.hh',
 )
@@ -573,7 +574,7 @@
     'test-number': ['test-number.cc', 'hb-number.cc'],
     'test-ot-tag': ['hb-ot-tag.cc'],
     'test-priority-queue': ['test-priority-queue.cc', 'hb-static.cc'],
-    'test-repacker': ['test-repacker.cc', 'hb-static.cc'],
+    'test-repacker': ['test-repacker.cc', 'hb-static.cc', 'graph/gsubgpos-graph.cc'],
     'test-set': ['test-set.cc', 'hb-static.cc'],
     'test-serialize': ['test-serialize.cc', 'hb-static.cc'],
     'test-unicode-ranges': ['test-unicode-ranges.cc'],