[repacker] Add basic version of the extension promotion selection algorithm.
diff --git a/src/graph/graph.hh b/src/graph/graph.hh
index a23f793..df845da 100644
--- a/src/graph/graph.hh
+++ b/src/graph/graph.hh
@@ -480,6 +480,18 @@
       find_subgraph (link.objidx, subgraph);
   }
 
+  size_t find_subgraph_size (unsigned node_idx, hb_set_t& subgraph)
+  {
+    if (subgraph.has (node_idx)) return 0;
+    subgraph.add (node_idx);
+
+    const auto& o = vertices_[node_idx].obj;
+    size_t size = o.tail - o.head;
+    for (const auto& link : o.all_links ())
+      size += find_subgraph_size (link.objidx, subgraph);
+    return size;
+  }
+
   /*
    * Finds the topmost children of 32bit offsets in the subgraph starting
    * at node_idx. Found indices are placed into 'found'.
diff --git a/src/hb-repacker.hh b/src/hb-repacker.hh
index e52d0c0..7e5b86b 100644
--- a/src/hb-repacker.hh
+++ b/src/hb-repacker.hh
@@ -41,6 +41,13 @@
  * docs/repacker.md
  */
 
+inline int compare_sizes (const void* a, const void* b)
+{
+  hb_pair_t<unsigned, size_t>* size_a = (hb_pair_t<unsigned, size_t>*) a;
+  hb_pair_t<unsigned, size_t>* size_b = (hb_pair_t<unsigned, size_t>*) b;
+  return size_a->second - size_b->second;
+}
+
 /*
  * Analyze the lookups in a GSUB/GPOS table and decide if any should be promoted
  * to extension lookups.
@@ -48,10 +55,44 @@
 static inline
 bool _promote_extensions_if_needed (graph::make_extension_context_t& ext_context)
 {
-  // TODO: Move this into graph or gsubgpos graph?
-  for (auto p : ext_context.lookups.iter ())
+  // Simple Algorithm (v1, current):
+  // 1. Calculate how many bytes each non-extension lookup consumes.
+  // 2. Select up to 64k of those to remain as non-extension (greedy, smallest first).
+  // 3. Promote the rest.
+  //
+  // Advanced Algorithm (v2, not implemented):
+  // 1. Perform connected component analysis using lookups as roots.
+  // 2. Compute size of each connected component.
+  // 3. Select up to 64k worth of connected components to remain as non-extensions.
+  //    (greedy, smallest first)
+  // 4. Promote the rest.
+
+  // TODO(garretrieger): support extension demotion, then consider all lookups. Requires advanced algo.
+
+  hb_vector_t<hb_pair_t<unsigned, size_t>> lookup_sizes;
+  lookup_sizes.alloc (ext_context.lookups.get_population ());
+
+  for (unsigned lookup_index : ext_context.lookups.keys ())
   {
-    if (!p.second->make_extension (ext_context, p.first))
+    hb_set_t visited;
+    lookup_sizes.push (hb_pair_t<unsigned, size_t> {
+        lookup_index,
+        ext_context.graph.find_subgraph_size (lookup_index, visited)
+      });
+  }
+
+  lookup_sizes.qsort (compare_sizes);
+
+  size_t accumlated_bytes = 0;
+  for (auto p : lookup_sizes)
+  {
+    unsigned lookup_index = p.first;
+    size_t size = p.second;
+    accumlated_bytes += size;
+
+    if (accumlated_bytes < (1 << 16)) continue; // this lookup fits with 64k, which won't overflow.
+
+    if (!ext_context.lookups.get(lookup_index)->make_extension (ext_context, lookup_index))
       return false;
   }
 
@@ -173,7 +214,8 @@
 inline hb_blob_t*
 hb_resolve_overflows (const T& packed,
                       hb_tag_t table_tag,
-                      unsigned max_rounds = 20) {
+                      unsigned max_rounds = 20,
+                      bool recalculate_extensions = false) {
   graph_t sorted_graph (packed);
   sorted_graph.sort_shortest_distance ();
 
@@ -189,13 +231,16 @@
        ||  table_tag == HB_OT_TAG_GSUB)
       && will_overflow)
   {
-    graph::make_extension_context_t ext_context (table_tag, sorted_graph, extension_buffer);
-    if (ext_context.in_error ())
-      return nullptr;
+    if (recalculate_extensions)
+    {
+      graph::make_extension_context_t ext_context (table_tag, sorted_graph, extension_buffer);
+      if (ext_context.in_error ())
+        return nullptr;
 
-    if (0 && !_promote_extensions_if_needed (ext_context)) {
-      DEBUG_MSG (SUBSET_REPACK, nullptr, "Extensions promotion failed.");
-      return nullptr;
+      if (!_promote_extensions_if_needed (ext_context)) {
+        DEBUG_MSG (SUBSET_REPACK, nullptr, "Extensions promotion failed.");
+        return nullptr;
+      }
     }
 
     DEBUG_MSG (SUBSET_REPACK, nullptr, "Assigning spaces to 32 bit subgraphs.");