Fix page_map corruption in hb_set_t during process().

If a process operation results in less pages then the current set has, it will likely corrupt the page_map since it overwrites page_map entries ahead of where it's processing. This fixes that problem by removing page_map entries that will be dropped. Then dropping orphaned pages and re-indexing retained pages.
diff --git a/src/hb-set.hh b/src/hb-set.hh
index e60a0ee..9c1031f 100644
--- a/src/hb-set.hh
+++ b/src/hb-set.hh
@@ -450,6 +450,32 @@
     return true;
   }
 
+  void compact (unsigned int length)
+  {
+    hb_hashmap_t<uint32_t, uint32_t> old_index_to_page_map_index;
+
+    for (unsigned int i = 0; i < length; i++) {
+      old_index_to_page_map_index.set (page_map[i].index, i);
+    }
+
+    compact_pages (old_index_to_page_map_index);
+  }
+
+  void compact_pages (const hb_hashmap_t<uint32_t, uint32_t>& old_index_to_page_map_index)
+  {
+    unsigned int write_index = 0;
+    for (unsigned int i = 0; i < pages.length; i++)
+    {
+      if (!old_index_to_page_map_index.has (i)) continue;
+
+      if (write_index < i)
+        pages[write_index] = pages[i];
+
+      page_map[old_index_to_page_map_index[i]].index = write_index;
+      write_index++;
+    }
+  }
+
   template <typename Op>
   void process (const Op& op, const hb_set_t *other)
   {
@@ -463,10 +489,22 @@
 
     unsigned int count = 0, newCount = 0;
     unsigned int a = 0, b = 0;
+    unsigned int write_index = 0;
     for (; a < na && b < nb; )
     {
       if (page_map[a].major == other->page_map[b].major)
       {
+        if (!Op::passthru_left)
+        {
+          // Move page_map entries that we're keeping from the left side set
+          // to the front of the page_map vector. This isn't necessary if
+          // passthru_left is set since no left side pages will be removed
+          // in that case.
+          if (write_index < a)
+            page_map[write_index] = page_map[a];
+          write_index++;
+        }
+
 	count++;
 	a++;
 	b++;
@@ -489,9 +527,16 @@
     if (Op::passthru_right)
       count += nb - b;
 
-    if (count > pages.length)
-      if (!resize (count))
-	return;
+    if (!Op::passthru_left)
+    {
+      na  = write_index;
+      next_page = write_index;
+      compact (write_index);
+    }
+
+    if (!resize (count))
+      return;
+
     newCount = count;
 
     /* Process in-place backward. */
diff --git a/test/api/test-set.c b/test/api/test-set.c
index aa2b388..d4e49f7 100644
--- a/test/api/test-set.c
+++ b/test/api/test-set.c
@@ -135,6 +135,81 @@
 //   printf ("}\n");
 // }
 
+static void test_set_intersect_empty (void)
+{
+  hb_set_t* a = hb_set_create ();
+  hb_set_add (a, 3585);
+  hb_set_add (a, 21333);
+  hb_set_add (a, 24405);
+
+  hb_set_t* b = hb_set_create();
+  hb_set_add (b, 21483);
+  hb_set_add (b, 24064);
+
+  hb_set_intersect (a, b);
+  g_assert (hb_set_is_empty (a));
+
+  hb_set_destroy (a);
+  hb_set_destroy (b);
+
+
+  a = hb_set_create ();
+  hb_set_add (a, 16777216);
+
+  b = hb_set_create();
+  hb_set_add (b, 0);
+
+  hb_set_intersect (a, b);
+  g_assert (hb_set_is_empty (a));
+
+  hb_set_destroy (a);
+  hb_set_destroy (b);
+}
+
+static void test_set_intersect_page_reduction (void)
+{
+  hb_set_t* a = hb_set_create ();
+  hb_set_add (a, 3585);
+  hb_set_add (a, 21333);
+  hb_set_add (a, 24405);
+
+  hb_set_t* b = hb_set_create();
+  hb_set_add (b, 3585);
+  hb_set_add (b, 24405);
+
+  hb_set_intersect(a, b);
+  g_assert (hb_set_is_equal (a, b));
+
+  hb_set_destroy (a);
+  hb_set_destroy (b);
+}
+
+static void test_set_union (void)
+{
+  hb_set_t* a = hb_set_create();
+  hb_set_add (a, 3585);
+  hb_set_add (a, 21333);
+  hb_set_add (a, 24405);
+
+  hb_set_t* b = hb_set_create();
+  hb_set_add (b, 21483);
+  hb_set_add (b, 24064);
+
+  hb_set_t* u = hb_set_create ();
+  hb_set_add (u, 3585);
+  hb_set_add (u, 21333);
+  hb_set_add (u, 21483);
+  hb_set_add (u, 24064);
+  hb_set_add (u, 24405);
+
+  hb_set_union(b, a);
+  g_assert (hb_set_is_equal (u, b));
+
+  hb_set_destroy (a);
+  hb_set_destroy (b);
+  hb_set_destroy (u);
+}
+
 static void
 test_set_algebra (void)
 {
@@ -405,5 +480,9 @@
   hb_test_add (test_set_iter);
   hb_test_add (test_set_empty);
 
+  hb_test_add (test_set_intersect_empty);
+  hb_test_add (test_set_intersect_page_reduction);
+  hb_test_add (test_set_union);
+
   return hb_test_run();
 }