[GSUB/GPOS] Use Coverage digests as gatekeeper

Gives me a good 10% speedup for the Devanagari test case.  Less so
for less lookup-intensive tests.

For the Devanagari test case, the false positive rate of the GSUB digest
is 4%.
diff --git a/src/hb-ot-layout-gpos-table.hh b/src/hb-ot-layout-gpos-table.hh
index 3b0b881..34b9723 100644
--- a/src/hb-ot-layout-gpos-table.hh
+++ b/src/hb-ot-layout-gpos-table.hh
@@ -1551,27 +1551,15 @@
 
     c->buffer->idx = 0;
 
-    /* Fast path for lookups with one coverage only (which is most). */
-    const Coverage *coverage = get_coverage ();
-    if (coverage)
-      while (c->buffer->idx < c->buffer->len)
-      {
-	if ((c->buffer->cur().mask & c->lookup_mask) &&
-	    coverage->get_coverage (c->buffer->cur().codepoint) != NOT_COVERED &&
-	    apply_once (c))
-	  ret = true;
-	else
-	  c->buffer->idx++;
-      }
-    else
-      while (c->buffer->idx < c->buffer->len)
-      {
-	if ((c->buffer->cur().mask & c->lookup_mask) &&
-	    apply_once (c))
-	  ret = true;
-	else
-	  c->buffer->idx++;
-      }
+    while (c->buffer->idx < c->buffer->len)
+    {
+      if ((c->buffer->cur().mask & c->lookup_mask) &&
+	  c->digest->may_have (c->buffer->cur().codepoint) &&
+	  apply_once (c))
+	ret = true;
+      else
+	c->buffer->idx++;
+    }
 
     return ret;
   }
diff --git a/src/hb-ot-layout-gsub-table.hh b/src/hb-ot-layout-gsub-table.hh
index ca91a25..182f780 100644
--- a/src/hb-ot-layout-gsub-table.hh
+++ b/src/hb-ot-layout-gsub-table.hh
@@ -1219,28 +1219,15 @@
 	c->buffer->clear_output ();
 	c->buffer->idx = 0;
 
-	/* Fast path for lookups with one coverage only (which is most). */
-	const Coverage *coverage = get_coverage ();
-	if (coverage)
-	  while (c->buffer->idx < c->buffer->len)
-	  {
-	    if ((c->buffer->cur().mask & c->lookup_mask) &&
-		coverage->get_coverage (c->buffer->cur().codepoint) != NOT_COVERED &&
-		apply_once (c))
-	      ret = true;
-	    else
-	      c->buffer->next_glyph ();
-	  }
-	else
-	  while (c->buffer->idx < c->buffer->len)
-	  {
-	    if ((c->buffer->cur().mask & c->lookup_mask) &&
-		apply_once (c))
-	      ret = true;
-	    else
-	      c->buffer->next_glyph ();
-
-	  }
+	while (c->buffer->idx < c->buffer->len)
+	{
+	  if ((c->buffer->cur().mask & c->lookup_mask) &&
+	      c->digest->may_have (c->buffer->cur().codepoint) &&
+	      apply_once (c))
+	    ret = true;
+	  else
+	    c->buffer->next_glyph ();
+	}
 	if (ret)
 	  c->buffer->swap_buffers ();
     }
@@ -1250,7 +1237,9 @@
 	c->buffer->idx = c->buffer->len - 1;
 	do
 	{
-	  if ((c->buffer->cur().mask & c->lookup_mask) && apply_once (c))
+	  if ((c->buffer->cur().mask & c->lookup_mask) &&
+	      c->digest->may_have (c->buffer->cur().codepoint) &&
+	      apply_once (c))
 	    ret = true;
 	  else
 	    c->buffer->idx--;
diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh
index 1f20514..7a3f32e 100644
--- a/src/hb-ot-layout-gsubgpos-private.hh
+++ b/src/hb-ot-layout-gsubgpos-private.hh
@@ -31,6 +31,7 @@
 
 #include "hb-buffer-private.hh"
 #include "hb-ot-layout-gdef-table.hh"
+#include "hb-set-private.hh"
 
 
 
@@ -109,12 +110,14 @@
   unsigned int debug_depth;
   const GDEF &gdef;
   bool has_glyph_classes;
+  const hb_set_digest_t *digest;
 
 
   hb_apply_context_t (hb_font_t *font_,
 		      hb_face_t *face_,
 		      hb_buffer_t *buffer_,
-		      hb_mask_t lookup_mask_) :
+		      hb_mask_t lookup_mask_,
+		      const hb_set_digest_t *digest_) :
 			font (font_), face (face_), buffer (buffer_),
 			direction (buffer_->props.direction),
 			lookup_mask (lookup_mask_),
@@ -123,7 +126,8 @@
 			gdef (hb_ot_layout_from_face (face_) &&
 			      !HB_SHAPER_DATA_IS_INVALID (hb_ot_layout_from_face (face_)) ?
 			      *hb_ot_layout_from_face (face_)->gdef : Null(GDEF)),
-			has_glyph_classes (gdef.has_glyph_classes ()) {}
+			has_glyph_classes (gdef.has_glyph_classes ()),
+			digest (digest_) {}
 
   void set_lookup (const Lookup &l) {
     lookup_props = l.get_props ();
diff --git a/src/hb-ot-layout-private.hh b/src/hb-ot-layout-private.hh
index fdbeb5b..d87a138 100644
--- a/src/hb-ot-layout-private.hh
+++ b/src/hb-ot-layout-private.hh
@@ -35,6 +35,7 @@
 
 #include "hb-font-private.hh"
 #include "hb-buffer-private.hh"
+#include "hb-set-private.hh"
 
 
 /* buffer var allocations, used during the GSUB/GPOS processing */
@@ -168,6 +169,9 @@
   const struct GDEF *gdef;
   const struct GSUB *gsub;
   const struct GPOS *gpos;
+
+  hb_set_digest_t *gsub_digests;
+  hb_set_digest_t *gpos_digests;
 };
 
 
diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc
index 0d0dfa0..b680d9c 100644
--- a/src/hb-ot-layout.cc
+++ b/src/hb-ot-layout.cc
@@ -58,6 +58,24 @@
   layout->gpos_blob = Sanitizer<GPOS>::sanitize (hb_face_reference_table (face, HB_OT_TAG_GPOS));
   layout->gpos = Sanitizer<GPOS>::lock_instance (layout->gpos_blob);
 
+  layout->gsub_digests = (hb_set_digest_t *) calloc (layout->gsub->get_lookup_count (), sizeof (hb_set_digest_t));
+  layout->gpos_digests = (hb_set_digest_t *) calloc (layout->gpos->get_lookup_count (), sizeof (hb_set_digest_t));
+
+  if (unlikely ((layout->gsub->get_lookup_count() && !layout->gsub_digests) ||
+		(layout->gpos->get_lookup_count() && !layout->gpos_digests)))
+  {
+    _hb_ot_layout_destroy (layout);
+    return NULL;
+  }
+
+  unsigned int count;
+  count = layout->gsub->get_lookup_count();
+  for (unsigned int i = 0; i < count; i++)
+    layout->gsub->add_coverage (&layout->gsub_digests[i], i);
+  count = layout->gpos->get_lookup_count();
+  for (unsigned int i = 0; i < count; i++)
+    layout->gpos->add_coverage (&layout->gpos_digests[i], i);
+
   return layout;
 }
 
@@ -68,6 +86,9 @@
   hb_blob_destroy (layout->gsub_blob);
   hb_blob_destroy (layout->gpos_blob);
 
+  free (layout->gsub_digests);
+  free (layout->gpos_digests);
+
   free (layout);
 }
 
@@ -412,7 +433,7 @@
 				unsigned int  lookup_index,
 				hb_mask_t     mask)
 {
-  hb_apply_context_t c (NULL, face, buffer, mask);
+  hb_apply_context_t c (NULL, face, buffer, mask, NULL);
   return _get_gsub (face).substitute_lookup (&c, lookup_index);
 }
 
@@ -422,7 +443,7 @@
 				     unsigned int  lookup_index,
 				     hb_mask_t     mask)
 {
-  hb_apply_context_t c (NULL, face, buffer, mask);
+  hb_apply_context_t c (NULL, face, buffer, mask, &hb_ot_layout_from_face (face)->gsub_digests[lookup_index]);
   return hb_ot_layout_from_face (face)->gsub->substitute_lookup (&c, lookup_index);
 }
 
@@ -463,7 +484,7 @@
 			      unsigned int  lookup_index,
 			      hb_mask_t     mask)
 {
-  hb_apply_context_t c (font, font->face, buffer, mask);
+  hb_apply_context_t c (font, font->face, buffer, mask, NULL);
   return _get_gpos (font->face).position_lookup (&c, lookup_index);
 }
 
@@ -473,7 +494,7 @@
 				   unsigned int  lookup_index,
 				   hb_mask_t     mask)
 {
-  hb_apply_context_t c (font, font->face, buffer, mask);
+  hb_apply_context_t c (font, font->face, buffer, mask, &hb_ot_layout_from_face (font->face)->gpos_digests[lookup_index]);
   return hb_ot_layout_from_face (font->face)->gpos->position_lookup (&c, lookup_index);
 }