Add intersects() method to GSUB/GPOS lookups
authorBehdad Esfahbod <behdad@behdad.org>
Mon, 3 Sep 2018 02:47:50 +0000 (19:47 -0700)
committerBehdad Esfahbod <behdad@behdad.org>
Mon, 3 Sep 2018 02:47:50 +0000 (19:47 -0700)
src/hb-ot-layout-common.hh
src/hb-ot-layout-gpos-table.hh
src/hb-ot-layout-gsub-table.hh
src/hb-ot-layout-gsubgpos.hh

index da8669d..de01bb4 100644 (file)
@@ -168,9 +168,8 @@ struct RangeRecord
     return_trace (c->check_struct (this));
   }
 
-  inline bool intersects (const hb_set_t *glyphs) const {
-    return glyphs->intersects (start, end);
-  }
+  inline bool intersects (const hb_set_t *glyphs) const
+  { return glyphs->intersects (start, end); }
 
   template <typename set_t>
   inline bool add_coverage (set_t *glyphs) const {
@@ -767,9 +766,17 @@ struct CoverageFormat1
     return_trace (glyphArray.sanitize (c));
   }
 
-  inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
-    return glyphs->has (glyphArray[index]);
+  inline bool intersects (const hb_set_t *glyphs) const
+  {
+    /* TODO Speed up, using hb_set_next() and bsearch()? */
+    unsigned int count = glyphArray.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (glyphs->has (glyphArray[i]))
+        return true;
+    return false;
   }
+  inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
+  { return glyphs->has (glyphArray[index]); }
 
   template <typename set_t>
   inline bool add_coverage (set_t *glyphs) const {
@@ -857,7 +864,17 @@ struct CoverageFormat2
     return_trace (rangeRecord.sanitize (c));
   }
 
-  inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const {
+  inline bool intersects (const hb_set_t *glyphs) const
+  {
+    /* TODO Speed up, using hb_set_next() and bsearch()? */
+    unsigned int count = rangeRecord.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (rangeRecord[i].intersects (glyphs))
+        return true;
+    return false;
+  }
+  inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
+  {
     unsigned int i;
     unsigned int count = rangeRecord.len;
     for (i = 0; i < count; i++) {
@@ -985,13 +1002,13 @@ struct Coverage
 
   inline bool intersects (const hb_set_t *glyphs) const
   {
-    /* TODO speed this up */
-    for (hb_auto_t<Coverage::Iter> iter (*this); iter.more (); iter.next ())
-      if (glyphs->has (iter.get_glyph ()))
-        return true;
-    return false;
+    switch (u.format)
+    {
+    case 1: return u.format1.intersects (glyphs);
+    case 2: return u.format2.intersects (glyphs);
+    default:return false;
+    }
   }
-
   inline bool intersects_coverage (const hb_set_t *glyphs, unsigned int index) const
   {
     switch (u.format)
@@ -1141,6 +1158,17 @@ struct ClassDefFormat1
     return true;
   }
 
+  inline bool intersects (const hb_set_t *glyphs) const
+  {
+    /* TODO Speed up, using hb_set_next()? */
+    hb_codepoint_t start = startGlyph;
+    hb_codepoint_t end = startGlyph + classValue.len;
+    for (hb_codepoint_t iter = startGlyph - 1;
+        hb_set_next (glyphs, &iter) && iter < end;)
+      if (classValue[iter - start])
+        return true;
+    return false;
+  }
   inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
     unsigned int count = classValue.len;
     if (klass == 0)
@@ -1191,7 +1219,8 @@ struct ClassDefFormat2
   }
 
   template <typename set_t>
-  inline bool add_coverage (set_t *glyphs) const {
+  inline bool add_coverage (set_t *glyphs) const
+  {
     unsigned int count = rangeRecord.len;
     for (unsigned int i = 0; i < count; i++)
       if (rangeRecord[i].value)
@@ -1201,7 +1230,8 @@ struct ClassDefFormat2
   }
 
   template <typename set_t>
-  inline bool add_class (set_t *glyphs, unsigned int klass) const {
+  inline bool add_class (set_t *glyphs, unsigned int klass) const
+  {
     unsigned int count = rangeRecord.len;
     for (unsigned int i = 0; i < count; i++)
     {
@@ -1212,7 +1242,17 @@ struct ClassDefFormat2
     return true;
   }
 
-  inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
+  inline bool intersects (const hb_set_t *glyphs) const
+  {
+    /* TODO Speed up, using hb_set_next() and bsearch()? */
+    unsigned int count = rangeRecord.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (rangeRecord[i].intersects (glyphs))
+        return true;
+    return false;
+  }
+  inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const
+  {
     unsigned int count = rangeRecord.len;
     if (klass == 0)
     {
@@ -1289,6 +1329,13 @@ struct ClassDef
     }
   }
 
+  inline bool intersects (const hb_set_t *glyphs) const {
+    switch (u.format) {
+    case 1: return u.format1.intersects (glyphs);
+    case 2: return u.format2.intersects (glyphs);
+    default:return false;
+    }
+  }
   inline bool intersects_class (const hb_set_t *glyphs, unsigned int klass) const {
     switch (u.format) {
     case 1: return u.format1.intersects_class (glyphs, klass);
index 16b5479..641d16d 100644 (file)
@@ -459,6 +459,9 @@ struct MarkArray : ArrayOf<MarkRecord>      /* Array of MarkRecords--in Coverage orde
 
 struct SinglePosFormat1
 {
+  inline bool intersects (const hb_set_t *glyphs) const
+  { return (this+coverage).intersects (glyphs); }
+
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
@@ -466,9 +469,7 @@ struct SinglePosFormat1
   }
 
   inline const Coverage &get_coverage (void) const
-  {
-    return this+coverage;
-  }
+  { return this+coverage; }
 
   inline bool apply (hb_ot_apply_context_t *c) const
   {
@@ -507,6 +508,9 @@ struct SinglePosFormat1
 
 struct SinglePosFormat2
 {
+  inline bool intersects (const hb_set_t *glyphs) const
+  { return (this+coverage).intersects (glyphs); }
+
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
@@ -514,9 +518,7 @@ struct SinglePosFormat2
   }
 
   inline const Coverage &get_coverage (void) const
-  {
-    return this+coverage;
-  }
+  { return this+coverage; }
 
   inline bool apply (hb_ot_apply_context_t *c) const
   {
@@ -598,6 +600,24 @@ struct PairSet
 {
   friend struct PairPosFormat1;
 
+  inline bool intersects (const hb_set_t *glyphs,
+                         const ValueFormat *valueFormats) const
+  {
+    unsigned int len1 = valueFormats[0].get_len ();
+    unsigned int len2 = valueFormats[1].get_len ();
+    unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
+
+    const PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
+    unsigned int count = len;
+    for (unsigned int i = 0; i < count; i++)
+    {
+      if (glyphs->has (record->secondGlyph))
+        return true;
+      record = &StructAtOffset<const PairValueRecord> (record, record_size);
+    }
+    return false;
+  }
+
   inline void collect_glyphs (hb_collect_glyphs_context_t *c,
                              const ValueFormat *valueFormats) const
   {
@@ -652,7 +672,8 @@ struct PairSet
     return_trace (false);
   }
 
-  struct sanitize_closure_t {
+  struct sanitize_closure_t
+  {
     const void *base;
     const ValueFormat *valueFormats;
     unsigned int len1; /* valueFormats[0].get_len() */
@@ -681,6 +702,20 @@ struct PairSet
 
 struct PairPosFormat1
 {
+  inline bool intersects (const hb_set_t *glyphs) const
+  {
+    unsigned int count = pairSet.len;
+    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
+    {
+      if (unlikely (iter.get_coverage () >= count))
+        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
+      if (glyphs->has (iter.get_glyph ()) &&
+         (this+pairSet[iter.get_coverage ()]).intersects (glyphs, valueFormat))
+        return true;
+    }
+    return false;
+  }
+
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
@@ -691,9 +726,7 @@ struct PairPosFormat1
   }
 
   inline const Coverage &get_coverage (void) const
-  {
-    return this+coverage;
-  }
+  { return this+coverage; }
 
   inline bool apply (hb_ot_apply_context_t *c) const
   {
@@ -717,7 +750,8 @@ struct PairPosFormat1
 
     unsigned int len1 = valueFormat[0].get_len ();
     unsigned int len2 = valueFormat[1].get_len ();
-    PairSet::sanitize_closure_t closure = {
+    PairSet::sanitize_closure_t closure =
+    {
       this,
       valueFormat,
       len1,
@@ -747,6 +781,12 @@ struct PairPosFormat1
 
 struct PairPosFormat2
 {
+  inline bool intersects (const hb_set_t *glyphs) const
+  {
+    return (this+coverage).intersects (glyphs) &&
+          (this+classDef2).intersects (glyphs);
+  }
+
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
@@ -755,9 +795,7 @@ struct PairPosFormat2
   }
 
   inline const Coverage &get_coverage (void) const
-  {
-    return this+coverage;
-  }
+  { return this+coverage; }
 
   inline bool apply (hb_ot_apply_context_t *c) const
   {
@@ -889,6 +927,9 @@ reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direc
 
 struct CursivePosFormat1
 {
+  inline bool intersects (const hb_set_t *glyphs) const
+  { return (this+coverage).intersects (glyphs); }
+
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
@@ -896,9 +937,7 @@ struct CursivePosFormat1
   }
 
   inline const Coverage &get_coverage (void) const
-  {
-    return this+coverage;
-  }
+  { return this+coverage; }
 
   inline bool apply (hb_ot_apply_context_t *c) const
   {
@@ -1047,6 +1086,10 @@ typedef AnchorMatrix BaseArray;          /* base-major--
 
 struct MarkBasePosFormat1
 {
+  inline bool intersects (const hb_set_t *glyphs) const
+  { return (this+markCoverage).intersects (glyphs) &&
+          (this+baseCoverage).intersects (glyphs); }
+
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
@@ -1055,9 +1098,7 @@ struct MarkBasePosFormat1
   }
 
   inline const Coverage &get_coverage (void) const
-  {
-    return this+markCoverage;
-  }
+  { return this+markCoverage; }
 
   inline bool apply (hb_ot_apply_context_t *c) const
   {
@@ -1161,6 +1202,10 @@ typedef OffsetListOf<LigatureAttach> LigatureArray;
 
 struct MarkLigPosFormat1
 {
+  inline bool intersects (const hb_set_t *glyphs) const
+  { return (this+markCoverage).intersects (glyphs) &&
+          (this+ligatureCoverage).intersects (glyphs); }
+
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
@@ -1169,9 +1214,7 @@ struct MarkLigPosFormat1
   }
 
   inline const Coverage &get_coverage (void) const
-  {
-    return this+markCoverage;
-  }
+  { return this+markCoverage; }
 
   inline bool apply (hb_ot_apply_context_t *c) const
   {
@@ -1274,6 +1317,10 @@ typedef AnchorMatrix Mark2Array; /* mark2-major--
 
 struct MarkMarkPosFormat1
 {
+  inline bool intersects (const hb_set_t *glyphs) const
+  { return (this+mark1Coverage).intersects (glyphs) &&
+          (this+mark2Coverage).intersects (glyphs); }
+
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
@@ -1282,9 +1329,7 @@ struct MarkMarkPosFormat1
   }
 
   inline const Coverage &get_coverage (void) const
-  {
-    return this+mark1Coverage;
-  }
+  { return this+mark1Coverage; }
 
   inline bool apply (hb_ot_apply_context_t *c) const
   {
@@ -1467,6 +1512,12 @@ struct PosLookup : Lookup
     return_trace (dispatch (c));
   }
 
+  inline bool intersects (const hb_set_t *glyphs) const
+  {
+    hb_intersects_context_t c (glyphs);
+    return dispatch (&c);
+  }
+
   inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
index c108e16..d6518b9 100644 (file)
@@ -37,6 +37,9 @@ namespace OT {
 
 struct SingleSubstFormat1
 {
+  inline bool intersects (const hb_set_t *glyphs) const
+  { return (this+coverage).intersects (glyphs); }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
@@ -64,9 +67,7 @@ struct SingleSubstFormat1
   }
 
   inline const Coverage &get_coverage (void) const
-  {
-    return this+coverage;
-  }
+  { return this+coverage; }
 
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
@@ -120,6 +121,9 @@ struct SingleSubstFormat1
 
 struct SingleSubstFormat2
 {
+  inline bool intersects (const hb_set_t *glyphs) const
+  { return (this+coverage).intersects (glyphs); }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
@@ -147,9 +151,7 @@ struct SingleSubstFormat2
   }
 
   inline const Coverage &get_coverage (void) const
-  {
-    return this+coverage;
-  }
+  { return this+coverage; }
 
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
@@ -160,14 +162,12 @@ struct SingleSubstFormat2
   inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
-    hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
-    unsigned int index = (this+coverage).get_coverage (glyph_id);
+    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return_trace (false);
 
     if (unlikely (index >= substitute.len)) return_trace (false);
 
-    glyph_id = substitute[index];
-    c->replace_glyph (glyph_id);
+    c->replace_glyph (substitute[index]);
 
     return_trace (true);
   }
@@ -325,6 +325,9 @@ struct Sequence
 
 struct MultipleSubstFormat1
 {
+  inline bool intersects (const hb_set_t *glyphs) const
+  { return (this+coverage).intersects (glyphs); }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
@@ -344,13 +347,11 @@ struct MultipleSubstFormat1
     if (unlikely (!(this+coverage).add_coverage (c->input))) return;
     unsigned int count = sequence.len;
     for (unsigned int i = 0; i < count; i++)
-       (this+sequence[i]).collect_glyphs (c);
+      (this+sequence[i]).collect_glyphs (c);
   }
 
   inline const Coverage &get_coverage (void) const
-  {
-    return this+coverage;
-  }
+  { return this+coverage; }
 
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
@@ -440,12 +441,72 @@ struct MultipleSubst
   } u;
 };
 
+struct AlternateSet
+{
+  inline void closure (hb_closure_context_t *c) const
+  {
+    TRACE_CLOSURE (this);
+    unsigned int count = alternates.len;
+    for (unsigned int i = 0; i < count; i++)
+      c->out->add (alternates[i]);
+  }
+
+  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
+  {
+    TRACE_COLLECT_GLYPHS (this);
+    c->output->add_array (alternates.arrayZ, alternates.len);
+  }
+
+  inline bool apply (hb_ot_apply_context_t *c) const
+  {
+    TRACE_APPLY (this);
+    unsigned int count = alternates.len;
+
+    if (unlikely (!count)) return_trace (false);
+
+    hb_mask_t glyph_mask = c->buffer->cur().mask;
+    hb_mask_t lookup_mask = c->lookup_mask;
+
+    /* Note: This breaks badly if two features enabled this lookup together. */
+    unsigned int shift = hb_ctz (lookup_mask);
+    unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
+
+    if (unlikely (alt_index > count || alt_index == 0)) return_trace (false);
+
+    c->replace_glyph (alternates[alt_index - 1]);
 
-typedef ArrayOf<GlyphID> AlternateSet; /* Array of alternate GlyphIDs--in
+    return_trace (true);
+  }
+
+  inline bool serialize (hb_serialize_context_t *c,
+                        Supplier<GlyphID> &glyphs,
+                        unsigned int num_glyphs)
+  {
+    TRACE_SERIALIZE (this);
+    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    if (unlikely (!alternates.serialize (c, glyphs, num_glyphs))) return_trace (false);
+    return_trace (true);
+  }
+
+  inline bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (alternates.sanitize (c));
+  }
+
+  protected:
+  ArrayOf<GlyphID>
+               alternates;             /* Array of alternate GlyphIDs--in
                                         * arbitrary order */
+  public:
+  DEFINE_SIZE_ARRAY (2, alternates);
+};
 
 struct AlternateSubstFormat1
 {
+  inline bool intersects (const hb_set_t *glyphs) const
+  { return (this+coverage).intersects (glyphs); }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
@@ -454,12 +515,8 @@ struct AlternateSubstFormat1
     {
       if (unlikely (iter.get_coverage () >= count))
         break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
-      if (c->glyphs->has (iter.get_glyph ())) {
-       const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
-       unsigned int count = alt_set.len;
-       for (unsigned int i = 0; i < count; i++)
-         c->out->add (alt_set[i]);
-      }
+      if (c->glyphs->has (iter.get_glyph ()))
+       (this+alternateSet[iter.get_coverage ()]).closure (c);
     }
   }
 
@@ -472,15 +529,12 @@ struct AlternateSubstFormat1
     {
       if (unlikely (iter.get_coverage () >= count))
         break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
-      const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
-      c->output->add_array (alt_set.arrayZ, alt_set.len);
+      (this+alternateSet[iter.get_coverage ()]).collect_glyphs (c);
     }
   }
 
   inline const Coverage &get_coverage (void) const
-  {
-    return this+coverage;
-  }
+  { return this+coverage; }
 
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
@@ -491,29 +545,11 @@ struct AlternateSubstFormat1
   inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
-    hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
 
-    unsigned int index = (this+coverage).get_coverage (glyph_id);
+    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return_trace (false);
 
-    const AlternateSet &alt_set = this+alternateSet[index];
-
-    if (unlikely (!alt_set.len)) return_trace (false);
-
-    hb_mask_t glyph_mask = c->buffer->cur().mask;
-    hb_mask_t lookup_mask = c->lookup_mask;
-
-    /* Note: This breaks badly if two features enabled this lookup together. */
-    unsigned int shift = hb_ctz (lookup_mask);
-    unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
-
-    if (unlikely (alt_index > alt_set.len || alt_index == 0)) return_trace (false);
-
-    glyph_id = alt_set[alt_index - 1];
-
-    c->replace_glyph (glyph_id);
-
-    return_trace (true);
+    return_trace ((this+alternateSet[index]).apply (c));
   }
 
   inline bool serialize (hb_serialize_context_t *c,
@@ -591,6 +627,15 @@ struct AlternateSubst
 
 struct Ligature
 {
+  inline bool intersects (const hb_set_t *glyphs) const
+  {
+    unsigned int count = component.len;
+    for (unsigned int i = 1; i < count; i++)
+      if (!glyphs->has (component[i]))
+        return false;
+    return true;
+  }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
@@ -694,6 +739,15 @@ struct Ligature
 
 struct LigatureSet
 {
+  inline bool intersects (const hb_set_t *glyphs) const
+  {
+    unsigned int num_ligs = ligature.len;
+    for (unsigned int i = 0; i < num_ligs; i++)
+      if ((this+ligature[i]).intersects (glyphs))
+        return true;
+    return false;
+  }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
@@ -771,6 +825,20 @@ struct LigatureSet
 
 struct LigatureSubstFormat1
 {
+  inline bool intersects (const hb_set_t *glyphs) const
+  {
+    unsigned int count = ligatureSet.len;
+    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
+    {
+      if (unlikely (iter.get_coverage () >= count))
+        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
+      if (glyphs->has (iter.get_glyph ()) &&
+         (this+ligatureSet[iter.get_coverage ()]).intersects (glyphs))
+        return true;
+    }
+    return false;
+  }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
@@ -798,9 +866,7 @@ struct LigatureSubstFormat1
   }
 
   inline const Coverage &get_coverage (void) const
-  {
-    return this+coverage;
-  }
+  { return this+coverage; }
 
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
@@ -815,9 +881,8 @@ struct LigatureSubstFormat1
   inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
-    hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
 
-    unsigned int index = (this+coverage).get_coverage (glyph_id);
+    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
     if (likely (index == NOT_COVERED)) return_trace (false);
 
     const LigatureSet &lig_set = this+ligatureSet[index];
@@ -923,6 +988,28 @@ struct ExtensionSubst : Extension<ExtensionSubst>
 
 struct ReverseChainSingleSubstFormat1
 {
+  inline bool intersects (const hb_set_t *glyphs) const
+  {
+    if (!(this+coverage).intersects (glyphs))
+      return false;
+
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+
+    unsigned int count;
+
+    count = backtrack.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (!(this+backtrack[i]).intersects (glyphs))
+        return false;
+
+    count = lookahead.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (!(this+lookahead[i]).intersects (glyphs))
+        return false;
+
+    return true;
+  }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
@@ -973,9 +1060,7 @@ struct ReverseChainSingleSubstFormat1
   }
 
   inline const Coverage &get_coverage (void) const
-  {
-    return this+coverage;
-  }
+  { return this+coverage; }
 
   inline bool would_apply (hb_would_apply_context_t *c) const
   {
@@ -1035,7 +1120,7 @@ struct ReverseChainSingleSubstFormat1
                                         * beginning of table */
   OffsetArrayOf<Coverage>
                backtrack;              /* Array of coverage tables
-                                        * in backtracking sequence, in  glyph
+                                        * in backtracking sequence, in glyph
                                         * sequence order */
   OffsetArrayOf<Coverage>
                lookaheadX;             /* Array of coverage tables
@@ -1146,6 +1231,12 @@ struct SubstLookup : Lookup
     return_trace (dispatch (c));
   }
 
+  inline bool intersects (const hb_set_t *glyphs) const
+  {
+    hb_intersects_context_t c (glyphs);
+    return dispatch (&c);
+  }
+
   inline hb_closure_context_t::return_t closure (hb_closure_context_t *c, unsigned int this_index) const
   {
     TRACE_CLOSURE (this);
@@ -1311,11 +1402,11 @@ struct GSUB : GSUBGPOS
   inline bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    struct GSUB *out = c->serializer->start_embed<GSUB> ();
+    //struct GSUB *out = c->serializer->start_embed<GSUB> ();
     if (unlikely (!GSUBGPOS::subset (c))) return_trace (false);
     /* TODO Replace following with c->iter_copy_and_subset()ish. */
     unsigned int count = get_lookup_count ();
-    LookupList &outLookupList = out+out->lookupList;
+    //LookupList &outLookupList = out+out->lookupList;
     for (unsigned int i = 0; i < count; i++)
       //XXX if (unlikely (!outLookupList.arrayZ[i].subset (c, get_lookup (i), &outLookupList)))
        return_trace (false);
index 5bdbf9a..e4399ae 100644 (file)
 namespace OT {
 
 
+struct hb_intersects_context_t :
+       hb_dispatch_context_t<hb_intersects_context_t, bool, 0>
+{
+  inline const char *get_name (void) { return "INTERSECTS"; }
+  template <typename T>
+  inline return_t dispatch (const T &obj) { return obj.intersects (this->glyphs); }
+  static return_t default_return_value (void) { return false; }
+  bool stop_sublookup_iteration (return_t r) const { return r; }
+
+  const hb_set_t *glyphs;
+  unsigned int debug_depth;
+
+  hb_intersects_context_t (const hb_set_t *glyphs_) :
+                            glyphs (glyphs_),
+                            debug_depth (0) {}
+};
+
 struct hb_closure_context_t :
        hb_dispatch_context_t<hb_closure_context_t, hb_void_t, HB_DEBUG_CLOSURE>
 {
@@ -49,15 +66,14 @@ struct hb_closure_context_t :
   inline return_t dispatch (const T &obj) { obj.closure (this); return HB_VOID; }
   static return_t default_return_value (void) { return HB_VOID; }
   bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
-  return_t recurse (unsigned int lookup_index)
+  void recurse (unsigned int lookup_index)
   {
     if (unlikely (nesting_level_left == 0 || !recurse_func))
-      return default_return_value ();
+      return;
 
     nesting_level_left--;
     recurse_func (this, lookup_index);
     nesting_level_left++;
-    return HB_VOID;
   }
 
   bool should_visit_lookup (unsigned int lookup_index)
@@ -146,10 +162,10 @@ struct hb_collect_glyphs_context_t :
   inline return_t dispatch (const T &obj) { obj.collect_glyphs (this); return HB_VOID; }
   static return_t default_return_value (void) { return HB_VOID; }
   bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
-  return_t recurse (unsigned int lookup_index)
+  void recurse (unsigned int lookup_index)
   {
     if (unlikely (nesting_level_left == 0 || !recurse_func))
-      return default_return_value ();
+      return;
 
     /* Note that GPOS sets recurse_func to nullptr already, so it doesn't get
      * past the previous check.  For GSUB, we only want to collect the output
@@ -162,11 +178,11 @@ struct hb_collect_glyphs_context_t :
      */
 
     if (output == hb_set_get_empty ())
-      return HB_VOID;
+      return;
 
     /* Return if new lookup was recursed to before. */
     if (recursed_lookups->has (lookup_index))
-      return HB_VOID;
+      return;
 
     hb_set_t *old_before = before;
     hb_set_t *old_input  = input;
@@ -183,7 +199,7 @@ struct hb_collect_glyphs_context_t :
 
     recursed_lookups->add (lookup_index);
 
-    return HB_VOID;
+    return;
   }
 
   hb_face_t *face;
@@ -208,24 +224,16 @@ struct hb_collect_glyphs_context_t :
                              after  (glyphs_after  ? glyphs_after  : hb_set_get_empty ()),
                              output (glyphs_output ? glyphs_output : hb_set_get_empty ()),
                              recurse_func (nullptr),
-                             recursed_lookups (nullptr),
+                             recursed_lookups (hb_set_create ()),
                              nesting_level_left (nesting_level_left_),
-                             debug_depth (0)
-  {
-    recursed_lookups = hb_set_create ();
-  }
-  ~hb_collect_glyphs_context_t (void)
-  {
-    hb_set_destroy (recursed_lookups);
-  }
+                             debug_depth (0) {}
+  ~hb_collect_glyphs_context_t (void) { hb_set_destroy (recursed_lookups); }
 
   void set_recurse_func (recurse_func_t func) { recurse_func = func; }
 };
 
 
 
-/* XXX Can we remove this? */
-
 template <typename set_t>
 struct hb_add_coverage_context_t :
        hb_dispatch_context_t<hb_add_coverage_context_t<set_t>, const Coverage &, HB_DEBUG_GET_COVERAGE>
@@ -599,7 +607,7 @@ struct hb_ot_apply_context_t :
 
 
 
-typedef bool (*intersects_func_t) (hb_set_t *glyphs, const HBUINT16 &value, const void *data);
+typedef bool (*intersects_func_t) (const hb_set_t *glyphs, const HBUINT16 &value, const void *data);
 typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const HBUINT16 &value, const void *data);
 typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data);
 
@@ -617,29 +625,29 @@ struct ContextApplyFuncs
 };
 
 
-static inline bool intersects_glyph (hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
+static inline bool intersects_glyph (const hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
 {
   return glyphs->has (value);
 }
-static inline bool intersects_class (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
+static inline bool intersects_class (const hb_set_t *glyphs, const HBUINT16 &value, const void *data)
 {
   const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
   return class_def.intersects_class (glyphs, value);
 }
-static inline bool intersects_coverage (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
+static inline bool intersects_coverage (const hb_set_t *glyphs, const HBUINT16 &value, const void *data)
 {
   const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
   return (data+coverage).intersects (glyphs);
 }
 
-static inline bool intersects_array (hb_closure_context_t *c,
+static inline bool intersects_array (const hb_set_t *glyphs,
                                     unsigned int count,
                                     const HBUINT16 values[],
                                     intersects_func_t intersects_func,
                                     const void *intersects_data)
 {
   for (unsigned int i = 0; i < count; i++)
-    if (likely (!intersects_func (c->glyphs, values[i], intersects_data)))
+    if (likely (!intersects_func (glyphs, values[i], intersects_data)))
       return false;
   return true;
 }
@@ -1140,6 +1148,16 @@ struct ContextApplyLookupContext
   const void *match_data;
 };
 
+static inline bool context_intersects (const hb_set_t *glyphs,
+                                      unsigned int inputCount, /* Including the first glyph (not matched) */
+                                      const HBUINT16 input[], /* Array of input values--start with second glyph */
+                                      ContextClosureLookupContext &lookup_context)
+{
+  return intersects_array (glyphs,
+                          inputCount ? inputCount - 1 : 0, input,
+                          lookup_context.funcs.intersects, lookup_context.intersects_data);
+}
+
 static inline void context_closure_lookup (hb_closure_context_t *c,
                                           unsigned int inputCount, /* Including the first glyph (not matched) */
                                           const HBUINT16 input[], /* Array of input values--start with second glyph */
@@ -1147,9 +1165,9 @@ static inline void context_closure_lookup (hb_closure_context_t *c,
                                           const LookupRecord lookupRecord[],
                                           ContextClosureLookupContext &lookup_context)
 {
-  if (intersects_array (c,
-                       inputCount ? inputCount - 1 : 0, input,
-                       lookup_context.funcs.intersects, lookup_context.intersects_data))
+  if (context_intersects (c->glyphs,
+                         inputCount, input,
+                         lookup_context))
     recurse_lookups (c,
                     lookupCount, lookupRecord);
 }
@@ -1201,6 +1219,13 @@ static inline bool context_apply_lookup (hb_ot_apply_context_t *c,
 
 struct Rule
 {
+  inline bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const
+  {
+    return context_intersects (glyphs,
+                              inputCount, inputZ,
+                              lookup_context);
+  }
+
   inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
   {
     TRACE_CLOSURE (this);
@@ -1261,6 +1286,15 @@ struct Rule
 
 struct RuleSet
 {
+  inline bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const
+  {
+    unsigned int num_rules = rule.len;
+    for (unsigned int i = 0; i < num_rules; i++)
+      if ((this+rule[i]).intersects (glyphs, lookup_context))
+        return true;
+    return false;
+  }
+
   inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
   {
     TRACE_CLOSURE (this);
@@ -1318,23 +1352,42 @@ struct RuleSet
 
 struct ContextFormat1
 {
+  inline bool intersects (const hb_set_t *glyphs) const
+  {
+    struct ContextClosureLookupContext lookup_context = {
+      {intersects_glyph},
+      nullptr
+    };
+
+    unsigned int count = ruleSet.len;
+    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
+    {
+      if (unlikely (iter.get_coverage () >= count))
+        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
+      if (glyphs->has (iter.get_glyph ()) &&
+         (this+ruleSet[iter.get_coverage ()]).intersects (glyphs, lookup_context))
+        return true;
+    }
+    return false;
+  }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
 
-    const Coverage &cov = (this+coverage);
-
     struct ContextClosureLookupContext lookup_context = {
       {intersects_glyph},
       nullptr
     };
 
     unsigned int count = ruleSet.len;
-    for (unsigned int i = 0; i < count; i++)
-      if (cov.intersects_coverage (c->glyphs, i)) {
-       const RuleSet &rule_set = this+ruleSet[i];
-       rule_set.closure (c, lookup_context);
-      }
+    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
+    {
+      if (unlikely (iter.get_coverage () >= count))
+        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
+      if (c->glyphs->has (iter.get_glyph ()))
+       (this+ruleSet[iter.get_coverage ()]).closure (c, lookup_context);
+    }
   }
 
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
@@ -1365,9 +1418,7 @@ struct ContextFormat1
   }
 
   inline const Coverage &get_coverage (void) const
-  {
-    return this+coverage;
-  }
+  { return this+coverage; }
 
   inline bool apply (hb_ot_apply_context_t *c) const
   {
@@ -1405,6 +1456,27 @@ struct ContextFormat1
 
 struct ContextFormat2
 {
+  inline bool intersects (const hb_set_t *glyphs) const
+  {
+    if (!(this+coverage).intersects (glyphs))
+      return false;
+
+    const ClassDef &class_def = this+classDef;
+
+    struct ContextClosureLookupContext lookup_context = {
+      {intersects_class},
+      &class_def
+    };
+
+    unsigned int count = ruleSet.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (class_def.intersects_class (glyphs, i) &&
+         (this+ruleSet[i]).intersects (glyphs, lookup_context))
+        return true;
+
+    return false;
+  }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
@@ -1457,9 +1529,7 @@ struct ContextFormat2
   }
 
   inline const Coverage &get_coverage (void) const
-  {
-    return this+coverage;
-  }
+  { return this+coverage; }
 
   inline bool apply (hb_ot_apply_context_t *c) const
   {
@@ -1501,6 +1571,20 @@ struct ContextFormat2
 
 struct ContextFormat3
 {
+  inline bool intersects (const hb_set_t *glyphs) const
+  {
+    if (!(this+coverageZ[0]).intersects (glyphs))
+      return false;
+
+    struct ContextClosureLookupContext lookup_context = {
+      {intersects_coverage},
+      this
+    };
+    return context_intersects (glyphs,
+                              glyphCount, (const HBUINT16 *) (coverageZ + 1),
+                              lookup_context);
+  }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
@@ -1548,9 +1632,7 @@ struct ContextFormat3
   }
 
   inline const Coverage &get_coverage (void) const
-  {
-    return this+coverageZ[0];
-  }
+  { return this+coverageZ[0]; }
 
   inline bool apply (hb_ot_apply_context_t *c) const
   {
@@ -1638,6 +1720,26 @@ struct ChainContextApplyLookupContext
   const void *match_data[3];
 };
 
+static inline bool chain_context_intersects (const hb_set_t *glyphs,
+                                            unsigned int backtrackCount,
+                                            const HBUINT16 backtrack[],
+                                            unsigned int inputCount, /* Including the first glyph (not matched) */
+                                            const HBUINT16 input[], /* Array of input values--start with second glyph */
+                                            unsigned int lookaheadCount,
+                                            const HBUINT16 lookahead[],
+                                            ChainContextClosureLookupContext &lookup_context)
+{
+  return intersects_array (glyphs,
+                          backtrackCount, backtrack,
+                          lookup_context.funcs.intersects, lookup_context.intersects_data[0])
+      && intersects_array (glyphs,
+                          inputCount ? inputCount - 1 : 0, input,
+                          lookup_context.funcs.intersects, lookup_context.intersects_data[1])
+      && intersects_array (glyphs,
+                         lookaheadCount, lookahead,
+                         lookup_context.funcs.intersects, lookup_context.intersects_data[2]);
+}
+
 static inline void chain_context_closure_lookup (hb_closure_context_t *c,
                                                 unsigned int backtrackCount,
                                                 const HBUINT16 backtrack[],
@@ -1649,15 +1751,11 @@ static inline void chain_context_closure_lookup (hb_closure_context_t *c,
                                                 const LookupRecord lookupRecord[],
                                                 ChainContextClosureLookupContext &lookup_context)
 {
-  if (intersects_array (c,
-                       backtrackCount, backtrack,
-                       lookup_context.funcs.intersects, lookup_context.intersects_data[0])
-   && intersects_array (c,
-                       inputCount ? inputCount - 1 : 0, input,
-                       lookup_context.funcs.intersects, lookup_context.intersects_data[1])
-   && intersects_array (c,
-                      lookaheadCount, lookahead,
-                      lookup_context.funcs.intersects, lookup_context.intersects_data[2]))
+  if (chain_context_intersects (c->glyphs,
+                               backtrackCount, backtrack,
+                               inputCount, input,
+                               lookaheadCount, lookahead,
+                               lookup_context))
     recurse_lookups (c,
                     lookupCount, lookupRecord);
 }
@@ -1737,6 +1835,17 @@ static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
 
 struct ChainRule
 {
+  inline bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
+  {
+    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
+    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
+    return chain_context_intersects (glyphs,
+                                    backtrack.len, backtrack.arrayZ,
+                                    input.len, input.arrayZ,
+                                    lookahead.len, lookahead.arrayZ,
+                                    lookup_context);
+  }
+
   inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
   {
     TRACE_CLOSURE (this);
@@ -1823,6 +1932,14 @@ struct ChainRule
 
 struct ChainRuleSet
 {
+  inline bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
+  {
+    unsigned int num_rules = rule.len;
+    for (unsigned int i = 0; i < num_rules; i++)
+      if ((this+rule[i]).intersects (glyphs, lookup_context))
+        return true;
+    return false;
+  }
   inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
   {
     TRACE_CLOSURE (this);
@@ -1877,10 +1994,28 @@ struct ChainRuleSet
 
 struct ChainContextFormat1
 {
+  inline bool intersects (const hb_set_t *glyphs) const
+  {
+    struct ChainContextClosureLookupContext lookup_context = {
+      {intersects_glyph},
+      {nullptr, nullptr, nullptr}
+    };
+
+    unsigned int count = ruleSet.len;
+    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
+    {
+      if (unlikely (iter.get_coverage () >= count))
+        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
+      if (glyphs->has (iter.get_glyph ()) &&
+         (this+ruleSet[iter.get_coverage ()]).intersects (glyphs, lookup_context))
+        return true;
+    }
+    return false;
+  }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
-    const Coverage &cov = (this+coverage);
 
     struct ChainContextClosureLookupContext lookup_context = {
       {intersects_glyph},
@@ -1888,11 +2023,13 @@ struct ChainContextFormat1
     };
 
     unsigned int count = ruleSet.len;
-    for (unsigned int i = 0; i < count; i++)
-      if (cov.intersects_coverage (c->glyphs, i)) {
-       const ChainRuleSet &rule_set = this+ruleSet[i];
-       rule_set.closure (c, lookup_context);
-      }
+    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
+    {
+      if (unlikely (iter.get_coverage () >= count))
+        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
+      if (c->glyphs->has (iter.get_glyph ()))
+       (this+ruleSet[iter.get_coverage ()]).closure (c, lookup_context);
+    }
   }
 
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
@@ -1923,9 +2060,7 @@ struct ChainContextFormat1
   }
 
   inline const Coverage &get_coverage (void) const
-  {
-    return this+coverage;
-  }
+  { return this+coverage; }
 
   inline bool apply (hb_ot_apply_context_t *c) const
   {
@@ -1961,6 +2096,30 @@ struct ChainContextFormat1
 
 struct ChainContextFormat2
 {
+  inline bool intersects (const hb_set_t *glyphs) const
+  {
+    if (!(this+coverage).intersects (glyphs))
+      return false;
+
+    const ClassDef &backtrack_class_def = this+backtrackClassDef;
+    const ClassDef &input_class_def = this+inputClassDef;
+    const ClassDef &lookahead_class_def = this+lookaheadClassDef;
+
+    struct ChainContextClosureLookupContext lookup_context = {
+      {intersects_class},
+      {&backtrack_class_def,
+       &input_class_def,
+       &lookahead_class_def}
+    };
+
+    unsigned int count = ruleSet.len;
+    for (unsigned int i = 0; i < count; i++)
+      if (input_class_def.intersects_class (glyphs, i) &&
+         (this+ruleSet[i]).intersects (glyphs, lookup_context))
+        return true;
+
+    return false;
+  }
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);
@@ -2027,9 +2186,7 @@ struct ChainContextFormat2
   }
 
   inline const Coverage &get_coverage (void) const
-  {
-    return this+coverage;
-  }
+  { return this+coverage; }
 
   inline bool apply (hb_ot_apply_context_t *c) const
   {
@@ -2088,6 +2245,25 @@ struct ChainContextFormat2
 
 struct ChainContextFormat3
 {
+  inline bool intersects (const hb_set_t *glyphs) const
+  {
+    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+
+    if (!(this+input[0]).intersects (glyphs))
+      return false;
+
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
+    struct ChainContextClosureLookupContext lookup_context = {
+      {intersects_coverage},
+      {this, this, this}
+    };
+    return chain_context_intersects (glyphs,
+                                    backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
+                                    input.len, (const HBUINT16 *) input.arrayZ + 1,
+                                    lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
+                                    lookup_context);
+  }
+
   inline void closure (hb_closure_context_t *c) const
   {
     TRACE_CLOSURE (this);