src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-layout-gsubgpos-private.hh
changeset 48274 51772bf1fb0c
parent 47216 71c04702a3d5
child 50352 25db2c8f3cf8
equal deleted inserted replaced
48273:e2065f7505eb 48274:51772bf1fb0c
    27  */
    27  */
    28 
    28 
    29 #ifndef HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH
    29 #ifndef HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH
    30 #define HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH
    30 #define HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH
    31 
    31 
       
    32 #include "hb-private.hh"
       
    33 #include "hb-debug.hh"
    32 #include "hb-buffer-private.hh"
    34 #include "hb-buffer-private.hh"
    33 #include "hb-ot-layout-gdef-table.hh"
    35 #include "hb-ot-layout-gdef-table.hh"
    34 #include "hb-set-private.hh"
    36 #include "hb-set-private.hh"
    35 
    37 
    36 
    38 
    37 namespace OT {
    39 namespace OT {
    38 
    40 
    39 
       
    40 #ifndef HB_DEBUG_CLOSURE
       
    41 #define HB_DEBUG_CLOSURE (HB_DEBUG+0)
       
    42 #endif
       
    43 
       
    44 #define TRACE_CLOSURE(this) \
       
    45         hb_auto_trace_t<HB_DEBUG_CLOSURE, hb_void_t> trace \
       
    46         (&c->debug_depth, c->get_name (), this, HB_FUNC, \
       
    47          "");
       
    48 
    41 
    49 struct hb_closure_context_t :
    42 struct hb_closure_context_t :
    50        hb_dispatch_context_t<hb_closure_context_t, hb_void_t, HB_DEBUG_CLOSURE>
    43        hb_dispatch_context_t<hb_closure_context_t, hb_void_t, HB_DEBUG_CLOSURE>
    51 {
    44 {
    52   inline const char *get_name (void) { return "CLOSURE"; }
    45   inline const char *get_name (void) { return "CLOSURE"; }
    75   hb_closure_context_t (hb_face_t *face_,
    68   hb_closure_context_t (hb_face_t *face_,
    76                         hb_set_t *glyphs_,
    69                         hb_set_t *glyphs_,
    77                         unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
    70                         unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
    78                           face (face_),
    71                           face (face_),
    79                           glyphs (glyphs_),
    72                           glyphs (glyphs_),
    80                           recurse_func (NULL),
    73                           recurse_func (nullptr),
    81                           nesting_level_left (nesting_level_left_),
    74                           nesting_level_left (nesting_level_left_),
    82                           debug_depth (0) {}
    75                           debug_depth (0) {}
    83 
    76 
    84   void set_recurse_func (recurse_func_t func) { recurse_func = func; }
    77   void set_recurse_func (recurse_func_t func) { recurse_func = func; }
    85 };
    78 };
    86 
    79 
    87 
       
    88 
       
    89 #ifndef HB_DEBUG_WOULD_APPLY
       
    90 #define HB_DEBUG_WOULD_APPLY (HB_DEBUG+0)
       
    91 #endif
       
    92 
       
    93 #define TRACE_WOULD_APPLY(this) \
       
    94         hb_auto_trace_t<HB_DEBUG_WOULD_APPLY, bool> trace \
       
    95         (&c->debug_depth, c->get_name (), this, HB_FUNC, \
       
    96          "%d glyphs", c->len);
       
    97 
    80 
    98 struct hb_would_apply_context_t :
    81 struct hb_would_apply_context_t :
    99        hb_dispatch_context_t<hb_would_apply_context_t, bool, HB_DEBUG_WOULD_APPLY>
    82        hb_dispatch_context_t<hb_would_apply_context_t, bool, HB_DEBUG_WOULD_APPLY>
   100 {
    83 {
   101   inline const char *get_name (void) { return "WOULD_APPLY"; }
    84   inline const char *get_name (void) { return "WOULD_APPLY"; }
   120                               zero_context (zero_context_),
   103                               zero_context (zero_context_),
   121                               debug_depth (0) {}
   104                               debug_depth (0) {}
   122 };
   105 };
   123 
   106 
   124 
   107 
   125 
       
   126 #ifndef HB_DEBUG_COLLECT_GLYPHS
       
   127 #define HB_DEBUG_COLLECT_GLYPHS (HB_DEBUG+0)
       
   128 #endif
       
   129 
       
   130 #define TRACE_COLLECT_GLYPHS(this) \
       
   131         hb_auto_trace_t<HB_DEBUG_COLLECT_GLYPHS, hb_void_t> trace \
       
   132         (&c->debug_depth, c->get_name (), this, HB_FUNC, \
       
   133          "");
       
   134 
       
   135 struct hb_collect_glyphs_context_t :
   108 struct hb_collect_glyphs_context_t :
   136        hb_dispatch_context_t<hb_collect_glyphs_context_t, hb_void_t, HB_DEBUG_COLLECT_GLYPHS>
   109        hb_dispatch_context_t<hb_collect_glyphs_context_t, hb_void_t, HB_DEBUG_COLLECT_GLYPHS>
   137 {
   110 {
   138   inline const char *get_name (void) { return "COLLECT_GLYPHS"; }
   111   inline const char *get_name (void) { return "COLLECT_GLYPHS"; }
   139   typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index);
   112   typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index);
   144   return_t recurse (unsigned int lookup_index)
   117   return_t recurse (unsigned int lookup_index)
   145   {
   118   {
   146     if (unlikely (nesting_level_left == 0 || !recurse_func))
   119     if (unlikely (nesting_level_left == 0 || !recurse_func))
   147       return default_return_value ();
   120       return default_return_value ();
   148 
   121 
   149     /* Note that GPOS sets recurse_func to NULL already, so it doesn't get
   122     /* Note that GPOS sets recurse_func to nullptr already, so it doesn't get
   150      * past the previous check.  For GSUB, we only want to collect the output
   123      * past the previous check.  For GSUB, we only want to collect the output
   151      * glyphs in the recursion.  If output is not requested, we can go home now.
   124      * glyphs in the recursion.  If output is not requested, we can go home now.
   152      *
   125      *
   153      * Note further, that the above is not exactly correct.  A recursed lookup
   126      * Note further, that the above is not exactly correct.  A recursed lookup
   154      * is allowed to match input that is not matched in the context, but that's
   127      * is allowed to match input that is not matched in the context, but that's
   158 
   131 
   159     if (output == hb_set_get_empty ())
   132     if (output == hb_set_get_empty ())
   160       return HB_VOID;
   133       return HB_VOID;
   161 
   134 
   162     /* Return if new lookup was recursed to before. */
   135     /* Return if new lookup was recursed to before. */
   163     if (recursed_lookups.has (lookup_index))
   136     if (recursed_lookups->has (lookup_index))
   164       return HB_VOID;
   137       return HB_VOID;
   165 
   138 
   166     hb_set_t *old_before = before;
   139     hb_set_t *old_before = before;
   167     hb_set_t *old_input  = input;
   140     hb_set_t *old_input  = input;
   168     hb_set_t *old_after  = after;
   141     hb_set_t *old_after  = after;
   174 
   147 
   175     before = old_before;
   148     before = old_before;
   176     input  = old_input;
   149     input  = old_input;
   177     after  = old_after;
   150     after  = old_after;
   178 
   151 
   179     recursed_lookups.add (lookup_index);
   152     recursed_lookups->add (lookup_index);
   180 
   153 
   181     return HB_VOID;
   154     return HB_VOID;
   182   }
   155   }
   183 
   156 
   184   hb_face_t *face;
   157   hb_face_t *face;
   185   hb_set_t *before;
   158   hb_set_t *before;
   186   hb_set_t *input;
   159   hb_set_t *input;
   187   hb_set_t *after;
   160   hb_set_t *after;
   188   hb_set_t *output;
   161   hb_set_t *output;
   189   recurse_func_t recurse_func;
   162   recurse_func_t recurse_func;
   190   hb_set_t recursed_lookups;
   163   hb_set_t *recursed_lookups;
   191   unsigned int nesting_level_left;
   164   unsigned int nesting_level_left;
   192   unsigned int debug_depth;
   165   unsigned int debug_depth;
   193 
   166 
   194   hb_collect_glyphs_context_t (hb_face_t *face_,
   167   hb_collect_glyphs_context_t (hb_face_t *face_,
   195                                hb_set_t  *glyphs_before, /* OUT. May be NULL */
   168                                hb_set_t  *glyphs_before, /* OUT. May be nullptr */
   196                                hb_set_t  *glyphs_input,  /* OUT. May be NULL */
   169                                hb_set_t  *glyphs_input,  /* OUT. May be nullptr */
   197                                hb_set_t  *glyphs_after,  /* OUT. May be NULL */
   170                                hb_set_t  *glyphs_after,  /* OUT. May be nullptr */
   198                                hb_set_t  *glyphs_output, /* OUT. May be NULL */
   171                                hb_set_t  *glyphs_output, /* OUT. May be nullptr */
   199                                unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
   172                                unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
   200                               face (face_),
   173                               face (face_),
   201                               before (glyphs_before ? glyphs_before : hb_set_get_empty ()),
   174                               before (glyphs_before ? glyphs_before : hb_set_get_empty ()),
   202                               input  (glyphs_input  ? glyphs_input  : hb_set_get_empty ()),
   175                               input  (glyphs_input  ? glyphs_input  : hb_set_get_empty ()),
   203                               after  (glyphs_after  ? glyphs_after  : hb_set_get_empty ()),
   176                               after  (glyphs_after  ? glyphs_after  : hb_set_get_empty ()),
   204                               output (glyphs_output ? glyphs_output : hb_set_get_empty ()),
   177                               output (glyphs_output ? glyphs_output : hb_set_get_empty ()),
   205                               recurse_func (NULL),
   178                               recurse_func (nullptr),
   206                               recursed_lookups (),
   179                               recursed_lookups (nullptr),
   207                               nesting_level_left (nesting_level_left_),
   180                               nesting_level_left (nesting_level_left_),
   208                               debug_depth (0)
   181                               debug_depth (0)
   209   {
   182   {
   210     recursed_lookups.init ();
   183     recursed_lookups = hb_set_create ();
   211   }
   184   }
   212   ~hb_collect_glyphs_context_t (void)
   185   ~hb_collect_glyphs_context_t (void)
   213   {
   186   {
   214     recursed_lookups.fini ();
   187     hb_set_destroy (recursed_lookups);
   215   }
   188   }
   216 
   189 
   217   void set_recurse_func (recurse_func_t func) { recurse_func = func; }
   190   void set_recurse_func (recurse_func_t func) { recurse_func = func; }
   218 };
   191 };
   219 
   192 
   220 
   193 
   221 
       
   222 #ifndef HB_DEBUG_GET_COVERAGE
       
   223 #define HB_DEBUG_GET_COVERAGE (HB_DEBUG+0)
       
   224 #endif
       
   225 
   194 
   226 /* XXX Can we remove this? */
   195 /* XXX Can we remove this? */
   227 
   196 
   228 template <typename set_t>
   197 template <typename set_t>
   229 struct hb_add_coverage_context_t :
   198 struct hb_add_coverage_context_t :
   246 
   215 
   247   set_t *set;
   216   set_t *set;
   248   unsigned int debug_depth;
   217   unsigned int debug_depth;
   249 };
   218 };
   250 
   219 
   251 
       
   252 
       
   253 #ifndef HB_DEBUG_APPLY
       
   254 #define HB_DEBUG_APPLY (HB_DEBUG+0)
       
   255 #endif
       
   256 
       
   257 #define TRACE_APPLY(this) \
       
   258         hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace \
       
   259         (&c->debug_depth, c->get_name (), this, HB_FUNC, \
       
   260          "idx %d gid %u lookup %d", \
       
   261          c->buffer->idx, c->buffer->cur().codepoint, (int) c->lookup_index);
       
   262 
   220 
   263 struct hb_apply_context_t :
   221 struct hb_apply_context_t :
   264        hb_dispatch_context_t<hb_apply_context_t, bool, HB_DEBUG_APPLY>
   222        hb_dispatch_context_t<hb_apply_context_t, bool, HB_DEBUG_APPLY>
   265 {
   223 {
   266   struct matcher_t
   224   struct matcher_t
   271              ignore_zwj (false),
   229              ignore_zwj (false),
   272              mask (-1),
   230              mask (-1),
   273 #define arg1(arg) (arg) /* Remove the macro to see why it's needed! */
   231 #define arg1(arg) (arg) /* Remove the macro to see why it's needed! */
   274              syllable arg1(0),
   232              syllable arg1(0),
   275 #undef arg1
   233 #undef arg1
   276              match_func (NULL),
   234              match_func (nullptr),
   277              match_data (NULL) {};
   235              match_data (nullptr) {};
   278 
   236 
   279     typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data);
   237     typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data);
   280 
   238 
   281     inline void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; }
   239     inline void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; }
   282     inline void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
   240     inline void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
   317               const hb_glyph_info_t    &info) const
   275               const hb_glyph_info_t    &info) const
   318     {
   276     {
   319       if (!c->check_glyph_property (&info, lookup_props))
   277       if (!c->check_glyph_property (&info, lookup_props))
   320         return SKIP_YES;
   278         return SKIP_YES;
   321 
   279 
   322       if (unlikely (_hb_glyph_info_is_default_ignorable_and_not_fvs (&info) &&
   280       if (unlikely (_hb_glyph_info_is_default_ignorable_and_not_hidden (&info) &&
   323                     (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) &&
   281                     (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) &&
   324                     (ignore_zwj || !_hb_glyph_info_is_zwj (&info))))
   282                     (ignore_zwj || !_hb_glyph_info_is_zwj (&info))))
   325         return SKIP_MAYBE;
   283         return SKIP_MAYBE;
   326 
   284 
   327       return SKIP_NO;
   285       return SKIP_NO;
   340   struct skipping_iterator_t
   298   struct skipping_iterator_t
   341   {
   299   {
   342     inline void init (hb_apply_context_t *c_, bool context_match = false)
   300     inline void init (hb_apply_context_t *c_, bool context_match = false)
   343     {
   301     {
   344       c = c_;
   302       c = c_;
   345       match_glyph_data = NULL,
   303       match_glyph_data = nullptr;
   346       matcher.set_match_func (NULL, NULL);
   304       matcher.set_match_func (nullptr, nullptr);
   347       matcher.set_lookup_props (c->lookup_props);
   305       matcher.set_lookup_props (c->lookup_props);
   348       /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
   306       /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
   349       matcher.set_ignore_zwnj (context_match || c->table_index == 1);
   307       matcher.set_ignore_zwnj (c->table_index == 1 || (context_match && c->auto_zwnj));
   350       /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */
   308       /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */
   351       matcher.set_ignore_zwj (context_match || c->table_index == 1 || c->auto_zwj);
   309       matcher.set_ignore_zwj  (c->table_index == 1 || (context_match || c->auto_zwj));
   352       matcher.set_mask (context_match ? -1 : c->lookup_mask);
   310       matcher.set_mask (context_match ? -1 : c->lookup_mask);
   353     }
   311     }
   354     inline void set_lookup_props (unsigned int lookup_props)
   312     inline void set_lookup_props (unsigned int lookup_props)
   355     {
   313     {
   356       matcher.set_lookup_props (lookup_props);
   314       matcher.set_lookup_props (lookup_props);
   371       end = c->buffer->len;
   329       end = c->buffer->len;
   372       matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
   330       matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
   373     }
   331     }
   374 
   332 
   375     inline void reject (void) { num_items++; match_glyph_data--; }
   333     inline void reject (void) { num_items++; match_glyph_data--; }
       
   334 
       
   335     inline matcher_t::may_skip_t
       
   336     may_skip (const hb_apply_context_t *c,
       
   337               const hb_glyph_info_t    &info) const
       
   338     {
       
   339       return matcher.may_skip (c, info);
       
   340     }
   376 
   341 
   377     inline bool next (void)
   342     inline bool next (void)
   378     {
   343     {
   379       assert (num_items > 0);
   344       assert (num_items > 0);
   380       while (idx + num_items < end)
   345       while (idx + num_items < end)
   455     bool ret = recurse_func (this, lookup_index);
   420     bool ret = recurse_func (this, lookup_index);
   456     nesting_level_left++;
   421     nesting_level_left++;
   457     return ret;
   422     return ret;
   458   }
   423   }
   459 
   424 
   460   unsigned int table_index; /* GSUB/GPOS */
   425   skipping_iterator_t iter_input, iter_context;
       
   426 
   461   hb_font_t *font;
   427   hb_font_t *font;
   462   hb_face_t *face;
   428   hb_face_t *face;
   463   hb_buffer_t *buffer;
   429   hb_buffer_t *buffer;
       
   430   recurse_func_t recurse_func;
       
   431   const GDEF &gdef;
       
   432   const VariationStore &var_store;
       
   433 
   464   hb_direction_t direction;
   434   hb_direction_t direction;
   465   hb_mask_t lookup_mask;
   435   hb_mask_t lookup_mask;
       
   436   unsigned int table_index; /* GSUB/GPOS */
       
   437   unsigned int lookup_index;
       
   438   unsigned int lookup_props;
       
   439   unsigned int nesting_level_left;
       
   440   unsigned int debug_depth;
       
   441 
       
   442   bool auto_zwnj;
   466   bool auto_zwj;
   443   bool auto_zwj;
   467   recurse_func_t recurse_func;
       
   468   unsigned int nesting_level_left;
       
   469   unsigned int lookup_props;
       
   470   const GDEF &gdef;
       
   471   bool has_glyph_classes;
   444   bool has_glyph_classes;
   472   const VariationStore &var_store;
       
   473   skipping_iterator_t iter_input, iter_context;
       
   474   unsigned int lookup_index;
       
   475   unsigned int debug_depth;
       
   476 
   445 
   477 
   446 
   478   hb_apply_context_t (unsigned int table_index_,
   447   hb_apply_context_t (unsigned int table_index_,
   479                       hb_font_t *font_,
   448                       hb_font_t *font_,
   480                       hb_buffer_t *buffer_) :
   449                       hb_buffer_t *buffer_) :
   481                         table_index (table_index_),
   450                         iter_input (), iter_context (),
   482                         font (font_), face (font->face), buffer (buffer_),
   451                         font (font_), face (font->face), buffer (buffer_),
       
   452                         recurse_func (nullptr),
       
   453                         gdef (*hb_ot_layout_from_face (face)->gdef),
       
   454                         var_store (gdef.get_var_store ()),
   483                         direction (buffer_->props.direction),
   455                         direction (buffer_->props.direction),
   484                         lookup_mask (1),
   456                         lookup_mask (1),
       
   457                         table_index (table_index_),
       
   458                         lookup_index ((unsigned int) -1),
       
   459                         lookup_props (0),
       
   460                         nesting_level_left (HB_MAX_NESTING_LEVEL),
       
   461                         debug_depth (0),
       
   462                         auto_zwnj (true),
   485                         auto_zwj (true),
   463                         auto_zwj (true),
   486                         recurse_func (NULL),
   464                         has_glyph_classes (gdef.has_glyph_classes ()) {}
   487                         nesting_level_left (HB_MAX_NESTING_LEVEL),
       
   488                         lookup_props (0),
       
   489                         gdef (*hb_ot_layout_from_face (face)->gdef),
       
   490                         has_glyph_classes (gdef.has_glyph_classes ()),
       
   491                         var_store (gdef.get_var_store ()),
       
   492                         iter_input (),
       
   493                         iter_context (),
       
   494                         lookup_index ((unsigned int) -1),
       
   495                         debug_depth (0) {}
       
   496 
   465 
   497   inline void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; }
   466   inline void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; }
   498   inline void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; }
   467   inline void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; }
       
   468   inline void set_auto_zwnj (bool auto_zwnj_) { auto_zwnj = auto_zwnj_; }
   499   inline void set_recurse_func (recurse_func_t func) { recurse_func = func; }
   469   inline void set_recurse_func (recurse_func_t func) { recurse_func = func; }
   500   inline void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; }
   470   inline void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; }
   501   inline void set_lookup_props (unsigned int lookup_props_)
   471   inline void set_lookup_props (unsigned int lookup_props_)
   502   {
   472   {
   503     lookup_props = lookup_props_;
   473     lookup_props = lookup_props_;
   705                                 const USHORT input[], /* Array of input values--start with second glyph */
   675                                 const USHORT input[], /* Array of input values--start with second glyph */
   706                                 match_func_t match_func,
   676                                 match_func_t match_func,
   707                                 const void *match_data,
   677                                 const void *match_data,
   708                                 unsigned int *end_offset,
   678                                 unsigned int *end_offset,
   709                                 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],
   679                                 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],
   710                                 bool *p_is_mark_ligature = NULL,
   680                                 bool *p_is_mark_ligature = nullptr,
   711                                 unsigned int *p_total_component_count = NULL)
   681                                 unsigned int *p_total_component_count = nullptr)
   712 {
   682 {
   713   TRACE_APPLY (NULL);
   683   TRACE_APPLY (nullptr);
   714 
   684 
   715   if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return_trace (false);
   685   if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return_trace (false);
   716 
   686 
   717   hb_buffer_t *buffer = c->buffer;
   687   hb_buffer_t *buffer = c->buffer;
   718 
   688 
   729    *   it as a ligature glyph.
   699    *   it as a ligature glyph.
   730    *
   700    *
   731    * - Ligatures cannot be formed across glyphs attached to different components
   701    * - Ligatures cannot be formed across glyphs attached to different components
   732    *   of previous ligatures.  Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and
   702    *   of previous ligatures.  Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and
   733    *   LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother.
   703    *   LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother.
   734    *   However, it would be wrong to ligate that SHADDA,FATHA sequence.o
   704    *   However, it would be wrong to ligate that SHADDA,FATHA sequence.
   735    *   There is an exception to this: If a ligature tries ligating with marks that
   705    *   There are a couple of exceptions to this:
   736    *   belong to it itself, go ahead, assuming that the font designer knows what
   706    *
   737    *   they are doing (otherwise it can break Indic stuff when a matra wants to
   707    *   o If a ligature tries ligating with marks that belong to it itself, go ahead,
   738    *   ligate with a conjunct...)
   708    *     assuming that the font designer knows what they are doing (otherwise it can
       
   709    *     break Indic stuff when a matra wants to ligate with a conjunct,
       
   710    *
       
   711    *   o If two marks want to ligate and they belong to different components of the
       
   712    *     same ligature glyph, and said ligature glyph is to be ignored according to
       
   713    *     mark-filtering rules, then allow.
       
   714    *     https://github.com/behdad/harfbuzz/issues/545
   739    */
   715    */
   740 
   716 
   741   bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->cur());
   717   bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->cur());
   742 
   718 
   743   unsigned int total_component_count = 0;
   719   unsigned int total_component_count = 0;
   744   total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur());
   720   total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur());
   745 
   721 
   746   unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
   722   unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
   747   unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
   723   unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
   748 
   724 
       
   725   enum {
       
   726     LIGBASE_NOT_CHECKED,
       
   727     LIGBASE_MAY_NOT_SKIP,
       
   728     LIGBASE_MAY_SKIP
       
   729   } ligbase = LIGBASE_NOT_CHECKED;
       
   730 
   749   match_positions[0] = buffer->idx;
   731   match_positions[0] = buffer->idx;
   750   for (unsigned int i = 1; i < count; i++)
   732   for (unsigned int i = 1; i < count; i++)
   751   {
   733   {
   752     if (!skippy_iter.next ()) return_trace (false);
   734     if (!skippy_iter.next ()) return_trace (false);
   753 
   735 
   754     match_positions[i] = skippy_iter.idx;
   736     match_positions[i] = skippy_iter.idx;
   755 
   737 
   756     unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]);
   738     unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]);
   757     unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]);
   739     unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]);
   758 
   740 
   759     if (first_lig_id && first_lig_comp) {
   741     if (first_lig_id && first_lig_comp)
       
   742     {
   760       /* If first component was attached to a previous ligature component,
   743       /* If first component was attached to a previous ligature component,
   761        * all subsequent components should be attached to the same ligature
   744        * all subsequent components should be attached to the same ligature
   762        * component, otherwise we shouldn't ligate them. */
   745        * component, otherwise we shouldn't ligate them... */
   763       if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
   746       if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
   764         return_trace (false);
   747       {
   765     } else {
   748         /* ...unless, we are attached to a base ligature and that base
       
   749          * ligature is ignorable. */
       
   750         if (ligbase == LIGBASE_NOT_CHECKED)
       
   751         {
       
   752           bool found = false;
       
   753           const hb_glyph_info_t *out = buffer->out_info;
       
   754           unsigned int j = buffer->out_len;
       
   755           while (j && _hb_glyph_info_get_lig_id (&out[j - 1]) == first_lig_id)
       
   756           {
       
   757             if (_hb_glyph_info_get_lig_comp (&out[j - 1]) == 0)
       
   758             {
       
   759               j--;
       
   760               found = true;
       
   761               break;
       
   762             }
       
   763             j--;
       
   764           }
       
   765 
       
   766           if (found && skippy_iter.may_skip (c, out[j]) == hb_apply_context_t::matcher_t::SKIP_YES)
       
   767             ligbase = LIGBASE_MAY_SKIP;
       
   768           else
       
   769             ligbase = LIGBASE_MAY_NOT_SKIP;
       
   770         }
       
   771 
       
   772         if (ligbase == LIGBASE_MAY_NOT_SKIP)
       
   773           return_trace (false);
       
   774       }
       
   775     }
       
   776     else
       
   777     {
   766       /* If first component was NOT attached to a previous ligature component,
   778       /* If first component was NOT attached to a previous ligature component,
   767        * all subsequent components should also NOT be attached to any ligature
   779        * all subsequent components should also NOT be attached to any ligature
   768        * component, unless they are attached to the first component itself! */
   780        * component, unless they are attached to the first component itself! */
   769       if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id))
   781       if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id))
   770         return_trace (false);
   782         return_trace (false);
   790                                  unsigned int match_length,
   802                                  unsigned int match_length,
   791                                  hb_codepoint_t lig_glyph,
   803                                  hb_codepoint_t lig_glyph,
   792                                  bool is_mark_ligature,
   804                                  bool is_mark_ligature,
   793                                  unsigned int total_component_count)
   805                                  unsigned int total_component_count)
   794 {
   806 {
   795   TRACE_APPLY (NULL);
   807   TRACE_APPLY (nullptr);
   796 
   808 
   797   hb_buffer_t *buffer = c->buffer;
   809   hb_buffer_t *buffer = c->buffer;
   798 
   810 
   799   buffer->merge_clusters (buffer->idx, buffer->idx + match_length);
   811   buffer->merge_clusters (buffer->idx, buffer->idx + match_length);
   800 
   812 
   884 
   896 
   885 static inline bool match_backtrack (hb_apply_context_t *c,
   897 static inline bool match_backtrack (hb_apply_context_t *c,
   886                                     unsigned int count,
   898                                     unsigned int count,
   887                                     const USHORT backtrack[],
   899                                     const USHORT backtrack[],
   888                                     match_func_t match_func,
   900                                     match_func_t match_func,
   889                                     const void *match_data)
   901                                     const void *match_data,
   890 {
   902                                     unsigned int *match_start)
   891   TRACE_APPLY (NULL);
   903 {
       
   904   TRACE_APPLY (nullptr);
   892 
   905 
   893   hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
   906   hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
   894   skippy_iter.reset (c->buffer->backtrack_len (), count);
   907   skippy_iter.reset (c->buffer->backtrack_len (), count);
   895   skippy_iter.set_match_func (match_func, match_data, backtrack);
   908   skippy_iter.set_match_func (match_func, match_data, backtrack);
   896 
   909 
   897   for (unsigned int i = 0; i < count; i++)
   910   for (unsigned int i = 0; i < count; i++)
   898     if (!skippy_iter.prev ())
   911     if (!skippy_iter.prev ())
   899       return_trace (false);
   912       return_trace (false);
       
   913 
       
   914   *match_start = skippy_iter.idx;
   900 
   915 
   901   return_trace (true);
   916   return_trace (true);
   902 }
   917 }
   903 
   918 
   904 static inline bool match_lookahead (hb_apply_context_t *c,
   919 static inline bool match_lookahead (hb_apply_context_t *c,
   905                                     unsigned int count,
   920                                     unsigned int count,
   906                                     const USHORT lookahead[],
   921                                     const USHORT lookahead[],
   907                                     match_func_t match_func,
   922                                     match_func_t match_func,
   908                                     const void *match_data,
   923                                     const void *match_data,
   909                                     unsigned int offset)
   924                                     unsigned int offset,
   910 {
   925                                     unsigned int *end_index)
   911   TRACE_APPLY (NULL);
   926 {
       
   927   TRACE_APPLY (nullptr);
   912 
   928 
   913   hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
   929   hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
   914   skippy_iter.reset (c->buffer->idx + offset - 1, count);
   930   skippy_iter.reset (c->buffer->idx + offset - 1, count);
   915   skippy_iter.set_match_func (match_func, match_data, lookahead);
   931   skippy_iter.set_match_func (match_func, match_data, lookahead);
   916 
   932 
   917   for (unsigned int i = 0; i < count; i++)
   933   for (unsigned int i = 0; i < count; i++)
   918     if (!skippy_iter.next ())
   934     if (!skippy_iter.next ())
   919       return_trace (false);
   935       return_trace (false);
       
   936 
       
   937   *end_index = skippy_iter.idx + 1;
   920 
   938 
   921   return_trace (true);
   939   return_trace (true);
   922 }
   940 }
   923 
   941 
   924 
   942 
   954                                  unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
   972                                  unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
   955                                  unsigned int lookupCount,
   973                                  unsigned int lookupCount,
   956                                  const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
   974                                  const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
   957                                  unsigned int match_length)
   975                                  unsigned int match_length)
   958 {
   976 {
   959   TRACE_APPLY (NULL);
   977   TRACE_APPLY (nullptr);
   960 
   978 
   961   hb_buffer_t *buffer = c->buffer;
   979   hb_buffer_t *buffer = c->buffer;
   962   unsigned int end;
   980   int end;
   963 
   981 
   964   /* All positions are distance from beginning of *output* buffer.
   982   /* All positions are distance from beginning of *output* buffer.
   965    * Adjust. */
   983    * Adjust. */
   966   {
   984   {
   967     unsigned int bl = buffer->backtrack_len ();
   985     unsigned int bl = buffer->backtrack_len ();
   994     int delta = new_len - orig_len;
  1012     int delta = new_len - orig_len;
   995 
  1013 
   996     if (!delta)
  1014     if (!delta)
   997         continue;
  1015         continue;
   998 
  1016 
   999     /* Recursed lookup changed buffer len.  Adjust. */
  1017     /* Recursed lookup changed buffer len.  Adjust.
  1000 
  1018      *
  1001     end = int (end) + delta;
  1019      * TODO:
  1002     if (end <= match_positions[idx])
  1020      *
       
  1021      * Right now, if buffer length increased by n, we assume n new glyphs
       
  1022      * were added right after the current position, and if buffer length
       
  1023      * was decreased by n, we assume n match positions after the current
       
  1024      * one where removed.  The former (buffer length increased) case is
       
  1025      * fine, but the decrease case can be improved in at least two ways,
       
  1026      * both of which are significant:
       
  1027      *
       
  1028      *   - If recursed-to lookup is MultipleSubst and buffer length
       
  1029      *     decreased, then it's current match position that was deleted,
       
  1030      *     NOT the one after it.
       
  1031      *
       
  1032      *   - If buffer length was decreased by n, it does not necessarily
       
  1033      *     mean that n match positions where removed, as there might
       
  1034      *     have been marks and default-ignorables in the sequence.  We
       
  1035      *     should instead drop match positions between current-position
       
  1036      *     and current-position + n instead.
       
  1037      *
       
  1038      * It should be possible to construct tests for both of these cases.
       
  1039      */
       
  1040 
       
  1041     end += delta;
       
  1042     if (end <= int (match_positions[idx]))
  1003     {
  1043     {
  1004       /* End might end up being smaller than match_positions[idx] if the recursed
  1044       /* End might end up being smaller than match_positions[idx] if the recursed
  1005        * lookup ended up removing many items, more than we have had matched.
  1045        * lookup ended up removing many items, more than we have had matched.
  1006        * Just never rewind end back and get out of here.
  1046        * Just never rewind end back and get out of here.
  1007        * https://bugs.chromium.org/p/chromium/issues/detail?id=659496 */
  1047        * https://bugs.chromium.org/p/chromium/issues/detail?id=659496 */
  1116   unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
  1156   unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
  1117   return match_input (c,
  1157   return match_input (c,
  1118                       inputCount, input,
  1158                       inputCount, input,
  1119                       lookup_context.funcs.match, lookup_context.match_data,
  1159                       lookup_context.funcs.match, lookup_context.match_data,
  1120                       &match_length, match_positions)
  1160                       &match_length, match_positions)
  1121       && apply_lookup (c,
  1161       && (c->buffer->unsafe_to_break (c->buffer->idx, c->buffer->idx + match_length),
       
  1162           apply_lookup (c,
  1122                        inputCount, match_positions,
  1163                        inputCount, match_positions,
  1123                        lookupCount, lookupRecord,
  1164                        lookupCount, lookupRecord,
  1124                        match_length);
  1165                        match_length));
  1125 }
  1166 }
  1126 
  1167 
  1127 struct Rule
  1168 struct Rule
  1128 {
  1169 {
  1129   inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
  1170   inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
  1162 
  1203 
  1163   public:
  1204   public:
  1164   inline bool sanitize (hb_sanitize_context_t *c) const
  1205   inline bool sanitize (hb_sanitize_context_t *c) const
  1165   {
  1206   {
  1166     TRACE_SANITIZE (this);
  1207     TRACE_SANITIZE (this);
  1167     return inputCount.sanitize (c)
  1208     return_trace (inputCount.sanitize (c) &&
  1168         && lookupCount.sanitize (c)
  1209                   lookupCount.sanitize (c) &&
  1169         && c->check_range (inputZ,
  1210                   c->check_range (inputZ,
  1170                            inputZ[0].static_size * inputCount
  1211                                   inputZ[0].static_size * inputCount +
  1171                            + lookupRecordX[0].static_size * lookupCount);
  1212                                   lookupRecordX[0].static_size * lookupCount));
  1172   }
  1213   }
  1173 
  1214 
  1174   protected:
  1215   protected:
  1175   USHORT        inputCount;             /* Total number of glyphs in input
  1216   USHORT        inputCount;             /* Total number of glyphs in input
  1176                                          * glyph sequence--includes the first
  1217                                          * glyph sequence--includes the first
  1249 
  1290 
  1250     const Coverage &cov = (this+coverage);
  1291     const Coverage &cov = (this+coverage);
  1251 
  1292 
  1252     struct ContextClosureLookupContext lookup_context = {
  1293     struct ContextClosureLookupContext lookup_context = {
  1253       {intersects_glyph},
  1294       {intersects_glyph},
  1254       NULL
  1295       nullptr
  1255     };
  1296     };
  1256 
  1297 
  1257     unsigned int count = ruleSet.len;
  1298     unsigned int count = ruleSet.len;
  1258     for (unsigned int i = 0; i < count; i++)
  1299     for (unsigned int i = 0; i < count; i++)
  1259       if (cov.intersects_coverage (c->glyphs, i)) {
  1300       if (cov.intersects_coverage (c->glyphs, i)) {
  1267     TRACE_COLLECT_GLYPHS (this);
  1308     TRACE_COLLECT_GLYPHS (this);
  1268     (this+coverage).add_coverage (c->input);
  1309     (this+coverage).add_coverage (c->input);
  1269 
  1310 
  1270     struct ContextCollectGlyphsLookupContext lookup_context = {
  1311     struct ContextCollectGlyphsLookupContext lookup_context = {
  1271       {collect_glyph},
  1312       {collect_glyph},
  1272       NULL
  1313       nullptr
  1273     };
  1314     };
  1274 
  1315 
  1275     unsigned int count = ruleSet.len;
  1316     unsigned int count = ruleSet.len;
  1276     for (unsigned int i = 0; i < count; i++)
  1317     for (unsigned int i = 0; i < count; i++)
  1277       (this+ruleSet[i]).collect_glyphs (c, lookup_context);
  1318       (this+ruleSet[i]).collect_glyphs (c, lookup_context);
  1282     TRACE_WOULD_APPLY (this);
  1323     TRACE_WOULD_APPLY (this);
  1283 
  1324 
  1284     const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
  1325     const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
  1285     struct ContextApplyLookupContext lookup_context = {
  1326     struct ContextApplyLookupContext lookup_context = {
  1286       {match_glyph},
  1327       {match_glyph},
  1287       NULL
  1328       nullptr
  1288     };
  1329     };
  1289     return_trace (rule_set.would_apply (c, lookup_context));
  1330     return_trace (rule_set.would_apply (c, lookup_context));
  1290   }
  1331   }
  1291 
  1332 
  1292   inline const Coverage &get_coverage (void) const
  1333   inline const Coverage &get_coverage (void) const
  1302       return_trace (false);
  1343       return_trace (false);
  1303 
  1344 
  1304     const RuleSet &rule_set = this+ruleSet[index];
  1345     const RuleSet &rule_set = this+ruleSet[index];
  1305     struct ContextApplyLookupContext lookup_context = {
  1346     struct ContextApplyLookupContext lookup_context = {
  1306       {match_glyph},
  1347       {match_glyph},
  1307       NULL
  1348       nullptr
  1308     };
  1349     };
  1309     return_trace (rule_set.apply (c, lookup_context));
  1350     return_trace (rule_set.apply (c, lookup_context));
  1310   }
  1351   }
  1311 
  1352 
  1312   inline bool sanitize (hb_sanitize_context_t *c) const
  1353   inline bool sanitize (hb_sanitize_context_t *c) const
  1637                                                const USHORT lookahead[],
  1678                                                const USHORT lookahead[],
  1638                                                unsigned int lookupCount,
  1679                                                unsigned int lookupCount,
  1639                                                const LookupRecord lookupRecord[],
  1680                                                const LookupRecord lookupRecord[],
  1640                                                ChainContextApplyLookupContext &lookup_context)
  1681                                                ChainContextApplyLookupContext &lookup_context)
  1641 {
  1682 {
  1642   unsigned int match_length = 0;
  1683   unsigned int start_index = 0, match_length = 0, end_index = 0;
  1643   unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
  1684   unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
  1644   return match_input (c,
  1685   return match_input (c,
  1645                       inputCount, input,
  1686                       inputCount, input,
  1646                       lookup_context.funcs.match, lookup_context.match_data[1],
  1687                       lookup_context.funcs.match, lookup_context.match_data[1],
  1647                       &match_length, match_positions)
  1688                       &match_length, match_positions)
  1648       && match_backtrack (c,
  1689       && match_backtrack (c,
  1649                           backtrackCount, backtrack,
  1690                           backtrackCount, backtrack,
  1650                           lookup_context.funcs.match, lookup_context.match_data[0])
  1691                           lookup_context.funcs.match, lookup_context.match_data[0],
       
  1692                           &start_index)
  1651       && match_lookahead (c,
  1693       && match_lookahead (c,
  1652                           lookaheadCount, lookahead,
  1694                           lookaheadCount, lookahead,
  1653                           lookup_context.funcs.match, lookup_context.match_data[2],
  1695                           lookup_context.funcs.match, lookup_context.match_data[2],
  1654                           match_length)
  1696                           match_length, &end_index)
  1655       && apply_lookup (c,
  1697       && (c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index),
       
  1698           apply_lookup (c,
  1656                        inputCount, match_positions,
  1699                        inputCount, match_positions,
  1657                        lookupCount, lookupRecord,
  1700                        lookupCount, lookupRecord,
  1658                        match_length);
  1701                        match_length));
  1659 }
  1702 }
  1660 
  1703 
  1661 struct ChainRule
  1704 struct ChainRule
  1662 {
  1705 {
  1663   inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
  1706   inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
  1805     TRACE_CLOSURE (this);
  1848     TRACE_CLOSURE (this);
  1806     const Coverage &cov = (this+coverage);
  1849     const Coverage &cov = (this+coverage);
  1807 
  1850 
  1808     struct ChainContextClosureLookupContext lookup_context = {
  1851     struct ChainContextClosureLookupContext lookup_context = {
  1809       {intersects_glyph},
  1852       {intersects_glyph},
  1810       {NULL, NULL, NULL}
  1853       {nullptr, nullptr, nullptr}
  1811     };
  1854     };
  1812 
  1855 
  1813     unsigned int count = ruleSet.len;
  1856     unsigned int count = ruleSet.len;
  1814     for (unsigned int i = 0; i < count; i++)
  1857     for (unsigned int i = 0; i < count; i++)
  1815       if (cov.intersects_coverage (c->glyphs, i)) {
  1858       if (cov.intersects_coverage (c->glyphs, i)) {
  1823     TRACE_COLLECT_GLYPHS (this);
  1866     TRACE_COLLECT_GLYPHS (this);
  1824     (this+coverage).add_coverage (c->input);
  1867     (this+coverage).add_coverage (c->input);
  1825 
  1868 
  1826     struct ChainContextCollectGlyphsLookupContext lookup_context = {
  1869     struct ChainContextCollectGlyphsLookupContext lookup_context = {
  1827       {collect_glyph},
  1870       {collect_glyph},
  1828       {NULL, NULL, NULL}
  1871       {nullptr, nullptr, nullptr}
  1829     };
  1872     };
  1830 
  1873 
  1831     unsigned int count = ruleSet.len;
  1874     unsigned int count = ruleSet.len;
  1832     for (unsigned int i = 0; i < count; i++)
  1875     for (unsigned int i = 0; i < count; i++)
  1833       (this+ruleSet[i]).collect_glyphs (c, lookup_context);
  1876       (this+ruleSet[i]).collect_glyphs (c, lookup_context);
  1838     TRACE_WOULD_APPLY (this);
  1881     TRACE_WOULD_APPLY (this);
  1839 
  1882 
  1840     const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
  1883     const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
  1841     struct ChainContextApplyLookupContext lookup_context = {
  1884     struct ChainContextApplyLookupContext lookup_context = {
  1842       {match_glyph},
  1885       {match_glyph},
  1843       {NULL, NULL, NULL}
  1886       {nullptr, nullptr, nullptr}
  1844     };
  1887     };
  1845     return_trace (rule_set.would_apply (c, lookup_context));
  1888     return_trace (rule_set.would_apply (c, lookup_context));
  1846   }
  1889   }
  1847 
  1890 
  1848   inline const Coverage &get_coverage (void) const
  1891   inline const Coverage &get_coverage (void) const
  1857     if (likely (index == NOT_COVERED)) return_trace (false);
  1900     if (likely (index == NOT_COVERED)) return_trace (false);
  1858 
  1901 
  1859     const ChainRuleSet &rule_set = this+ruleSet[index];
  1902     const ChainRuleSet &rule_set = this+ruleSet[index];
  1860     struct ChainContextApplyLookupContext lookup_context = {
  1903     struct ChainContextApplyLookupContext lookup_context = {
  1861       {match_glyph},
  1904       {match_glyph},
  1862       {NULL, NULL, NULL}
  1905       {nullptr, nullptr, nullptr}
  1863     };
  1906     };
  1864     return_trace (rule_set.apply (c, lookup_context));
  1907     return_trace (rule_set.apply (c, lookup_context));
  1865   }
  1908   }
  1866 
  1909 
  1867   inline bool sanitize (hb_sanitize_context_t *c) const
  1910   inline bool sanitize (hb_sanitize_context_t *c) const
  2311                 scriptList;     /* ScriptList table */
  2354                 scriptList;     /* ScriptList table */
  2312   OffsetTo<FeatureList>
  2355   OffsetTo<FeatureList>
  2313                 featureList;    /* FeatureList table */
  2356                 featureList;    /* FeatureList table */
  2314   OffsetTo<LookupList>
  2357   OffsetTo<LookupList>
  2315                 lookupList;     /* LookupList table */
  2358                 lookupList;     /* LookupList table */
  2316   OffsetTo<FeatureVariations, ULONG>
  2359   LOffsetTo<FeatureVariations>
  2317                 featureVars;    /* Offset to Feature Variations
  2360                 featureVars;    /* Offset to Feature Variations
  2318                                    table--from beginning of table
  2361                                    table--from beginning of table
  2319                                  * (may be NULL).  Introduced
  2362                                  * (may be NULL).  Introduced
  2320                                  * in version 0x00010001. */
  2363                                  * in version 0x00010001. */
  2321   public:
  2364   public: