Imported Upstream version 1.7.6
[platform/upstream/harfbuzz.git] / src / hb-ot-layout-gsub-table.hh
index 7de56cf..5f67aed 100644 (file)
@@ -41,7 +41,10 @@ struct SingleSubstFormat1
   {
     TRACE_CLOSURE (this);
     Coverage::Iter iter;
-    for (iter.init (this+coverage); iter.more (); iter.next ()) {
+    for (iter.init (this+coverage); iter.more (); iter.next ())
+    {
+      /* TODO Switch to range-based API to work around malicious fonts.
+       * https://github.com/harfbuzz/harfbuzz/issues/363 */
       hb_codepoint_t glyph_id = iter.get_glyph ();
       if (c->glyphs->has (glyph_id))
        c->glyphs->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
@@ -51,10 +54,13 @@ struct SingleSubstFormat1
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
+    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
     Coverage::Iter iter;
-    for (iter.init (this+coverage); iter.more (); iter.next ()) {
+    for (iter.init (this+coverage); iter.more (); iter.next ())
+    {
+      /* TODO Switch to range-based API to work around malicious fonts.
+       * https://github.com/harfbuzz/harfbuzz/issues/363 */
       hb_codepoint_t glyph_id = iter.get_glyph ();
-      c->input->add (glyph_id);
       c->output->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
     }
   }
@@ -70,7 +76,7 @@ struct SingleSubstFormat1
     return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
   }
 
-  inline bool apply (hb_apply_context_t *c) const
+  inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
     hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
@@ -104,11 +110,11 @@ struct SingleSubstFormat1
   }
 
   protected:
-  USHORT       format;                 /* Format identifier--format = 1 */
+  HBUINT16     format;                 /* Format identifier--format = 1 */
   OffsetTo<Coverage>
                coverage;               /* Offset to Coverage table--from
                                         * beginning of Substitution table */
-  SHORT                deltaGlyphID;           /* Add to original GlyphID to get
+  HBINT16      deltaGlyphID;           /* Add to original GlyphID to get
                                         * substitute GlyphID */
   public:
   DEFINE_SIZE_STATIC (6);
@@ -120,7 +126,11 @@ struct SingleSubstFormat2
   {
     TRACE_CLOSURE (this);
     Coverage::Iter iter;
-    for (iter.init (this+coverage); iter.more (); iter.next ()) {
+    unsigned int count = substitute.len;
+    for (iter.init (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 ()))
        c->glyphs->add (substitute[iter.get_coverage ()]);
     }
@@ -129,9 +139,13 @@ struct SingleSubstFormat2
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
+    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
     Coverage::Iter iter;
-    for (iter.init (this+coverage); iter.more (); iter.next ()) {
-      c->input->add (iter.get_glyph ());
+    unsigned int count = substitute.len;
+    for (iter.init (this+coverage); iter.more (); iter.next ())
+    {
+      if (unlikely (iter.get_coverage () >= count))
+        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
       c->output->add (substitute[iter.get_coverage ()]);
     }
   }
@@ -147,7 +161,7 @@ struct SingleSubstFormat2
     return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
   }
 
-  inline bool apply (hb_apply_context_t *c) const
+  inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
     hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
@@ -181,7 +195,7 @@ struct SingleSubstFormat2
   }
 
   protected:
-  USHORT       format;                 /* Format identifier--format = 2 */
+  HBUINT16     format;                 /* Format identifier--format = 2 */
   OffsetTo<Coverage>
                coverage;               /* Offset to Coverage table--from
                                         * beginning of Substitution table */
@@ -235,7 +249,7 @@ struct SingleSubst
 
   protected:
   union {
-  USHORT               format;         /* Format identifier */
+  HBUINT16             format;         /* Format identifier */
   SingleSubstFormat1   format1;
   SingleSubstFormat2   format2;
   } u;
@@ -255,26 +269,14 @@ struct Sequence
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
-    unsigned int count = substitute.len;
-    for (unsigned int i = 0; i < count; i++)
-      c->output->add (substitute[i]);
+    c->output->add_array (substitute.array, substitute.len);
   }
 
-  inline bool apply (hb_apply_context_t *c) const
+  inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
     unsigned int count = substitute.len;
 
-    /* TODO:
-     * Testing shows that Uniscribe actually allows zero-len susbstitute,
-     * which essentially deletes a glyph.  We don't allow for now.  It
-     * can be confusing to the client since the cluster from the deleted
-     * glyph won't be merged with any output cluster...  Also, currently
-     * buffer->move_to() makes assumptions about this too.  Perhaps fix
-     * in the future after figuring out what to do with the clusters.
-     */
-    if (unlikely (!count)) return_trace (false);
-
     /* Special-case to make it in-place and not consider this
      * as a "multiplied" substitution. */
     if (unlikely (count == 1))
@@ -282,6 +284,13 @@ struct Sequence
       c->replace_glyph (substitute.array[0]);
       return_trace (true);
     }
+    /* Spec disallows this, but Uniscribe allows it.
+     * https://github.com/harfbuzz/harfbuzz/issues/253 */
+    else if (unlikely (count == 0))
+    {
+      c->buffer->delete_glyph ();
+      return_trace (true);
+    }
 
     unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ?
                         HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
@@ -324,7 +333,11 @@ struct MultipleSubstFormat1
   {
     TRACE_CLOSURE (this);
     Coverage::Iter iter;
-    for (iter.init (this+coverage); iter.more (); iter.next ()) {
+    unsigned int count = sequence.len;
+    for (iter.init (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+sequence[iter.get_coverage ()]).closure (c);
     }
@@ -333,7 +346,7 @@ struct MultipleSubstFormat1
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
-    (this+coverage).add_coverage (c->input);
+    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);
@@ -350,7 +363,7 @@ struct MultipleSubstFormat1
     return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
   }
 
-  inline bool apply (hb_apply_context_t *c) const
+  inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
 
@@ -373,7 +386,7 @@ struct MultipleSubstFormat1
       if (unlikely (!sequence[i].serialize (c, this).serialize (c,
                                                                substitute_glyphs_list,
                                                                substitute_len_list[i]))) return_trace (false);
-    substitute_len_list.advance (num_glyphs);
+    substitute_len_list += num_glyphs;
     if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
     return_trace (true);
   }
@@ -385,7 +398,7 @@ struct MultipleSubstFormat1
   }
 
   protected:
-  USHORT       format;                 /* Format identifier--format = 1 */
+  HBUINT16     format;                 /* Format identifier--format = 1 */
   OffsetTo<Coverage>
                coverage;               /* Offset to Coverage table--from
                                         * beginning of Substitution table */
@@ -427,7 +440,7 @@ struct MultipleSubst
 
   protected:
   union {
-  USHORT               format;         /* Format identifier */
+  HBUINT16             format;         /* Format identifier */
   MultipleSubstFormat1 format1;
   } u;
 };
@@ -442,7 +455,11 @@ struct AlternateSubstFormat1
   {
     TRACE_CLOSURE (this);
     Coverage::Iter iter;
-    for (iter.init (this+coverage); iter.more (); iter.next ()) {
+    unsigned int count = alternateSet.len;
+    for (iter.init (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 ())) {
        const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
        unsigned int count = alt_set.len;
@@ -455,13 +472,15 @@ struct AlternateSubstFormat1
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
+    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
     Coverage::Iter iter;
-    for (iter.init (this+coverage); iter.more (); iter.next ()) {
-      c->input->add (iter.get_glyph ());
+    unsigned int count = alternateSet.len;
+    for (iter.init (this+coverage); iter.more (); iter.next ())
+    {
+      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 ()];
-      unsigned int count = alt_set.len;
-      for (unsigned int i = 0; i < count; i++)
-       c->output->add (alt_set[i]);
+      c->output->add_array (alt_set.array, alt_set.len);
     }
   }
 
@@ -476,7 +495,7 @@ struct AlternateSubstFormat1
     return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
   }
 
-  inline bool apply (hb_apply_context_t *c) const
+  inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
     hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
@@ -517,7 +536,7 @@ struct AlternateSubstFormat1
       if (unlikely (!alternateSet[i].serialize (c, this).serialize (c,
                                                                    alternate_glyphs_list,
                                                                    alternate_len_list[i]))) return_trace (false);
-    alternate_len_list.advance (num_glyphs);
+    alternate_len_list += num_glyphs;
     if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
     return_trace (true);
   }
@@ -529,7 +548,7 @@ struct AlternateSubstFormat1
   }
 
   protected:
-  USHORT       format;                 /* Format identifier--format = 1 */
+  HBUINT16     format;                 /* Format identifier--format = 1 */
   OffsetTo<Coverage>
                coverage;               /* Offset to Coverage table--from
                                         * beginning of Substitution table */
@@ -571,7 +590,7 @@ struct AlternateSubst
 
   protected:
   union {
-  USHORT               format;         /* Format identifier */
+  HBUINT16             format;         /* Format identifier */
   AlternateSubstFormat1        format1;
   } u;
 };
@@ -592,9 +611,7 @@ struct Ligature
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
-    unsigned int count = component.len;
-    for (unsigned int i = 1; i < count; i++)
-      c->input->add (component[i]);
+    c->input->add_array (component.array, component.len ? component.len - 1 : 0);
     c->output->add (ligGlyph);
   }
 
@@ -611,7 +628,7 @@ struct Ligature
     return_trace (true);
   }
 
-  inline bool apply (hb_apply_context_t *c) const
+  inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
     unsigned int count = component.len;
@@ -635,7 +652,7 @@ struct Ligature
     if (likely (!match_input (c, count,
                              &component[1],
                              match_glyph,
-                             NULL,
+                             nullptr,
                              &match_length,
                              match_positions,
                              &is_mark_ligature,
@@ -713,7 +730,7 @@ struct LigatureSet
     return_trace (false);
   }
 
-  inline bool apply (hb_apply_context_t *c) const
+  inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
     unsigned int num_ligs = ligature.len;
@@ -740,8 +757,8 @@ struct LigatureSet
                                                                ligatures[i],
                                                                component_list,
                                                                component_count_list[i]))) return_trace (false);
-    ligatures.advance (num_ligatures);
-    component_count_list.advance (num_ligatures);
+    ligatures += num_ligatures;
+    component_count_list += num_ligatures;
     return_trace (true);
   }
 
@@ -765,7 +782,11 @@ struct LigatureSubstFormat1
   {
     TRACE_CLOSURE (this);
     Coverage::Iter iter;
-    for (iter.init (this+coverage); iter.more (); iter.next ()) {
+    unsigned int count = ligatureSet.len;
+    for (iter.init (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+ligatureSet[iter.get_coverage ()]).closure (c);
     }
@@ -774,9 +795,13 @@ struct LigatureSubstFormat1
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
+    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
     Coverage::Iter iter;
-    for (iter.init (this+coverage); iter.more (); iter.next ()) {
-      c->input->add (iter.get_glyph ());
+    unsigned int count = ligatureSet.len;
+    for (iter.init (this+coverage); iter.more (); iter.next ())
+    {
+      if (unlikely (iter.get_coverage () >= count))
+        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
       (this+ligatureSet[iter.get_coverage ()]).collect_glyphs (c);
     }
   }
@@ -796,7 +821,7 @@ struct LigatureSubstFormat1
     return_trace (lig_set.would_apply (c));
   }
 
-  inline bool apply (hb_apply_context_t *c) const
+  inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
     hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
@@ -825,7 +850,7 @@ struct LigatureSubstFormat1
                                                                   component_count_list,
                                                                   ligature_per_first_glyph_count_list[i],
                                                                   component_list))) return_trace (false);
-    ligature_per_first_glyph_count_list.advance (num_first_glyphs);
+    ligature_per_first_glyph_count_list += num_first_glyphs;
     if (unlikely (!coverage.serialize (c, this).serialize (c, first_glyphs, num_first_glyphs))) return_trace (false);
     return_trace (true);
   }
@@ -837,7 +862,7 @@ struct LigatureSubstFormat1
   }
 
   protected:
-  USHORT       format;                 /* Format identifier--format = 1 */
+  HBUINT16     format;                 /* Format identifier--format = 1 */
   OffsetTo<Coverage>
                coverage;               /* Offset to Coverage table--from
                                         * beginning of Substitution table */
@@ -887,7 +912,7 @@ struct LigatureSubst
 
   protected:
   union {
-  USHORT               format;         /* Format identifier */
+  HBUINT16             format;         /* Format identifier */
   LigatureSubstFormat1 format1;
   } u;
 };
@@ -926,7 +951,11 @@ struct ReverseChainSingleSubstFormat1
 
     const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
     Coverage::Iter iter;
-    for (iter.init (this+coverage); iter.more (); iter.next ()) {
+    count = substitute.len;
+    for (iter.init (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 ()))
        c->glyphs->add (substitute[iter.get_coverage ()]);
     }
@@ -935,25 +964,22 @@ struct ReverseChainSingleSubstFormat1
   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   {
     TRACE_COLLECT_GLYPHS (this);
-
-    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
 
     unsigned int count;
 
-    (this+coverage).add_coverage (c->input);
-
     count = backtrack.len;
     for (unsigned int i = 0; i < count; i++)
-      (this+backtrack[i]).add_coverage (c->before);
+      if (unlikely (!(this+backtrack[i]).add_coverage (c->before))) return;
 
+    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
     count = lookahead.len;
     for (unsigned int i = 0; i < count; i++)
-      (this+lookahead[i]).add_coverage (c->after);
+      if (unlikely (!(this+lookahead[i]).add_coverage (c->after))) return;
 
     const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
     count = substitute.len;
-    for (unsigned int i = 0; i < count; i++)
-      c->output->add (substitute[i]);
+    c->output->add_array (substitute.array, substitute.len);
   }
 
   inline const Coverage &get_coverage (void) const
@@ -967,7 +993,7 @@ struct ReverseChainSingleSubstFormat1
     return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
   }
 
-  inline bool apply (hb_apply_context_t *c) const
+  inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
     if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
@@ -979,14 +1005,17 @@ struct ReverseChainSingleSubstFormat1
     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
     const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
 
+  unsigned int start_index = 0, end_index = 0;
     if (match_backtrack (c,
-                        backtrack.len, (USHORT *) backtrack.array,
-                        match_coverage, this) &&
+                        backtrack.len, (HBUINT16 *) backtrack.array,
+                        match_coverage, this,
+                        &start_index) &&
         match_lookahead (c,
-                        lookahead.len, (USHORT *) lookahead.array,
+                        lookahead.len, (HBUINT16 *) lookahead.array,
                         match_coverage, this,
-                        1))
+                        1, &end_index))
     {
+      c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index);
       c->replace_glyph_inplace (substitute[index]);
       /* Note: We DON'T decrease buffer->idx.  The main loop does it
        * for us.  This is useful for preventing surprises if someone
@@ -1010,7 +1039,7 @@ struct ReverseChainSingleSubstFormat1
   }
 
   protected:
-  USHORT       format;                 /* Format identifier--format = 1 */
+  HBUINT16     format;                 /* Format identifier--format = 1 */
   OffsetTo<Coverage>
                coverage;               /* Offset to Coverage table--from
                                         * beginning of table */
@@ -1044,7 +1073,7 @@ struct ReverseChainSingleSubst
 
   protected:
   union {
-  USHORT                               format;         /* Format identifier */
+  HBUINT16                             format;         /* Format identifier */
   ReverseChainSingleSubstFormat1       format1;
   } u;
 };
@@ -1090,7 +1119,7 @@ struct SubstLookupSubTable
 
   protected:
   union {
-  USHORT                       sub_format;
+  HBUINT16                     sub_format;
   SingleSubst                  single;
   MultipleSubst                        multiple;
   AlternateSubst               alternate;
@@ -1121,7 +1150,7 @@ struct SubstLookup : Lookup
     return lookup_type_is_reverse (type);
   }
 
-  inline bool apply (hb_apply_context_t *c) const
+  inline bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
     return_trace (dispatch (c));
@@ -1157,7 +1186,7 @@ struct SubstLookup : Lookup
       return_trace (dispatch (c));
   }
 
-  static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);
+  static bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index);
 
   inline SubstLookupSubTable& serialize_subtable (hb_serialize_context_t *c,
                                                  unsigned int i)
@@ -1242,8 +1271,9 @@ struct SubstLookup : Lookup
     if (unlikely (get_type () == SubstLookupSubTable::Extension))
     {
       /* The spec says all subtables of an Extension lookup should
-       * have the same type.  This is specially important if one has
-       * a reverse type! */
+       * have the same type, which shall not be the Extension type
+       * itself (but we already checked for that).
+       * This is specially important if one has a reverse type! */
       unsigned int type = get_subtable (0).u.extension.get_type ();
       unsigned int count = get_subtable_count ();
       for (unsigned int i = 1; i < count; i++)
@@ -1276,8 +1306,6 @@ struct GSUB : GSUBGPOS
     const OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
     return_trace (list.sanitize (c, this));
   }
-  public:
-  DEFINE_SIZE_STATIC (10);
 };
 
 
@@ -1288,28 +1316,10 @@ GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer)
 
   const GDEF &gdef = *hb_ot_layout_from_face (font->face)->gdef;
   unsigned int count = buffer->len;
-  hb_glyph_info_t *info = buffer->info;
   for (unsigned int i = 0; i < count; i++)
   {
-    unsigned int props = gdef.get_glyph_props (info[i].codepoint);
-    if (!props)
-    {
-      /* Never mark default-ignorables as marks.
-       * They won't get in the way of lookups anyway,
-       * but having them as mark will cause them to be skipped
-       * over if the lookup-flag says so, but at least for the
-       * Mongolian variation selectors, looks like Uniscribe
-       * marks them as non-mark.  Some Mongolian fonts without
-       * GDEF rely on this.  Another notable character that
-       * this applies to is COMBINING GRAPHEME JOINER. */
-      props = (_hb_glyph_info_get_general_category (&info[i]) !=
-              HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK ||
-              _hb_glyph_info_is_default_ignorable (&info[i])) ?
-             HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH :
-             HB_OT_LAYOUT_GLYPH_PROPS_MARK;
-    }
-    _hb_glyph_info_set_glyph_props (&info[i], props);
-    _hb_glyph_info_clear_lig_props (&info[i]);
+    _hb_glyph_info_set_glyph_props (&buffer->info[i], gdef.get_glyph_props (buffer->info[i].codepoint));
+    _hb_glyph_info_clear_lig_props (&buffer->info[i]);
     buffer->info[i].syllable() = 0;
   }
 }
@@ -1333,7 +1343,7 @@ template <typename context_t>
   return l.dispatch (c);
 }
 
-/*static*/ inline bool SubstLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
+/*static*/ inline bool SubstLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index)
 {
   const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
   const SubstLookup &l = gsub.get_lookup (lookup_index);