[set] Speed up next_range()
diff --git a/src/hb-algs.hh b/src/hb-algs.hh
index ea97057..847e0a4 100644
--- a/src/hb-algs.hh
+++ b/src/hb-algs.hh
@@ -1417,7 +1417,7 @@
   template <typename T> constexpr auto
   operator () (const T &a) const HB_AUTO_RETURN (~a)
 }
-HB_FUNCOBJ (hb_bitwise_neg);
+HB_FUNCOBJ (hb_bitwise_not);
 
 struct
 { HB_PARTIALIZE(2);
diff --git a/src/hb-bit-page.hh b/src/hb-bit-page.hh
index 869c678..b85d012 100644
--- a/src/hb-bit-page.hh
+++ b/src/hb-bit-page.hh
@@ -76,7 +76,7 @@
   hb_vector_size_t operator ^ (const hb_vector_size_t &o) const
   { return process (hb_bitwise_xor, o); }
   hb_vector_size_t operator ~ () const
-  { return process (hb_bitwise_neg); }
+  { return process (hb_bitwise_not); }
 
   hb_array_t<const elt_t> iter () const
   { return hb_array (v); }
@@ -106,6 +106,15 @@
     | hb_none
     ;
   }
+  bool is_full () const
+  {
+    if (has_population ()) return population == PAGE_BITS;
+    return
+    + hb_iter (v)
+    | hb_filter (hb_bitwise_not)
+    | hb_none
+    ;
+  }
   uint32_t hash () const
   {
     return hb_bytes_t ((const char *) &v, sizeof (v)).hash ();
@@ -251,7 +260,7 @@
     return population;
   }
 
-  bool next (hb_codepoint_t *codepoint) const
+  bool next (hb_codepoint_t *codepoint, unsigned bit = 1) const
   {
     unsigned int m = (*codepoint + 1) & MASK;
     if (!m)
@@ -262,12 +271,27 @@
     unsigned int i = m / ELT_BITS;
     unsigned int j = m & ELT_MASK;
 
-    const elt_t vv = v[i] & ~((elt_t (1) << j) - 1);
+    elt_t vv;
+    if (bit)
+      vv = v[i] & ~((elt_t (1) << j) - 1);
+    else
+      vv = v[i] | ((elt_t (1) << j) - 1);
     for (const elt_t *p = &vv; i < len (); p = &v[++i])
-      if (*p)
+      if (bit)
       {
-	*codepoint = i * ELT_BITS + elt_get_min (*p);
-	return true;
+	if (*p)
+	{
+	  *codepoint = i * ELT_BITS + elt_get_min (*p);
+	  return true;
+	}
+      }
+      else
+      {
+        if (~*p)
+	{
+	  *codepoint = i * ELT_BITS + elt_get_min (~*p);
+	  return true;
+	}
       }
 
     *codepoint = INVALID;
diff --git a/src/hb-bit-set.hh b/src/hb-bit-set.hh
index 1dbcce5..a51266f 100644
--- a/src/hb-bit-set.hh
+++ b/src/hb-bit-set.hh
@@ -699,19 +699,59 @@
   }
   bool next_range (hb_codepoint_t *first, hb_codepoint_t *last) const
   {
-    hb_codepoint_t i;
-
-    i = *last;
-    if (!next (&i))
+    *first = *last;
+    if (!next (first))
     {
       *last = *first = INVALID;
       return false;
     }
 
-    /* TODO Speed up. */
-    *last = *first = i;
-    while (next (&i) && i == *last + 1)
-      (*last)++;
+    const auto* page_map_array = page_map.arrayZ;
+    unsigned int major = get_major (*first);
+    unsigned int i = last_page_lookup;
+    if (unlikely (i >= page_map.length || page_map_array[i].major != major))
+    {
+      page_map.bfind (major, &i, HB_NOT_FOUND_STORE_CLOSEST);
+      assert (i < page_map.length);
+    }
+
+    *last = *first;
+    if (pages.arrayZ[page_map_array[i].index].next (last, 0))
+    {
+      *last += major * page_t::PAGE_BITS - 1;
+      return true;
+    }
+    else
+      *last = (major + 1) * page_t::PAGE_BITS - 1;
+
+    for (i++, major++; i < page_map.length; i++, major++)
+    {
+      const page_map_t &current = page_map_array[i];
+      if (current.major != major)
+        break;
+
+      auto &page = pages.arrayZ[current.index];
+
+      if (page.is_full ())
+      {
+        *last += page_t::PAGE_BITS;
+	continue;
+      }
+
+      if (page.get (0))
+      {
+	hb_codepoint_t x = 0;
+	if (page.next (&x, 0))
+	{
+	  *last += x;
+	  break;
+	}
+	else
+	  *last += page_t::PAGE_BITS;
+      }
+      else
+	break;
+    }
 
     return true;
   }