LCOV - code coverage report
Current view: top level - gfx/harfbuzz/src - hb-ot-layout-gsubgpos-private.hh (source / functions) Hit Total Coverage
Test: output.info Lines: 298 887 33.6 %
Date: 2017-07-14 16:53:18 Functions: 91 280 32.5 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright © 2007,2008,2009,2010  Red Hat, Inc.
       3             :  * Copyright © 2010,2012  Google, Inc.
       4             :  *
       5             :  *  This is part of HarfBuzz, a text shaping library.
       6             :  *
       7             :  * Permission is hereby granted, without written agreement and without
       8             :  * license or royalty fees, to use, copy, modify, and distribute this
       9             :  * software and its documentation for any purpose, provided that the
      10             :  * above copyright notice and the following two paragraphs appear in
      11             :  * all copies of this software.
      12             :  *
      13             :  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
      14             :  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
      15             :  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
      16             :  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
      17             :  * DAMAGE.
      18             :  *
      19             :  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
      20             :  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
      21             :  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
      22             :  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
      23             :  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
      24             :  *
      25             :  * Red Hat Author(s): Behdad Esfahbod
      26             :  * Google Author(s): Behdad Esfahbod
      27             :  */
      28             : 
      29             : #ifndef HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH
      30             : #define HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH
      31             : 
      32             : #include "hb-buffer-private.hh"
      33             : #include "hb-ot-layout-gdef-table.hh"
      34             : #include "hb-set-private.hh"
      35             : 
      36             : 
      37             : namespace OT {
      38             : 
      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             : 
      49             : struct hb_closure_context_t :
      50             :        hb_dispatch_context_t<hb_closure_context_t, hb_void_t, HB_DEBUG_CLOSURE>
      51             : {
      52           0 :   inline const char *get_name (void) { return "CLOSURE"; }
      53             :   typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
      54             :   template <typename T>
      55           0 :   inline return_t dispatch (const T &obj) { obj.closure (this); return HB_VOID; }
      56           0 :   static return_t default_return_value (void) { return HB_VOID; }
      57           0 :   bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
      58           0 :   return_t recurse (unsigned int lookup_index)
      59             :   {
      60           0 :     if (unlikely (nesting_level_left == 0 || !recurse_func))
      61           0 :       return default_return_value ();
      62             : 
      63           0 :     nesting_level_left--;
      64           0 :     recurse_func (this, lookup_index);
      65           0 :     nesting_level_left++;
      66           0 :     return HB_VOID;
      67             :   }
      68             : 
      69             :   hb_face_t *face;
      70             :   hb_set_t *glyphs;
      71             :   recurse_func_t recurse_func;
      72             :   unsigned int nesting_level_left;
      73             :   unsigned int debug_depth;
      74             : 
      75           0 :   hb_closure_context_t (hb_face_t *face_,
      76             :                         hb_set_t *glyphs_,
      77           0 :                         unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
      78             :                           face (face_),
      79             :                           glyphs (glyphs_),
      80             :                           recurse_func (NULL),
      81             :                           nesting_level_left (nesting_level_left_),
      82           0 :                           debug_depth (0) {}
      83             : 
      84           0 :   void set_recurse_func (recurse_func_t func) { recurse_func = func; }
      85             : };
      86             : 
      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             : 
      98             : struct hb_would_apply_context_t :
      99             :        hb_dispatch_context_t<hb_would_apply_context_t, bool, HB_DEBUG_WOULD_APPLY>
     100             : {
     101           0 :   inline const char *get_name (void) { return "WOULD_APPLY"; }
     102             :   template <typename T>
     103           0 :   inline return_t dispatch (const T &obj) { return obj.would_apply (this); }
     104           0 :   static return_t default_return_value (void) { return false; }
     105           0 :   bool stop_sublookup_iteration (return_t r) const { return r; }
     106             : 
     107             :   hb_face_t *face;
     108             :   const hb_codepoint_t *glyphs;
     109             :   unsigned int len;
     110             :   bool zero_context;
     111             :   unsigned int debug_depth;
     112             : 
     113           0 :   hb_would_apply_context_t (hb_face_t *face_,
     114             :                             const hb_codepoint_t *glyphs_,
     115             :                             unsigned int len_,
     116           0 :                             bool zero_context_) :
     117             :                               face (face_),
     118             :                               glyphs (glyphs_),
     119             :                               len (len_),
     120             :                               zero_context (zero_context_),
     121           0 :                               debug_depth (0) {}
     122             : };
     123             : 
     124             : 
     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 :
     136             :        hb_dispatch_context_t<hb_collect_glyphs_context_t, hb_void_t, HB_DEBUG_COLLECT_GLYPHS>
     137             : {
     138        3731 :   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);
     140             :   template <typename T>
     141          96 :   inline return_t dispatch (const T &obj) { obj.collect_glyphs (this); return HB_VOID; }
     142          96 :   static return_t default_return_value (void) { return HB_VOID; }
     143          96 :   bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
     144          11 :   return_t recurse (unsigned int lookup_index)
     145             :   {
     146          11 :     if (unlikely (nesting_level_left == 0 || !recurse_func))
     147           0 :       return default_return_value ();
     148             : 
     149             :     /* Note that GPOS sets recurse_func to NULL already, so it doesn't get
     150             :      * 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.
     152             :      *
     153             :      * 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
     155             :      * not how most fonts are built.  It's possible to relax that and recurse
     156             :      * with all sets here if it proves to be an issue.
     157             :      */
     158             : 
     159          11 :     if (output == hb_set_get_empty ())
     160          11 :       return HB_VOID;
     161             : 
     162             :     /* Return if new lookup was recursed to before. */
     163           0 :     if (recursed_lookups.has (lookup_index))
     164           0 :       return HB_VOID;
     165             : 
     166           0 :     hb_set_t *old_before = before;
     167           0 :     hb_set_t *old_input  = input;
     168           0 :     hb_set_t *old_after  = after;
     169           0 :     before = input = after = hb_set_get_empty ();
     170             : 
     171           0 :     nesting_level_left--;
     172           0 :     recurse_func (this, lookup_index);
     173           0 :     nesting_level_left++;
     174             : 
     175           0 :     before = old_before;
     176           0 :     input  = old_input;
     177           0 :     after  = old_after;
     178             : 
     179           0 :     recursed_lookups.add (lookup_index);
     180             : 
     181           0 :     return HB_VOID;
     182             :   }
     183             : 
     184             :   hb_face_t *face;
     185             :   hb_set_t *before;
     186             :   hb_set_t *input;
     187             :   hb_set_t *after;
     188             :   hb_set_t *output;
     189             :   recurse_func_t recurse_func;
     190             :   hb_set_t recursed_lookups;
     191             :   unsigned int nesting_level_left;
     192             :   unsigned int debug_depth;
     193             : 
     194          96 :   hb_collect_glyphs_context_t (hb_face_t *face_,
     195             :                                hb_set_t  *glyphs_before, /* OUT. May be NULL */
     196             :                                hb_set_t  *glyphs_input,  /* OUT. May be NULL */
     197             :                                hb_set_t  *glyphs_after,  /* OUT. May be NULL */
     198             :                                hb_set_t  *glyphs_output, /* OUT. May be NULL */
     199          96 :                                unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
     200             :                               face (face_),
     201          96 :                               before (glyphs_before ? glyphs_before : hb_set_get_empty ()),
     202          96 :                               input  (glyphs_input  ? glyphs_input  : hb_set_get_empty ()),
     203          96 :                               after  (glyphs_after  ? glyphs_after  : hb_set_get_empty ()),
     204          96 :                               output (glyphs_output ? glyphs_output : hb_set_get_empty ()),
     205             :                               recurse_func (NULL),
     206             :                               recursed_lookups (),
     207             :                               nesting_level_left (nesting_level_left_),
     208         480 :                               debug_depth (0)
     209             :   {
     210          96 :     recursed_lookups.init ();
     211          96 :   }
     212          96 :   ~hb_collect_glyphs_context_t (void)
     213          96 :   {
     214          96 :     recursed_lookups.fini ();
     215          96 :   }
     216             : 
     217          84 :   void set_recurse_func (recurse_func_t func) { recurse_func = func; }
     218             : };
     219             : 
     220             : 
     221             : 
     222             : #ifndef HB_DEBUG_GET_COVERAGE
     223             : #define HB_DEBUG_GET_COVERAGE (HB_DEBUG+0)
     224             : #endif
     225             : 
     226             : /* XXX Can we remove this? */
     227             : 
     228             : template <typename set_t>
     229             : struct hb_add_coverage_context_t :
     230             :        hb_dispatch_context_t<hb_add_coverage_context_t<set_t>, const Coverage &, HB_DEBUG_GET_COVERAGE>
     231             : {
     232         306 :   inline const char *get_name (void) { return "GET_COVERAGE"; }
     233             :   typedef const Coverage &return_t;
     234             :   template <typename T>
     235         102 :   inline return_t dispatch (const T &obj) { return obj.get_coverage (); }
     236         102 :   static return_t default_return_value (void) { return Null(Coverage); }
     237         102 :   bool stop_sublookup_iteration (return_t r) const
     238             :   {
     239         102 :     r.add_coverage (set);
     240         102 :     return false;
     241             :   }
     242             : 
     243         102 :   hb_add_coverage_context_t (set_t *set_) :
     244             :                             set (set_),
     245         102 :                             debug_depth (0) {}
     246             : 
     247             :   set_t *set;
     248             :   unsigned int debug_depth;
     249             : };
     250             : 
     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             : 
     263             : struct hb_apply_context_t :
     264             :        hb_dispatch_context_t<hb_apply_context_t, bool, HB_DEBUG_APPLY>
     265             : {
     266             :   struct matcher_t
     267             :   {
     268         136 :     inline matcher_t (void) :
     269             :              lookup_props (0),
     270             :              ignore_zwnj (false),
     271             :              ignore_zwj (false),
     272             :              mask (-1),
     273             : #define arg1(arg) (arg) /* Remove the macro to see why it's needed! */
     274             :              syllable arg1(0),
     275             : #undef arg1
     276             :              match_func (NULL),
     277         136 :              match_data (NULL) {};
     278             : 
     279             :     typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data);
     280             : 
     281         988 :     inline void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; }
     282         988 :     inline void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
     283         988 :     inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
     284         988 :     inline void set_mask (hb_mask_t mask_) { mask = mask_; }
     285         229 :     inline void set_syllable (uint8_t syllable_)  { syllable = syllable_; }
     286        1001 :     inline void set_match_func (match_func_t match_func_,
     287             :                                 const void *match_data_)
     288        1001 :     { match_func = match_func_; match_data = match_data_; }
     289             : 
     290             :     enum may_match_t {
     291             :       MATCH_NO,
     292             :       MATCH_YES,
     293             :       MATCH_MAYBE
     294             :     };
     295             : 
     296         204 :     inline may_match_t may_match (const hb_glyph_info_t &info,
     297             :                                   const USHORT          *glyph_data) const
     298             :     {
     299         408 :       if (!(info.mask & mask) ||
     300         204 :           (syllable && syllable != info.syllable ()))
     301           0 :         return MATCH_NO;
     302             : 
     303         204 :       if (match_func)
     304          11 :         return match_func (info.codepoint, *glyph_data, match_data) ? MATCH_YES : MATCH_NO;
     305             : 
     306         193 :       return MATCH_MAYBE;
     307             :     }
     308             : 
     309             :     enum may_skip_t {
     310             :       SKIP_NO,
     311             :       SKIP_YES,
     312             :       SKIP_MAYBE
     313             :     };
     314             : 
     315             :     inline may_skip_t
     316         204 :     may_skip (const hb_apply_context_t *c,
     317             :               const hb_glyph_info_t    &info) const
     318             :     {
     319         204 :       if (!c->check_glyph_property (&info, lookup_props))
     320           0 :         return SKIP_YES;
     321             : 
     322         204 :       if (unlikely (_hb_glyph_info_is_default_ignorable_and_not_fvs (&info) &&
     323             :                     (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) &&
     324             :                     (ignore_zwj || !_hb_glyph_info_is_zwj (&info))))
     325           0 :         return SKIP_MAYBE;
     326             : 
     327         204 :       return SKIP_NO;
     328             :     }
     329             : 
     330             :     protected:
     331             :     unsigned int lookup_props;
     332             :     bool ignore_zwnj;
     333             :     bool ignore_zwj;
     334             :     hb_mask_t mask;
     335             :     uint8_t syllable;
     336             :     match_func_t match_func;
     337             :     const void *match_data;
     338             :   };
     339             : 
     340         136 :   struct skipping_iterator_t
     341             :   {
     342         988 :     inline void init (hb_apply_context_t *c_, bool context_match = false)
     343             :     {
     344         988 :       c = c_;
     345         988 :       match_glyph_data = NULL;
     346         988 :       matcher.set_match_func (NULL, NULL);
     347         988 :       matcher.set_lookup_props (c->lookup_props);
     348             :       /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
     349         988 :       matcher.set_ignore_zwnj (context_match || c->table_index == 1);
     350             :       /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */
     351         988 :       matcher.set_ignore_zwj (context_match || c->table_index == 1 || c->auto_zwj);
     352         988 :       matcher.set_mask (context_match ? -1 : c->lookup_mask);
     353         988 :     }
     354           0 :     inline void set_lookup_props (unsigned int lookup_props)
     355             :     {
     356           0 :       matcher.set_lookup_props (lookup_props);
     357           0 :     }
     358          13 :     inline void set_match_func (matcher_t::match_func_t match_func_,
     359             :                                 const void *match_data_,
     360             :                                 const USHORT glyph_data[])
     361             :     {
     362          13 :       matcher.set_match_func (match_func_, match_data_);
     363          13 :       match_glyph_data = glyph_data;
     364          13 :     }
     365             : 
     366         229 :     inline void reset (unsigned int start_index_,
     367             :                        unsigned int num_items_)
     368             :     {
     369         229 :       idx = start_index_;
     370         229 :       num_items = num_items_;
     371         229 :       end = c->buffer->len;
     372         229 :       matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
     373         229 :     }
     374             : 
     375           0 :     inline void reject (void) { num_items++; match_glyph_data--; }
     376             : 
     377         227 :     inline bool next (void)
     378             :     {
     379         227 :       assert (num_items > 0);
     380         227 :       while (idx + num_items < end)
     381             :       {
     382         204 :         idx++;
     383         204 :         const hb_glyph_info_t &info = c->buffer->info[idx];
     384             : 
     385         204 :         matcher_t::may_skip_t skip = matcher.may_skip (c, info);
     386         204 :         if (unlikely (skip == matcher_t::SKIP_YES))
     387           0 :           continue;
     388             : 
     389         204 :         matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
     390         204 :         if (match == matcher_t::MATCH_YES ||
     391         193 :             (match == matcher_t::MATCH_MAYBE &&
     392             :              skip == matcher_t::SKIP_NO))
     393             :         {
     394         193 :           num_items--;
     395         193 :           match_glyph_data++;
     396         193 :           return true;
     397             :         }
     398             : 
     399          11 :         if (skip == matcher_t::SKIP_NO)
     400          11 :           return false;
     401             :       }
     402          23 :       return false;
     403             :     }
     404           0 :     inline bool prev (void)
     405             :     {
     406           0 :       assert (num_items > 0);
     407           0 :       while (idx >= num_items)
     408             :       {
     409           0 :         idx--;
     410           0 :         const hb_glyph_info_t &info = c->buffer->out_info[idx];
     411             : 
     412           0 :         matcher_t::may_skip_t skip = matcher.may_skip (c, info);
     413           0 :         if (unlikely (skip == matcher_t::SKIP_YES))
     414           0 :           continue;
     415             : 
     416           0 :         matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
     417           0 :         if (match == matcher_t::MATCH_YES ||
     418           0 :             (match == matcher_t::MATCH_MAYBE &&
     419             :              skip == matcher_t::SKIP_NO))
     420             :         {
     421           0 :           num_items--;
     422           0 :           match_glyph_data++;
     423           0 :           return true;
     424             :         }
     425             : 
     426           0 :         if (skip == matcher_t::SKIP_NO)
     427           0 :           return false;
     428             :       }
     429           0 :       return false;
     430             :     }
     431             : 
     432             :     unsigned int idx;
     433             :     protected:
     434             :     hb_apply_context_t *c;
     435             :     matcher_t matcher;
     436             :     const USHORT *match_glyph_data;
     437             : 
     438             :     unsigned int num_items;
     439             :     unsigned int end;
     440             :   };
     441             : 
     442             : 
     443        1006 :   inline const char *get_name (void) { return "APPLY"; }
     444             :   typedef return_t (*recurse_func_t) (hb_apply_context_t *c, unsigned int lookup_index);
     445             :   template <typename T>
     446           0 :   inline return_t dispatch (const T &obj) { return obj.apply (this); }
     447           0 :   static return_t default_return_value (void) { return false; }
     448           0 :   bool stop_sublookup_iteration (return_t r) const { return r; }
     449           0 :   return_t recurse (unsigned int lookup_index)
     450             :   {
     451           0 :     if (unlikely (nesting_level_left == 0 || !recurse_func))
     452           0 :       return default_return_value ();
     453             : 
     454           0 :     nesting_level_left--;
     455           0 :     bool ret = recurse_func (this, lookup_index);
     456           0 :     nesting_level_left++;
     457           0 :     return ret;
     458             :   }
     459             : 
     460             :   unsigned int table_index; /* GSUB/GPOS */
     461             :   hb_font_t *font;
     462             :   hb_face_t *face;
     463             :   hb_buffer_t *buffer;
     464             :   hb_direction_t direction;
     465             :   hb_mask_t lookup_mask;
     466             :   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;
     472             :   const VariationStore &var_store;
     473             :   skipping_iterator_t iter_input, iter_context;
     474             :   unsigned int lookup_index;
     475             :   unsigned int debug_depth;
     476             : 
     477             : 
     478          68 :   hb_apply_context_t (unsigned int table_index_,
     479             :                       hb_font_t *font_,
     480          68 :                       hb_buffer_t *buffer_) :
     481             :                         table_index (table_index_),
     482          68 :                         font (font_), face (font->face), buffer (buffer_),
     483          68 :                         direction (buffer_->props.direction),
     484             :                         lookup_mask (1),
     485             :                         auto_zwj (true),
     486             :                         recurse_func (NULL),
     487             :                         nesting_level_left (HB_MAX_NESTING_LEVEL),
     488             :                         lookup_props (0),
     489          68 :                         gdef (*hb_ot_layout_from_face (face)->gdef),
     490          68 :                         has_glyph_classes (gdef.has_glyph_classes ()),
     491          68 :                         var_store (gdef.get_var_store ()),
     492             :                         iter_input (),
     493             :                         iter_context (),
     494             :                         lookup_index ((unsigned int) -1),
     495         408 :                         debug_depth (0) {}
     496             : 
     497         494 :   inline void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; }
     498         494 :   inline void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; }
     499          68 :   inline void set_recurse_func (recurse_func_t func) { recurse_func = func; }
     500         494 :   inline void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; }
     501         494 :   inline void set_lookup_props (unsigned int lookup_props_)
     502             :   {
     503         494 :     lookup_props = lookup_props_;
     504         494 :     iter_input.init (this, false);
     505         494 :     iter_context.init (this, true);
     506         494 :   }
     507             : 
     508             :   inline bool
     509           0 :   match_properties_mark (hb_codepoint_t  glyph,
     510             :                          unsigned int    glyph_props,
     511             :                          unsigned int    match_props) const
     512             :   {
     513             :     /* If using mark filtering sets, the high short of
     514             :      * match_props has the set index.
     515             :      */
     516           0 :     if (match_props & LookupFlag::UseMarkFilteringSet)
     517           0 :       return gdef.mark_set_covers (match_props >> 16, glyph);
     518             : 
     519             :     /* The second byte of match_props has the meaning
     520             :      * "ignore marks of attachment type different than
     521             :      * the attachment type specified."
     522             :      */
     523           0 :     if (match_props & LookupFlag::MarkAttachmentType)
     524           0 :       return (match_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);
     525             : 
     526           0 :     return true;
     527             :   }
     528             : 
     529             :   inline bool
     530        1175 :   check_glyph_property (const hb_glyph_info_t *info,
     531             :                         unsigned int  match_props) const
     532             :   {
     533        1175 :     hb_codepoint_t glyph = info->codepoint;
     534        1175 :     unsigned int glyph_props = _hb_glyph_info_get_glyph_props (info);
     535             : 
     536             :     /* Not covered, if, for example, glyph class is ligature and
     537             :      * match_props includes LookupFlags::IgnoreLigatures
     538             :      */
     539        1175 :     if (glyph_props & match_props & LookupFlag::IgnoreFlags)
     540           0 :       return false;
     541             : 
     542        1175 :     if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK))
     543           0 :       return match_properties_mark (glyph, glyph_props, match_props);
     544             : 
     545        1175 :     return true;
     546             :   }
     547             : 
     548           0 :   inline void _set_glyph_props (hb_codepoint_t glyph_index,
     549             :                           unsigned int class_guess = 0,
     550             :                           bool ligature = false,
     551             :                           bool component = false) const
     552             :   {
     553           0 :     unsigned int add_in = _hb_glyph_info_get_glyph_props (&buffer->cur()) &
     554           0 :                           HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE;
     555           0 :     add_in |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED;
     556           0 :     if (ligature)
     557             :     {
     558           0 :       add_in |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED;
     559             :       /* In the only place that the MULTIPLIED bit is used, Uniscribe
     560             :        * seems to only care about the "last" transformation between
     561             :        * Ligature and Multiple substitions.  Ie. if you ligate, expand,
     562             :        * and ligate again, it forgives the multiplication and acts as
     563             :        * if only ligation happened.  As such, clear MULTIPLIED bit.
     564             :        */
     565           0 :       add_in &= ~HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
     566             :     }
     567           0 :     if (component)
     568           0 :       add_in |= HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
     569           0 :     if (likely (has_glyph_classes))
     570           0 :       _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | gdef.get_glyph_props (glyph_index));
     571           0 :     else if (class_guess)
     572           0 :       _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | class_guess);
     573           0 :   }
     574             : 
     575           0 :   inline void replace_glyph (hb_codepoint_t glyph_index) const
     576             :   {
     577           0 :     _set_glyph_props (glyph_index);
     578           0 :     buffer->replace_glyph (glyph_index);
     579           0 :   }
     580           0 :   inline void replace_glyph_inplace (hb_codepoint_t glyph_index) const
     581             :   {
     582           0 :     _set_glyph_props (glyph_index);
     583           0 :     buffer->cur().codepoint = glyph_index;
     584           0 :   }
     585           0 :   inline void replace_glyph_with_ligature (hb_codepoint_t glyph_index,
     586             :                                            unsigned int class_guess) const
     587             :   {
     588           0 :     _set_glyph_props (glyph_index, class_guess, true);
     589           0 :     buffer->replace_glyph (glyph_index);
     590           0 :   }
     591           0 :   inline void output_glyph_for_component (hb_codepoint_t glyph_index,
     592             :                                           unsigned int class_guess) const
     593             :   {
     594           0 :     _set_glyph_props (glyph_index, class_guess, false, true);
     595           0 :     buffer->output_glyph (glyph_index);
     596           0 :   }
     597             : };
     598             : 
     599             : 
     600             : 
     601             : typedef bool (*intersects_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data);
     602             : typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data);
     603             : typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data);
     604             : 
     605             : struct ContextClosureFuncs
     606             : {
     607             :   intersects_func_t intersects;
     608             : };
     609             : struct ContextCollectGlyphsFuncs
     610             : {
     611             :   collect_glyphs_func_t collect;
     612             : };
     613             : struct ContextApplyFuncs
     614             : {
     615             :   match_func_t match;
     616             : };
     617             : 
     618             : 
     619           0 : static inline bool intersects_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED)
     620             : {
     621           0 :   return glyphs->has (value);
     622             : }
     623           0 : static inline bool intersects_class (hb_set_t *glyphs, const USHORT &value, const void *data)
     624             : {
     625           0 :   const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
     626           0 :   return class_def.intersects_class (glyphs, value);
     627             : }
     628           0 : static inline bool intersects_coverage (hb_set_t *glyphs, const USHORT &value, const void *data)
     629             : {
     630           0 :   const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
     631           0 :   return (data+coverage).intersects (glyphs);
     632             : }
     633             : 
     634           0 : static inline bool intersects_array (hb_closure_context_t *c,
     635             :                                      unsigned int count,
     636             :                                      const USHORT values[],
     637             :                                      intersects_func_t intersects_func,
     638             :                                      const void *intersects_data)
     639             : {
     640           0 :   for (unsigned int i = 0; i < count; i++)
     641           0 :     if (likely (!intersects_func (c->glyphs, values[i], intersects_data)))
     642           0 :       return false;
     643           0 :   return true;
     644             : }
     645             : 
     646             : 
     647           0 : static inline void collect_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED)
     648             : {
     649           0 :   glyphs->add (value);
     650           0 : }
     651           8 : static inline void collect_class (hb_set_t *glyphs, const USHORT &value, const void *data)
     652             : {
     653           8 :   const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
     654           8 :   class_def.add_class (glyphs, value);
     655           8 : }
     656           3 : static inline void collect_coverage (hb_set_t *glyphs, const USHORT &value, const void *data)
     657             : {
     658           3 :   const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
     659           3 :   (data+coverage).add_coverage (glyphs);
     660           3 : }
     661          33 : static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
     662             :                                   hb_set_t *glyphs,
     663             :                                   unsigned int count,
     664             :                                   const USHORT values[],
     665             :                                   collect_glyphs_func_t collect_func,
     666             :                                   const void *collect_data)
     667             : {
     668          44 :   for (unsigned int i = 0; i < count; i++)
     669          11 :     collect_func (glyphs, values[i], collect_data);
     670          33 : }
     671             : 
     672             : 
     673          10 : static inline bool match_glyph (hb_codepoint_t glyph_id, const USHORT &value, const void *data HB_UNUSED)
     674             : {
     675          10 :   return glyph_id == value;
     676             : }
     677           1 : static inline bool match_class (hb_codepoint_t glyph_id, const USHORT &value, const void *data)
     678             : {
     679           1 :   const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
     680           1 :   return class_def.get_class (glyph_id) == value;
     681             : }
     682           0 : static inline bool match_coverage (hb_codepoint_t glyph_id, const USHORT &value, const void *data)
     683             : {
     684           0 :   const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
     685           0 :   return (data+coverage).get_coverage (glyph_id) != NOT_COVERED;
     686             : }
     687             : 
     688           0 : static inline bool would_match_input (hb_would_apply_context_t *c,
     689             :                                       unsigned int count, /* Including the first glyph (not matched) */
     690             :                                       const USHORT input[], /* Array of input values--start with second glyph */
     691             :                                       match_func_t match_func,
     692             :                                       const void *match_data)
     693             : {
     694           0 :   if (count != c->len)
     695           0 :     return false;
     696             : 
     697           0 :   for (unsigned int i = 1; i < count; i++)
     698           0 :     if (likely (!match_func (c->glyphs[i], input[i - 1], match_data)))
     699           0 :       return false;
     700             : 
     701           0 :   return true;
     702             : }
     703          11 : static inline bool match_input (hb_apply_context_t *c,
     704             :                                 unsigned int count, /* Including the first glyph (not matched) */
     705             :                                 const USHORT input[], /* Array of input values--start with second glyph */
     706             :                                 match_func_t match_func,
     707             :                                 const void *match_data,
     708             :                                 unsigned int *end_offset,
     709             :                                 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],
     710             :                                 bool *p_is_mark_ligature = NULL,
     711             :                                 unsigned int *p_total_component_count = NULL)
     712             : {
     713          11 :   TRACE_APPLY (NULL);
     714             : 
     715          11 :   if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return_trace (false);
     716             : 
     717          11 :   hb_buffer_t *buffer = c->buffer;
     718             : 
     719          11 :   hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
     720          11 :   skippy_iter.reset (buffer->idx, count - 1);
     721          11 :   skippy_iter.set_match_func (match_func, match_data, input);
     722             : 
     723             :   /*
     724             :    * This is perhaps the trickiest part of OpenType...  Remarks:
     725             :    *
     726             :    * - If all components of the ligature were marks, we call this a mark ligature.
     727             :    *
     728             :    * - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize
     729             :    *   it as a ligature glyph.
     730             :    *
     731             :    * - Ligatures cannot be formed across glyphs attached to different components
     732             :    *   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.
     734             :    *   However, it would be wrong to ligate that SHADDA,FATHA sequence.o
     735             :    *   There is an exception to this: If a ligature tries ligating with marks that
     736             :    *   belong to it itself, go ahead, assuming that the font designer knows what
     737             :    *   they are doing (otherwise it can break Indic stuff when a matra wants to
     738             :    *   ligate with a conjunct...)
     739             :    */
     740             : 
     741          11 :   bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->cur());
     742             : 
     743          11 :   unsigned int total_component_count = 0;
     744          11 :   total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur());
     745             : 
     746          11 :   unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
     747          11 :   unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
     748             : 
     749          11 :   match_positions[0] = buffer->idx;
     750          11 :   for (unsigned int i = 1; i < count; i++)
     751             :   {
     752          10 :     if (!skippy_iter.next ()) return_trace (false);
     753             : 
     754           0 :     match_positions[i] = skippy_iter.idx;
     755             : 
     756           0 :     unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]);
     757           0 :     unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]);
     758             : 
     759           0 :     if (first_lig_id && first_lig_comp) {
     760             :       /* If first component was attached to a previous ligature component,
     761             :        * all subsequent components should be attached to the same ligature
     762             :        * component, otherwise we shouldn't ligate them. */
     763           0 :       if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
     764           0 :         return_trace (false);
     765             :     } else {
     766             :       /* If first component was NOT attached to a previous ligature component,
     767             :        * all subsequent components should also NOT be attached to any ligature
     768             :        * component, unless they are attached to the first component itself! */
     769           0 :       if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id))
     770           0 :         return_trace (false);
     771             :     }
     772             : 
     773           0 :     is_mark_ligature = is_mark_ligature && _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx]);
     774           0 :     total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]);
     775             :   }
     776             : 
     777           1 :   *end_offset = skippy_iter.idx - buffer->idx + 1;
     778             : 
     779           1 :   if (p_is_mark_ligature)
     780           0 :     *p_is_mark_ligature = is_mark_ligature;
     781             : 
     782           1 :   if (p_total_component_count)
     783           0 :     *p_total_component_count = total_component_count;
     784             : 
     785           1 :   return_trace (true);
     786             : }
     787           0 : static inline bool ligate_input (hb_apply_context_t *c,
     788             :                                  unsigned int count, /* Including the first glyph */
     789             :                                  unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
     790             :                                  unsigned int match_length,
     791             :                                  hb_codepoint_t lig_glyph,
     792             :                                  bool is_mark_ligature,
     793             :                                  unsigned int total_component_count)
     794             : {
     795           0 :   TRACE_APPLY (NULL);
     796             : 
     797           0 :   hb_buffer_t *buffer = c->buffer;
     798             : 
     799           0 :   buffer->merge_clusters (buffer->idx, buffer->idx + match_length);
     800             : 
     801             :   /*
     802             :    * - If it *is* a mark ligature, we don't allocate a new ligature id, and leave
     803             :    *   the ligature to keep its old ligature id.  This will allow it to attach to
     804             :    *   a base ligature in GPOS.  Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH,
     805             :    *   and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA wit a
     806             :    *   ligature id and component value of 2.  Then if SHADDA,FATHA form a ligature
     807             :    *   later, we don't want them to lose their ligature id/component, otherwise
     808             :    *   GPOS will fail to correctly position the mark ligature on top of the
     809             :    *   LAM,LAM,HEH ligature.  See:
     810             :    *     https://bugzilla.gnome.org/show_bug.cgi?id=676343
     811             :    *
     812             :    * - If a ligature is formed of components that some of which are also ligatures
     813             :    *   themselves, and those ligature components had marks attached to *their*
     814             :    *   components, we have to attach the marks to the new ligature component
     815             :    *   positions!  Now *that*'s tricky!  And these marks may be following the
     816             :    *   last component of the whole sequence, so we should loop forward looking
     817             :    *   for them and update them.
     818             :    *
     819             :    *   Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a
     820             :    *   'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature
     821             :    *   id and component == 1.  Now, during 'liga', the LAM and the LAM-HEH ligature
     822             :    *   form a LAM-LAM-HEH ligature.  We need to reassign the SHADDA and FATHA to
     823             :    *   the new ligature with a component value of 2.
     824             :    *
     825             :    *   This in fact happened to a font...  See:
     826             :    *   https://bugzilla.gnome.org/show_bug.cgi?id=437633
     827             :    */
     828             : 
     829           0 :   unsigned int klass = is_mark_ligature ? 0 : HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
     830           0 :   unsigned int lig_id = is_mark_ligature ? 0 : _hb_allocate_lig_id (buffer);
     831           0 :   unsigned int last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
     832           0 :   unsigned int last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
     833           0 :   unsigned int components_so_far = last_num_components;
     834             : 
     835           0 :   if (!is_mark_ligature)
     836             :   {
     837           0 :     _hb_glyph_info_set_lig_props_for_ligature (&buffer->cur(), lig_id, total_component_count);
     838           0 :     if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
     839             :     {
     840           0 :       _hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER);
     841             :     }
     842             :   }
     843           0 :   c->replace_glyph_with_ligature (lig_glyph, klass);
     844             : 
     845           0 :   for (unsigned int i = 1; i < count; i++)
     846             :   {
     847           0 :     while (buffer->idx < match_positions[i] && !buffer->in_error)
     848             :     {
     849           0 :       if (!is_mark_ligature) {
     850           0 :         unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
     851           0 :         if (this_comp == 0)
     852           0 :           this_comp = last_num_components;
     853           0 :         unsigned int new_lig_comp = components_so_far - last_num_components +
     854           0 :                                     MIN (this_comp, last_num_components);
     855           0 :           _hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
     856             :       }
     857           0 :       buffer->next_glyph ();
     858             :     }
     859             : 
     860           0 :     last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
     861           0 :     last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
     862           0 :     components_so_far += last_num_components;
     863             : 
     864             :     /* Skip the base glyph */
     865           0 :     buffer->idx++;
     866             :   }
     867             : 
     868           0 :   if (!is_mark_ligature && last_lig_id) {
     869             :     /* Re-adjust components for any marks following. */
     870           0 :     for (unsigned int i = buffer->idx; i < buffer->len; i++) {
     871           0 :       if (last_lig_id == _hb_glyph_info_get_lig_id (&buffer->info[i])) {
     872           0 :         unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->info[i]);
     873           0 :         if (!this_comp)
     874           0 :           break;
     875           0 :         unsigned int new_lig_comp = components_so_far - last_num_components +
     876           0 :                                     MIN (this_comp, last_num_components);
     877           0 :         _hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
     878             :       } else
     879           0 :         break;
     880             :     }
     881             :   }
     882           0 :   return_trace (true);
     883             : }
     884             : 
     885           1 : static inline bool match_backtrack (hb_apply_context_t *c,
     886             :                                     unsigned int count,
     887             :                                     const USHORT backtrack[],
     888             :                                     match_func_t match_func,
     889             :                                     const void *match_data)
     890             : {
     891           1 :   TRACE_APPLY (NULL);
     892             : 
     893           1 :   hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
     894           1 :   skippy_iter.reset (c->buffer->backtrack_len (), count);
     895           1 :   skippy_iter.set_match_func (match_func, match_data, backtrack);
     896             : 
     897           1 :   for (unsigned int i = 0; i < count; i++)
     898           0 :     if (!skippy_iter.prev ())
     899           0 :       return_trace (false);
     900             : 
     901           1 :   return_trace (true);
     902             : }
     903             : 
     904           1 : static inline bool match_lookahead (hb_apply_context_t *c,
     905             :                                     unsigned int count,
     906             :                                     const USHORT lookahead[],
     907             :                                     match_func_t match_func,
     908             :                                     const void *match_data,
     909             :                                     unsigned int offset)
     910             : {
     911           1 :   TRACE_APPLY (NULL);
     912             : 
     913           1 :   hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
     914           1 :   skippy_iter.reset (c->buffer->idx + offset - 1, count);
     915           1 :   skippy_iter.set_match_func (match_func, match_data, lookahead);
     916             : 
     917           1 :   for (unsigned int i = 0; i < count; i++)
     918           1 :     if (!skippy_iter.next ())
     919           1 :       return_trace (false);
     920             : 
     921           0 :   return_trace (true);
     922             : }
     923             : 
     924             : 
     925             : 
     926             : struct LookupRecord
     927             : {
     928             :   inline bool sanitize (hb_sanitize_context_t *c) const
     929             :   {
     930             :     TRACE_SANITIZE (this);
     931             :     return_trace (c->check_struct (this));
     932             :   }
     933             : 
     934             :   USHORT        sequenceIndex;          /* Index into current glyph
     935             :                                          * sequence--first glyph = 0 */
     936             :   USHORT        lookupListIndex;        /* Lookup to apply to that
     937             :                                          * position--zero--based */
     938             :   public:
     939             :   DEFINE_SIZE_STATIC (4);
     940             : };
     941             : 
     942             : 
     943             : template <typename context_t>
     944          11 : static inline void recurse_lookups (context_t *c,
     945             :                                     unsigned int lookupCount,
     946             :                                     const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
     947             : {
     948          22 :   for (unsigned int i = 0; i < lookupCount; i++)
     949          11 :     c->recurse (lookupRecord[i].lookupListIndex);
     950          11 : }
     951             : 
     952           0 : static inline bool apply_lookup (hb_apply_context_t *c,
     953             :                                  unsigned int count, /* Including the first glyph */
     954             :                                  unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
     955             :                                  unsigned int lookupCount,
     956             :                                  const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
     957             :                                  unsigned int match_length)
     958             : {
     959           0 :   TRACE_APPLY (NULL);
     960             : 
     961           0 :   hb_buffer_t *buffer = c->buffer;
     962             :   int end;
     963             : 
     964             :   /* All positions are distance from beginning of *output* buffer.
     965             :    * Adjust. */
     966             :   {
     967           0 :     unsigned int bl = buffer->backtrack_len ();
     968           0 :     end = bl + match_length;
     969             : 
     970           0 :     int delta = bl - buffer->idx;
     971             :     /* Convert positions to new indexing. */
     972           0 :     for (unsigned int j = 0; j < count; j++)
     973           0 :       match_positions[j] += delta;
     974             :   }
     975             : 
     976           0 :   for (unsigned int i = 0; i < lookupCount && !buffer->in_error; i++)
     977             :   {
     978           0 :     unsigned int idx = lookupRecord[i].sequenceIndex;
     979           0 :     if (idx >= count)
     980           0 :       continue;
     981             : 
     982             :     /* Don't recurse to ourself at same position.
     983             :      * Note that this test is too naive, it doesn't catch longer loops. */
     984           0 :     if (idx == 0 && lookupRecord[i].lookupListIndex == c->lookup_index)
     985           0 :       continue;
     986             : 
     987           0 :     buffer->move_to (match_positions[idx]);
     988             : 
     989           0 :     unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
     990           0 :     if (!c->recurse (lookupRecord[i].lookupListIndex))
     991           0 :       continue;
     992             : 
     993           0 :     unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len ();
     994           0 :     int delta = new_len - orig_len;
     995             : 
     996           0 :     if (!delta)
     997           0 :         continue;
     998             : 
     999             :     /* Recursed lookup changed buffer len.  Adjust.
    1000             :      *
    1001             :      * TODO:
    1002             :      *
    1003             :      * Right now, if buffer length increased by n, we assume n new glyphs
    1004             :      * were added right after the current position, and if buffer length
    1005             :      * was decreased by n, we assume n match positions after the current
    1006             :      * one where removed.  The former (buffer length increased) case is
    1007             :      * fine, but the decrease case can be improved in at least two ways,
    1008             :      * both of which are significant:
    1009             :      *
    1010             :      *   - If recursed-to lookup is MultipleSubst and buffer length
    1011             :      *     decreased, then it's current match position that was deleted,
    1012             :      *     NOT the one after it.
    1013             :      *
    1014             :      *   - If buffer length was decreased by n, it does not necessarily
    1015             :      *     mean that n match positions where removed, as there might
    1016             :      *     have been marks and default-ignorables in the sequence.  We
    1017             :      *     should instead drop match positions between current-position
    1018             :      *     and current-position + n instead.
    1019             :      *
    1020             :      * It should be possible to construct tests for both of these cases.
    1021             :      */
    1022             : 
    1023           0 :     end += delta;
    1024           0 :     if (end <= int (match_positions[idx]))
    1025             :     {
    1026             :       /* End might end up being smaller than match_positions[idx] if the recursed
    1027             :        * lookup ended up removing many items, more than we have had matched.
    1028             :        * Just never rewind end back and get out of here.
    1029             :        * https://bugs.chromium.org/p/chromium/issues/detail?id=659496 */
    1030           0 :       end = match_positions[idx];
    1031             :       /* There can't be any further changes. */
    1032           0 :       break;
    1033             :     }
    1034             : 
    1035           0 :     unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */
    1036             : 
    1037           0 :     if (delta > 0)
    1038             :     {
    1039           0 :       if (unlikely (delta + count > HB_MAX_CONTEXT_LENGTH))
    1040           0 :         break;
    1041             :     }
    1042             :     else
    1043             :     {
    1044             :       /* NOTE: delta is negative. */
    1045           0 :       delta = MAX (delta, (int) next - (int) count);
    1046           0 :       next -= delta;
    1047             :     }
    1048             : 
    1049             :     /* Shift! */
    1050           0 :     memmove (match_positions + next + delta, match_positions + next,
    1051           0 :              (count - next) * sizeof (match_positions[0]));
    1052           0 :     next += delta;
    1053           0 :     count += delta;
    1054             : 
    1055             :     /* Fill in new entries. */
    1056           0 :     for (unsigned int j = idx + 1; j < next; j++)
    1057           0 :       match_positions[j] = match_positions[j - 1] + 1;
    1058             : 
    1059             :     /* And fixup the rest. */
    1060           0 :     for (; next < count; next++)
    1061           0 :       match_positions[next] += delta;
    1062             :   }
    1063             : 
    1064           0 :   buffer->move_to (end);
    1065             : 
    1066           0 :   return_trace (true);
    1067             : }
    1068             : 
    1069             : 
    1070             : 
    1071             : /* Contextual lookups */
    1072             : 
    1073             : struct ContextClosureLookupContext
    1074             : {
    1075             :   ContextClosureFuncs funcs;
    1076             :   const void *intersects_data;
    1077             : };
    1078             : 
    1079             : struct ContextCollectGlyphsLookupContext
    1080             : {
    1081             :   ContextCollectGlyphsFuncs funcs;
    1082             :   const void *collect_data;
    1083             : };
    1084             : 
    1085             : struct ContextApplyLookupContext
    1086             : {
    1087             :   ContextApplyFuncs funcs;
    1088             :   const void *match_data;
    1089             : };
    1090             : 
    1091           0 : static inline void context_closure_lookup (hb_closure_context_t *c,
    1092             :                                            unsigned int inputCount, /* Including the first glyph (not matched) */
    1093             :                                            const USHORT input[], /* Array of input values--start with second glyph */
    1094             :                                            unsigned int lookupCount,
    1095             :                                            const LookupRecord lookupRecord[],
    1096             :                                            ContextClosureLookupContext &lookup_context)
    1097             : {
    1098           0 :   if (intersects_array (c,
    1099             :                         inputCount ? inputCount - 1 : 0, input,
    1100             :                         lookup_context.funcs.intersects, lookup_context.intersects_data))
    1101             :     recurse_lookups (c,
    1102           0 :                      lookupCount, lookupRecord);
    1103           0 : }
    1104             : 
    1105           0 : static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
    1106             :                                                   unsigned int inputCount, /* Including the first glyph (not matched) */
    1107             :                                                   const USHORT input[], /* Array of input values--start with second glyph */
    1108             :                                                   unsigned int lookupCount,
    1109             :                                                   const LookupRecord lookupRecord[],
    1110             :                                                   ContextCollectGlyphsLookupContext &lookup_context)
    1111             : {
    1112           0 :   collect_array (c, c->input,
    1113             :                  inputCount ? inputCount - 1 : 0, input,
    1114           0 :                  lookup_context.funcs.collect, lookup_context.collect_data);
    1115             :   recurse_lookups (c,
    1116           0 :                    lookupCount, lookupRecord);
    1117           0 : }
    1118             : 
    1119           0 : static inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
    1120             :                                                unsigned int inputCount, /* Including the first glyph (not matched) */
    1121             :                                                const USHORT input[], /* Array of input values--start with second glyph */
    1122             :                                                unsigned int lookupCount HB_UNUSED,
    1123             :                                                const LookupRecord lookupRecord[] HB_UNUSED,
    1124             :                                                ContextApplyLookupContext &lookup_context)
    1125             : {
    1126           0 :   return would_match_input (c,
    1127             :                             inputCount, input,
    1128           0 :                             lookup_context.funcs.match, lookup_context.match_data);
    1129             : }
    1130           0 : static inline bool context_apply_lookup (hb_apply_context_t *c,
    1131             :                                          unsigned int inputCount, /* Including the first glyph (not matched) */
    1132             :                                          const USHORT input[], /* Array of input values--start with second glyph */
    1133             :                                          unsigned int lookupCount,
    1134             :                                          const LookupRecord lookupRecord[],
    1135             :                                          ContextApplyLookupContext &lookup_context)
    1136             : {
    1137           0 :   unsigned int match_length = 0;
    1138             :   unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
    1139           0 :   return match_input (c,
    1140             :                       inputCount, input,
    1141             :                       lookup_context.funcs.match, lookup_context.match_data,
    1142             :                       &match_length, match_positions)
    1143           0 :       && apply_lookup (c,
    1144             :                        inputCount, match_positions,
    1145             :                        lookupCount, lookupRecord,
    1146           0 :                        match_length);
    1147             : }
    1148             : 
    1149             : struct Rule
    1150             : {
    1151           0 :   inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
    1152             :   {
    1153           0 :     TRACE_CLOSURE (this);
    1154           0 :     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
    1155           0 :     context_closure_lookup (c,
    1156             :                             inputCount, inputZ,
    1157             :                             lookupCount, lookupRecord,
    1158           0 :                             lookup_context);
    1159           0 :   }
    1160             : 
    1161           0 :   inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const
    1162             :   {
    1163           0 :     TRACE_COLLECT_GLYPHS (this);
    1164           0 :     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
    1165           0 :     context_collect_glyphs_lookup (c,
    1166             :                                    inputCount, inputZ,
    1167             :                                    lookupCount, lookupRecord,
    1168           0 :                                    lookup_context);
    1169           0 :   }
    1170             : 
    1171           0 :   inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
    1172             :   {
    1173           0 :     TRACE_WOULD_APPLY (this);
    1174           0 :     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
    1175           0 :     return_trace (context_would_apply_lookup (c, inputCount, inputZ, lookupCount, lookupRecord, lookup_context));
    1176             :   }
    1177             : 
    1178           0 :   inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
    1179             :   {
    1180           0 :     TRACE_APPLY (this);
    1181           0 :     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
    1182           0 :     return_trace (context_apply_lookup (c, inputCount, inputZ, lookupCount, lookupRecord, lookup_context));
    1183             :   }
    1184             : 
    1185             :   public:
    1186           0 :   inline bool sanitize (hb_sanitize_context_t *c) const
    1187             :   {
    1188           0 :     TRACE_SANITIZE (this);
    1189           0 :     return inputCount.sanitize (c)
    1190           0 :         && lookupCount.sanitize (c)
    1191           0 :         && c->check_range (inputZ,
    1192           0 :                            inputZ[0].static_size * inputCount
    1193           0 :                            + lookupRecordX[0].static_size * lookupCount);
    1194             :   }
    1195             : 
    1196             :   protected:
    1197             :   USHORT        inputCount;             /* Total number of glyphs in input
    1198             :                                          * glyph sequence--includes the first
    1199             :                                          * glyph */
    1200             :   USHORT        lookupCount;            /* Number of LookupRecords */
    1201             :   USHORT        inputZ[VAR];            /* Array of match inputs--start with
    1202             :                                          * second glyph */
    1203             :   LookupRecord  lookupRecordX[VAR];     /* Array of LookupRecords--in
    1204             :                                          * design order */
    1205             :   public:
    1206             :   DEFINE_SIZE_ARRAY2 (4, inputZ, lookupRecordX);
    1207             : };
    1208             : 
    1209             : struct RuleSet
    1210             : {
    1211           0 :   inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
    1212             :   {
    1213           0 :     TRACE_CLOSURE (this);
    1214           0 :     unsigned int num_rules = rule.len;
    1215           0 :     for (unsigned int i = 0; i < num_rules; i++)
    1216           0 :       (this+rule[i]).closure (c, lookup_context);
    1217           0 :   }
    1218             : 
    1219           0 :   inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const
    1220             :   {
    1221           0 :     TRACE_COLLECT_GLYPHS (this);
    1222           0 :     unsigned int num_rules = rule.len;
    1223           0 :     for (unsigned int i = 0; i < num_rules; i++)
    1224           0 :       (this+rule[i]).collect_glyphs (c, lookup_context);
    1225           0 :   }
    1226             : 
    1227           0 :   inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
    1228             :   {
    1229           0 :     TRACE_WOULD_APPLY (this);
    1230           0 :     unsigned int num_rules = rule.len;
    1231           0 :     for (unsigned int i = 0; i < num_rules; i++)
    1232             :     {
    1233           0 :       if ((this+rule[i]).would_apply (c, lookup_context))
    1234           0 :         return_trace (true);
    1235             :     }
    1236           0 :     return_trace (false);
    1237             :   }
    1238             : 
    1239           0 :   inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
    1240             :   {
    1241           0 :     TRACE_APPLY (this);
    1242           0 :     unsigned int num_rules = rule.len;
    1243           0 :     for (unsigned int i = 0; i < num_rules; i++)
    1244             :     {
    1245           0 :       if ((this+rule[i]).apply (c, lookup_context))
    1246           0 :         return_trace (true);
    1247             :     }
    1248           0 :     return_trace (false);
    1249             :   }
    1250             : 
    1251           0 :   inline bool sanitize (hb_sanitize_context_t *c) const
    1252             :   {
    1253           0 :     TRACE_SANITIZE (this);
    1254           0 :     return_trace (rule.sanitize (c, this));
    1255             :   }
    1256             : 
    1257             :   protected:
    1258             :   OffsetArrayOf<Rule>
    1259             :                 rule;                   /* Array of Rule tables
    1260             :                                          * ordered by preference */
    1261             :   public:
    1262             :   DEFINE_SIZE_ARRAY (2, rule);
    1263             : };
    1264             : 
    1265             : 
    1266             : struct ContextFormat1
    1267             : {
    1268           0 :   inline void closure (hb_closure_context_t *c) const
    1269             :   {
    1270           0 :     TRACE_CLOSURE (this);
    1271             : 
    1272           0 :     const Coverage &cov = (this+coverage);
    1273             : 
    1274             :     struct ContextClosureLookupContext lookup_context = {
    1275             :       {intersects_glyph},
    1276             :       NULL
    1277           0 :     };
    1278             : 
    1279           0 :     unsigned int count = ruleSet.len;
    1280           0 :     for (unsigned int i = 0; i < count; i++)
    1281           0 :       if (cov.intersects_coverage (c->glyphs, i)) {
    1282           0 :         const RuleSet &rule_set = this+ruleSet[i];
    1283           0 :         rule_set.closure (c, lookup_context);
    1284             :       }
    1285           0 :   }
    1286             : 
    1287           0 :   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
    1288             :   {
    1289           0 :     TRACE_COLLECT_GLYPHS (this);
    1290           0 :     (this+coverage).add_coverage (c->input);
    1291             : 
    1292             :     struct ContextCollectGlyphsLookupContext lookup_context = {
    1293             :       {collect_glyph},
    1294             :       NULL
    1295           0 :     };
    1296             : 
    1297           0 :     unsigned int count = ruleSet.len;
    1298           0 :     for (unsigned int i = 0; i < count; i++)
    1299           0 :       (this+ruleSet[i]).collect_glyphs (c, lookup_context);
    1300           0 :   }
    1301             : 
    1302           0 :   inline bool would_apply (hb_would_apply_context_t *c) const
    1303             :   {
    1304           0 :     TRACE_WOULD_APPLY (this);
    1305             : 
    1306           0 :     const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
    1307             :     struct ContextApplyLookupContext lookup_context = {
    1308             :       {match_glyph},
    1309             :       NULL
    1310           0 :     };
    1311           0 :     return_trace (rule_set.would_apply (c, lookup_context));
    1312             :   }
    1313             : 
    1314           0 :   inline const Coverage &get_coverage (void) const
    1315             :   {
    1316           0 :     return this+coverage;
    1317             :   }
    1318             : 
    1319           0 :   inline bool apply (hb_apply_context_t *c) const
    1320             :   {
    1321           0 :     TRACE_APPLY (this);
    1322           0 :     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
    1323           0 :     if (likely (index == NOT_COVERED))
    1324           0 :       return_trace (false);
    1325             : 
    1326           0 :     const RuleSet &rule_set = this+ruleSet[index];
    1327             :     struct ContextApplyLookupContext lookup_context = {
    1328             :       {match_glyph},
    1329             :       NULL
    1330           0 :     };
    1331           0 :     return_trace (rule_set.apply (c, lookup_context));
    1332             :   }
    1333             : 
    1334           0 :   inline bool sanitize (hb_sanitize_context_t *c) const
    1335             :   {
    1336           0 :     TRACE_SANITIZE (this);
    1337           0 :     return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
    1338             :   }
    1339             : 
    1340             :   protected:
    1341             :   USHORT        format;                 /* Format identifier--format = 1 */
    1342             :   OffsetTo<Coverage>
    1343             :                 coverage;               /* Offset to Coverage table--from
    1344             :                                          * beginning of table */
    1345             :   OffsetArrayOf<RuleSet>
    1346             :                 ruleSet;                /* Array of RuleSet tables
    1347             :                                          * ordered by Coverage Index */
    1348             :   public:
    1349             :   DEFINE_SIZE_ARRAY (6, ruleSet);
    1350             : };
    1351             : 
    1352             : 
    1353             : struct ContextFormat2
    1354             : {
    1355           0 :   inline void closure (hb_closure_context_t *c) const
    1356             :   {
    1357           0 :     TRACE_CLOSURE (this);
    1358           0 :     if (!(this+coverage).intersects (c->glyphs))
    1359           0 :       return;
    1360             : 
    1361           0 :     const ClassDef &class_def = this+classDef;
    1362             : 
    1363             :     struct ContextClosureLookupContext lookup_context = {
    1364             :       {intersects_class},
    1365             :       &class_def
    1366           0 :     };
    1367             : 
    1368           0 :     unsigned int count = ruleSet.len;
    1369           0 :     for (unsigned int i = 0; i < count; i++)
    1370           0 :       if (class_def.intersects_class (c->glyphs, i)) {
    1371           0 :         const RuleSet &rule_set = this+ruleSet[i];
    1372           0 :         rule_set.closure (c, lookup_context);
    1373             :       }
    1374             :   }
    1375             : 
    1376           0 :   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
    1377             :   {
    1378           0 :     TRACE_COLLECT_GLYPHS (this);
    1379           0 :     (this+coverage).add_coverage (c->input);
    1380             : 
    1381           0 :     const ClassDef &class_def = this+classDef;
    1382             :     struct ContextCollectGlyphsLookupContext lookup_context = {
    1383             :       {collect_class},
    1384             :       &class_def
    1385           0 :     };
    1386             : 
    1387           0 :     unsigned int count = ruleSet.len;
    1388           0 :     for (unsigned int i = 0; i < count; i++)
    1389           0 :       (this+ruleSet[i]).collect_glyphs (c, lookup_context);
    1390           0 :   }
    1391             : 
    1392           0 :   inline bool would_apply (hb_would_apply_context_t *c) const
    1393             :   {
    1394           0 :     TRACE_WOULD_APPLY (this);
    1395             : 
    1396           0 :     const ClassDef &class_def = this+classDef;
    1397           0 :     unsigned int index = class_def.get_class (c->glyphs[0]);
    1398           0 :     const RuleSet &rule_set = this+ruleSet[index];
    1399             :     struct ContextApplyLookupContext lookup_context = {
    1400             :       {match_class},
    1401             :       &class_def
    1402           0 :     };
    1403           0 :     return_trace (rule_set.would_apply (c, lookup_context));
    1404             :   }
    1405             : 
    1406           0 :   inline const Coverage &get_coverage (void) const
    1407             :   {
    1408           0 :     return this+coverage;
    1409             :   }
    1410             : 
    1411           0 :   inline bool apply (hb_apply_context_t *c) const
    1412             :   {
    1413           0 :     TRACE_APPLY (this);
    1414           0 :     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
    1415           0 :     if (likely (index == NOT_COVERED)) return_trace (false);
    1416             : 
    1417           0 :     const ClassDef &class_def = this+classDef;
    1418           0 :     index = class_def.get_class (c->buffer->cur().codepoint);
    1419           0 :     const RuleSet &rule_set = this+ruleSet[index];
    1420             :     struct ContextApplyLookupContext lookup_context = {
    1421             :       {match_class},
    1422             :       &class_def
    1423           0 :     };
    1424           0 :     return_trace (rule_set.apply (c, lookup_context));
    1425             :   }
    1426             : 
    1427           0 :   inline bool sanitize (hb_sanitize_context_t *c) const
    1428             :   {
    1429           0 :     TRACE_SANITIZE (this);
    1430           0 :     return_trace (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
    1431             :   }
    1432             : 
    1433             :   protected:
    1434             :   USHORT        format;                 /* Format identifier--format = 2 */
    1435             :   OffsetTo<Coverage>
    1436             :                 coverage;               /* Offset to Coverage table--from
    1437             :                                          * beginning of table */
    1438             :   OffsetTo<ClassDef>
    1439             :                 classDef;               /* Offset to glyph ClassDef table--from
    1440             :                                          * beginning of table */
    1441             :   OffsetArrayOf<RuleSet>
    1442             :                 ruleSet;                /* Array of RuleSet tables
    1443             :                                          * ordered by class */
    1444             :   public:
    1445             :   DEFINE_SIZE_ARRAY (8, ruleSet);
    1446             : };
    1447             : 
    1448             : 
    1449             : struct ContextFormat3
    1450             : {
    1451           0 :   inline void closure (hb_closure_context_t *c) const
    1452             :   {
    1453           0 :     TRACE_CLOSURE (this);
    1454           0 :     if (!(this+coverageZ[0]).intersects (c->glyphs))
    1455           0 :       return;
    1456             : 
    1457           0 :     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
    1458             :     struct ContextClosureLookupContext lookup_context = {
    1459             :       {intersects_coverage},
    1460             :       this
    1461           0 :     };
    1462           0 :     context_closure_lookup (c,
    1463             :                             glyphCount, (const USHORT *) (coverageZ + 1),
    1464             :                             lookupCount, lookupRecord,
    1465           0 :                             lookup_context);
    1466             :   }
    1467             : 
    1468           0 :   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
    1469             :   {
    1470           0 :     TRACE_COLLECT_GLYPHS (this);
    1471           0 :     (this+coverageZ[0]).add_coverage (c->input);
    1472             : 
    1473           0 :     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
    1474             :     struct ContextCollectGlyphsLookupContext lookup_context = {
    1475             :       {collect_coverage},
    1476             :       this
    1477           0 :     };
    1478             : 
    1479           0 :     context_collect_glyphs_lookup (c,
    1480             :                                    glyphCount, (const USHORT *) (coverageZ + 1),
    1481             :                                    lookupCount, lookupRecord,
    1482           0 :                                    lookup_context);
    1483           0 :   }
    1484             : 
    1485           0 :   inline bool would_apply (hb_would_apply_context_t *c) const
    1486             :   {
    1487           0 :     TRACE_WOULD_APPLY (this);
    1488             : 
    1489           0 :     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
    1490             :     struct ContextApplyLookupContext lookup_context = {
    1491             :       {match_coverage},
    1492             :       this
    1493           0 :     };
    1494           0 :     return_trace (context_would_apply_lookup (c, glyphCount, (const USHORT *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
    1495             :   }
    1496             : 
    1497           0 :   inline const Coverage &get_coverage (void) const
    1498             :   {
    1499           0 :     return this+coverageZ[0];
    1500             :   }
    1501             : 
    1502           0 :   inline bool apply (hb_apply_context_t *c) const
    1503             :   {
    1504           0 :     TRACE_APPLY (this);
    1505           0 :     unsigned int index = (this+coverageZ[0]).get_coverage (c->buffer->cur().codepoint);
    1506           0 :     if (likely (index == NOT_COVERED)) return_trace (false);
    1507             : 
    1508           0 :     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
    1509             :     struct ContextApplyLookupContext lookup_context = {
    1510             :       {match_coverage},
    1511             :       this
    1512           0 :     };
    1513           0 :     return_trace (context_apply_lookup (c, glyphCount, (const USHORT *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
    1514             :   }
    1515             : 
    1516           0 :   inline bool sanitize (hb_sanitize_context_t *c) const
    1517             :   {
    1518           0 :     TRACE_SANITIZE (this);
    1519           0 :     if (!c->check_struct (this)) return_trace (false);
    1520           0 :     unsigned int count = glyphCount;
    1521           0 :     if (!count) return_trace (false); /* We want to access coverageZ[0] freely. */
    1522           0 :     if (!c->check_array (coverageZ, coverageZ[0].static_size, count)) return_trace (false);
    1523           0 :     for (unsigned int i = 0; i < count; i++)
    1524           0 :       if (!coverageZ[i].sanitize (c, this)) return_trace (false);
    1525           0 :     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * count);
    1526           0 :     return_trace (c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount));
    1527             :   }
    1528             : 
    1529             :   protected:
    1530             :   USHORT        format;                 /* Format identifier--format = 3 */
    1531             :   USHORT        glyphCount;             /* Number of glyphs in the input glyph
    1532             :                                          * sequence */
    1533             :   USHORT        lookupCount;            /* Number of LookupRecords */
    1534             :   OffsetTo<Coverage>
    1535             :                 coverageZ[VAR];         /* Array of offsets to Coverage
    1536             :                                          * table in glyph sequence order */
    1537             :   LookupRecord  lookupRecordX[VAR];     /* Array of LookupRecords--in
    1538             :                                          * design order */
    1539             :   public:
    1540             :   DEFINE_SIZE_ARRAY2 (6, coverageZ, lookupRecordX);
    1541             : };
    1542             : 
    1543             : struct Context
    1544             : {
    1545             :   template <typename context_t>
    1546           0 :   inline typename context_t::return_t dispatch (context_t *c) const
    1547             :   {
    1548           0 :     TRACE_DISPATCH (this, u.format);
    1549           0 :     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
    1550           0 :     switch (u.format) {
    1551           0 :     case 1: return_trace (c->dispatch (u.format1));
    1552           0 :     case 2: return_trace (c->dispatch (u.format2));
    1553           0 :     case 3: return_trace (c->dispatch (u.format3));
    1554           0 :     default:return_trace (c->default_return_value ());
    1555             :     }
    1556             :   }
    1557             : 
    1558             :   protected:
    1559             :   union {
    1560             :   USHORT                format;         /* Format identifier */
    1561             :   ContextFormat1        format1;
    1562             :   ContextFormat2        format2;
    1563             :   ContextFormat3        format3;
    1564             :   } u;
    1565             : };
    1566             : 
    1567             : 
    1568             : /* Chaining Contextual lookups */
    1569             : 
    1570             : struct ChainContextClosureLookupContext
    1571             : {
    1572             :   ContextClosureFuncs funcs;
    1573             :   const void *intersects_data[3];
    1574             : };
    1575             : 
    1576             : struct ChainContextCollectGlyphsLookupContext
    1577             : {
    1578             :   ContextCollectGlyphsFuncs funcs;
    1579             :   const void *collect_data[3];
    1580             : };
    1581             : 
    1582             : struct ChainContextApplyLookupContext
    1583             : {
    1584             :   ContextApplyFuncs funcs;
    1585             :   const void *match_data[3];
    1586             : };
    1587             : 
    1588           0 : static inline void chain_context_closure_lookup (hb_closure_context_t *c,
    1589             :                                                  unsigned int backtrackCount,
    1590             :                                                  const USHORT backtrack[],
    1591             :                                                  unsigned int inputCount, /* Including the first glyph (not matched) */
    1592             :                                                  const USHORT input[], /* Array of input values--start with second glyph */
    1593             :                                                  unsigned int lookaheadCount,
    1594             :                                                  const USHORT lookahead[],
    1595             :                                                  unsigned int lookupCount,
    1596             :                                                  const LookupRecord lookupRecord[],
    1597             :                                                  ChainContextClosureLookupContext &lookup_context)
    1598             : {
    1599           0 :   if (intersects_array (c,
    1600             :                         backtrackCount, backtrack,
    1601             :                         lookup_context.funcs.intersects, lookup_context.intersects_data[0])
    1602           0 :    && intersects_array (c,
    1603             :                         inputCount ? inputCount - 1 : 0, input,
    1604             :                         lookup_context.funcs.intersects, lookup_context.intersects_data[1])
    1605           0 :    && intersects_array (c,
    1606             :                        lookaheadCount, lookahead,
    1607             :                        lookup_context.funcs.intersects, lookup_context.intersects_data[2]))
    1608             :     recurse_lookups (c,
    1609           0 :                      lookupCount, lookupRecord);
    1610           0 : }
    1611             : 
    1612          11 : static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
    1613             :                                                         unsigned int backtrackCount,
    1614             :                                                         const USHORT backtrack[],
    1615             :                                                         unsigned int inputCount, /* Including the first glyph (not matched) */
    1616             :                                                         const USHORT input[], /* Array of input values--start with second glyph */
    1617             :                                                         unsigned int lookaheadCount,
    1618             :                                                         const USHORT lookahead[],
    1619             :                                                         unsigned int lookupCount,
    1620             :                                                         const LookupRecord lookupRecord[],
    1621             :                                                         ChainContextCollectGlyphsLookupContext &lookup_context)
    1622             : {
    1623          11 :   collect_array (c, c->before,
    1624             :                  backtrackCount, backtrack,
    1625          11 :                  lookup_context.funcs.collect, lookup_context.collect_data[0]);
    1626          11 :   collect_array (c, c->input,
    1627             :                  inputCount ? inputCount - 1 : 0, input,
    1628          11 :                  lookup_context.funcs.collect, lookup_context.collect_data[1]);
    1629          11 :   collect_array (c, c->after,
    1630             :                  lookaheadCount, lookahead,
    1631          11 :                  lookup_context.funcs.collect, lookup_context.collect_data[2]);
    1632             :   recurse_lookups (c,
    1633          11 :                    lookupCount, lookupRecord);
    1634          11 : }
    1635             : 
    1636           0 : static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c,
    1637             :                                                      unsigned int backtrackCount,
    1638             :                                                      const USHORT backtrack[] HB_UNUSED,
    1639             :                                                      unsigned int inputCount, /* Including the first glyph (not matched) */
    1640             :                                                      const USHORT input[], /* Array of input values--start with second glyph */
    1641             :                                                      unsigned int lookaheadCount,
    1642             :                                                      const USHORT lookahead[] HB_UNUSED,
    1643             :                                                      unsigned int lookupCount HB_UNUSED,
    1644             :                                                      const LookupRecord lookupRecord[] HB_UNUSED,
    1645             :                                                      ChainContextApplyLookupContext &lookup_context)
    1646             : {
    1647           0 :   return (c->zero_context ? !backtrackCount && !lookaheadCount : true)
    1648           0 :       && would_match_input (c,
    1649             :                             inputCount, input,
    1650           0 :                             lookup_context.funcs.match, lookup_context.match_data[1]);
    1651             : }
    1652             : 
    1653           1 : static inline bool chain_context_apply_lookup (hb_apply_context_t *c,
    1654             :                                                unsigned int backtrackCount,
    1655             :                                                const USHORT backtrack[],
    1656             :                                                unsigned int inputCount, /* Including the first glyph (not matched) */
    1657             :                                                const USHORT input[], /* Array of input values--start with second glyph */
    1658             :                                                unsigned int lookaheadCount,
    1659             :                                                const USHORT lookahead[],
    1660             :                                                unsigned int lookupCount,
    1661             :                                                const LookupRecord lookupRecord[],
    1662             :                                                ChainContextApplyLookupContext &lookup_context)
    1663             : {
    1664           1 :   unsigned int match_length = 0;
    1665             :   unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
    1666           1 :   return match_input (c,
    1667             :                       inputCount, input,
    1668             :                       lookup_context.funcs.match, lookup_context.match_data[1],
    1669             :                       &match_length, match_positions)
    1670           1 :       && match_backtrack (c,
    1671             :                           backtrackCount, backtrack,
    1672             :                           lookup_context.funcs.match, lookup_context.match_data[0])
    1673           1 :       && match_lookahead (c,
    1674             :                           lookaheadCount, lookahead,
    1675             :                           lookup_context.funcs.match, lookup_context.match_data[2],
    1676             :                           match_length)
    1677           1 :       && apply_lookup (c,
    1678             :                        inputCount, match_positions,
    1679             :                        lookupCount, lookupRecord,
    1680           1 :                        match_length);
    1681             : }
    1682             : 
    1683             : struct ChainRule
    1684             : {
    1685           0 :   inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
    1686             :   {
    1687           0 :     TRACE_CLOSURE (this);
    1688           0 :     const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
    1689           0 :     const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
    1690           0 :     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
    1691           0 :     chain_context_closure_lookup (c,
    1692             :                                   backtrack.len, backtrack.array,
    1693             :                                   input.len, input.array,
    1694             :                                   lookahead.len, lookahead.array,
    1695             :                                   lookup.len, lookup.array,
    1696           0 :                                   lookup_context);
    1697           0 :   }
    1698             : 
    1699           8 :   inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
    1700             :   {
    1701           8 :     TRACE_COLLECT_GLYPHS (this);
    1702           8 :     const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
    1703           8 :     const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
    1704           8 :     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
    1705          40 :     chain_context_collect_glyphs_lookup (c,
    1706             :                                          backtrack.len, backtrack.array,
    1707             :                                          input.len, input.array,
    1708             :                                          lookahead.len, lookahead.array,
    1709             :                                          lookup.len, lookup.array,
    1710          40 :                                          lookup_context);
    1711           8 :   }
    1712             : 
    1713           0 :   inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
    1714             :   {
    1715           0 :     TRACE_WOULD_APPLY (this);
    1716           0 :     const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
    1717           0 :     const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
    1718           0 :     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
    1719           0 :     return_trace (chain_context_would_apply_lookup (c,
    1720             :                                                     backtrack.len, backtrack.array,
    1721             :                                                     input.len, input.array,
    1722             :                                                     lookahead.len, lookahead.array, lookup.len,
    1723             :                                                     lookup.array, lookup_context));
    1724             :   }
    1725             : 
    1726           1 :   inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
    1727             :   {
    1728           1 :     TRACE_APPLY (this);
    1729           1 :     const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
    1730           1 :     const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
    1731           1 :     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
    1732           1 :     return_trace (chain_context_apply_lookup (c,
    1733             :                                               backtrack.len, backtrack.array,
    1734             :                                               input.len, input.array,
    1735             :                                               lookahead.len, lookahead.array, lookup.len,
    1736             :                                               lookup.array, lookup_context));
    1737             :   }
    1738             : 
    1739           4 :   inline bool sanitize (hb_sanitize_context_t *c) const
    1740             :   {
    1741           4 :     TRACE_SANITIZE (this);
    1742           4 :     if (!backtrack.sanitize (c)) return_trace (false);
    1743           4 :     const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
    1744           4 :     if (!input.sanitize (c)) return_trace (false);
    1745           4 :     const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
    1746           4 :     if (!lookahead.sanitize (c)) return_trace (false);
    1747           4 :     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
    1748           4 :     return_trace (lookup.sanitize (c));
    1749             :   }
    1750             : 
    1751             :   protected:
    1752             :   ArrayOf<USHORT>
    1753             :                 backtrack;              /* Array of backtracking values
    1754             :                                          * (to be matched before the input
    1755             :                                          * sequence) */
    1756             :   HeadlessArrayOf<USHORT>
    1757             :                 inputX;                 /* Array of input values (start with
    1758             :                                          * second glyph) */
    1759             :   ArrayOf<USHORT>
    1760             :                 lookaheadX;             /* Array of lookahead values's (to be
    1761             :                                          * matched after the input sequence) */
    1762             :   ArrayOf<LookupRecord>
    1763             :                 lookupX;                /* Array of LookupRecords--in
    1764             :                                          * design order) */
    1765             :   public:
    1766             :   DEFINE_SIZE_MIN (8);
    1767             : };
    1768             : 
    1769             : struct ChainRuleSet
    1770             : {
    1771           0 :   inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
    1772             :   {
    1773           0 :     TRACE_CLOSURE (this);
    1774           0 :     unsigned int num_rules = rule.len;
    1775           0 :     for (unsigned int i = 0; i < num_rules; i++)
    1776           0 :       (this+rule[i]).closure (c, lookup_context);
    1777           0 :   }
    1778             : 
    1779          16 :   inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
    1780             :   {
    1781          16 :     TRACE_COLLECT_GLYPHS (this);
    1782          16 :     unsigned int num_rules = rule.len;
    1783          24 :     for (unsigned int i = 0; i < num_rules; i++)
    1784           8 :       (this+rule[i]).collect_glyphs (c, lookup_context);
    1785          16 :   }
    1786             : 
    1787           0 :   inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
    1788             :   {
    1789           0 :     TRACE_WOULD_APPLY (this);
    1790           0 :     unsigned int num_rules = rule.len;
    1791           0 :     for (unsigned int i = 0; i < num_rules; i++)
    1792           0 :       if ((this+rule[i]).would_apply (c, lookup_context))
    1793           0 :         return_trace (true);
    1794             : 
    1795           0 :     return_trace (false);
    1796             :   }
    1797             : 
    1798           1 :   inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
    1799             :   {
    1800           1 :     TRACE_APPLY (this);
    1801           1 :     unsigned int num_rules = rule.len;
    1802           2 :     for (unsigned int i = 0; i < num_rules; i++)
    1803           1 :       if ((this+rule[i]).apply (c, lookup_context))
    1804           0 :         return_trace (true);
    1805             : 
    1806           1 :     return_trace (false);
    1807             :   }
    1808             : 
    1809           4 :   inline bool sanitize (hb_sanitize_context_t *c) const
    1810             :   {
    1811           4 :     TRACE_SANITIZE (this);
    1812           4 :     return_trace (rule.sanitize (c, this));
    1813             :   }
    1814             : 
    1815             :   protected:
    1816             :   OffsetArrayOf<ChainRule>
    1817             :                 rule;                   /* Array of ChainRule tables
    1818             :                                          * ordered by preference */
    1819             :   public:
    1820             :   DEFINE_SIZE_ARRAY (2, rule);
    1821             : };
    1822             : 
    1823             : struct ChainContextFormat1
    1824             : {
    1825           0 :   inline void closure (hb_closure_context_t *c) const
    1826             :   {
    1827           0 :     TRACE_CLOSURE (this);
    1828           0 :     const Coverage &cov = (this+coverage);
    1829             : 
    1830             :     struct ChainContextClosureLookupContext lookup_context = {
    1831             :       {intersects_glyph},
    1832             :       {NULL, NULL, NULL}
    1833           0 :     };
    1834             : 
    1835           0 :     unsigned int count = ruleSet.len;
    1836           0 :     for (unsigned int i = 0; i < count; i++)
    1837           0 :       if (cov.intersects_coverage (c->glyphs, i)) {
    1838           0 :         const ChainRuleSet &rule_set = this+ruleSet[i];
    1839           0 :         rule_set.closure (c, lookup_context);
    1840             :       }
    1841           0 :   }
    1842             : 
    1843           0 :   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
    1844             :   {
    1845           0 :     TRACE_COLLECT_GLYPHS (this);
    1846           0 :     (this+coverage).add_coverage (c->input);
    1847             : 
    1848             :     struct ChainContextCollectGlyphsLookupContext lookup_context = {
    1849             :       {collect_glyph},
    1850             :       {NULL, NULL, NULL}
    1851           0 :     };
    1852             : 
    1853           0 :     unsigned int count = ruleSet.len;
    1854           0 :     for (unsigned int i = 0; i < count; i++)
    1855           0 :       (this+ruleSet[i]).collect_glyphs (c, lookup_context);
    1856           0 :   }
    1857             : 
    1858           0 :   inline bool would_apply (hb_would_apply_context_t *c) const
    1859             :   {
    1860           0 :     TRACE_WOULD_APPLY (this);
    1861             : 
    1862           0 :     const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
    1863             :     struct ChainContextApplyLookupContext lookup_context = {
    1864             :       {match_glyph},
    1865             :       {NULL, NULL, NULL}
    1866           0 :     };
    1867           0 :     return_trace (rule_set.would_apply (c, lookup_context));
    1868             :   }
    1869             : 
    1870           0 :   inline const Coverage &get_coverage (void) const
    1871             :   {
    1872           0 :     return this+coverage;
    1873             :   }
    1874             : 
    1875           0 :   inline bool apply (hb_apply_context_t *c) const
    1876             :   {
    1877           0 :     TRACE_APPLY (this);
    1878           0 :     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
    1879           0 :     if (likely (index == NOT_COVERED)) return_trace (false);
    1880             : 
    1881           0 :     const ChainRuleSet &rule_set = this+ruleSet[index];
    1882             :     struct ChainContextApplyLookupContext lookup_context = {
    1883             :       {match_glyph},
    1884             :       {NULL, NULL, NULL}
    1885           0 :     };
    1886           0 :     return_trace (rule_set.apply (c, lookup_context));
    1887             :   }
    1888             : 
    1889           0 :   inline bool sanitize (hb_sanitize_context_t *c) const
    1890             :   {
    1891           0 :     TRACE_SANITIZE (this);
    1892           0 :     return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
    1893             :   }
    1894             : 
    1895             :   protected:
    1896             :   USHORT        format;                 /* Format identifier--format = 1 */
    1897             :   OffsetTo<Coverage>
    1898             :                 coverage;               /* Offset to Coverage table--from
    1899             :                                          * beginning of table */
    1900             :   OffsetArrayOf<ChainRuleSet>
    1901             :                 ruleSet;                /* Array of ChainRuleSet tables
    1902             :                                          * ordered by Coverage Index */
    1903             :   public:
    1904             :   DEFINE_SIZE_ARRAY (6, ruleSet);
    1905             : };
    1906             : 
    1907             : struct ChainContextFormat2
    1908             : {
    1909           0 :   inline void closure (hb_closure_context_t *c) const
    1910             :   {
    1911           0 :     TRACE_CLOSURE (this);
    1912           0 :     if (!(this+coverage).intersects (c->glyphs))
    1913           0 :       return;
    1914             : 
    1915           0 :     const ClassDef &backtrack_class_def = this+backtrackClassDef;
    1916           0 :     const ClassDef &input_class_def = this+inputClassDef;
    1917           0 :     const ClassDef &lookahead_class_def = this+lookaheadClassDef;
    1918             : 
    1919             :     struct ChainContextClosureLookupContext lookup_context = {
    1920             :       {intersects_class},
    1921             :       {&backtrack_class_def,
    1922             :        &input_class_def,
    1923             :        &lookahead_class_def}
    1924           0 :     };
    1925             : 
    1926           0 :     unsigned int count = ruleSet.len;
    1927           0 :     for (unsigned int i = 0; i < count; i++)
    1928           0 :       if (input_class_def.intersects_class (c->glyphs, i)) {
    1929           0 :         const ChainRuleSet &rule_set = this+ruleSet[i];
    1930           0 :         rule_set.closure (c, lookup_context);
    1931             :       }
    1932             :   }
    1933             : 
    1934           4 :   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
    1935             :   {
    1936           4 :     TRACE_COLLECT_GLYPHS (this);
    1937           4 :     (this+coverage).add_coverage (c->input);
    1938             : 
    1939           4 :     const ClassDef &backtrack_class_def = this+backtrackClassDef;
    1940           4 :     const ClassDef &input_class_def = this+inputClassDef;
    1941           4 :     const ClassDef &lookahead_class_def = this+lookaheadClassDef;
    1942             : 
    1943             :     struct ChainContextCollectGlyphsLookupContext lookup_context = {
    1944             :       {collect_class},
    1945             :       {&backtrack_class_def,
    1946             :        &input_class_def,
    1947             :        &lookahead_class_def}
    1948           4 :     };
    1949             : 
    1950           4 :     unsigned int count = ruleSet.len;
    1951          20 :     for (unsigned int i = 0; i < count; i++)
    1952          16 :       (this+ruleSet[i]).collect_glyphs (c, lookup_context);
    1953           4 :   }
    1954             : 
    1955           0 :   inline bool would_apply (hb_would_apply_context_t *c) const
    1956             :   {
    1957           0 :     TRACE_WOULD_APPLY (this);
    1958             : 
    1959           0 :     const ClassDef &backtrack_class_def = this+backtrackClassDef;
    1960           0 :     const ClassDef &input_class_def = this+inputClassDef;
    1961           0 :     const ClassDef &lookahead_class_def = this+lookaheadClassDef;
    1962             : 
    1963           0 :     unsigned int index = input_class_def.get_class (c->glyphs[0]);
    1964           0 :     const ChainRuleSet &rule_set = this+ruleSet[index];
    1965             :     struct ChainContextApplyLookupContext lookup_context = {
    1966             :       {match_class},
    1967             :       {&backtrack_class_def,
    1968             :        &input_class_def,
    1969             :        &lookahead_class_def}
    1970           0 :     };
    1971           0 :     return_trace (rule_set.would_apply (c, lookup_context));
    1972             :   }
    1973             : 
    1974           2 :   inline const Coverage &get_coverage (void) const
    1975             :   {
    1976           2 :     return this+coverage;
    1977             :   }
    1978             : 
    1979           4 :   inline bool apply (hb_apply_context_t *c) const
    1980             :   {
    1981           4 :     TRACE_APPLY (this);
    1982           4 :     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
    1983           4 :     if (likely (index == NOT_COVERED)) return_trace (false);
    1984             : 
    1985           1 :     const ClassDef &backtrack_class_def = this+backtrackClassDef;
    1986           1 :     const ClassDef &input_class_def = this+inputClassDef;
    1987           1 :     const ClassDef &lookahead_class_def = this+lookaheadClassDef;
    1988             : 
    1989           1 :     index = input_class_def.get_class (c->buffer->cur().codepoint);
    1990           1 :     const ChainRuleSet &rule_set = this+ruleSet[index];
    1991             :     struct ChainContextApplyLookupContext lookup_context = {
    1992             :       {match_class},
    1993             :       {&backtrack_class_def,
    1994             :        &input_class_def,
    1995             :        &lookahead_class_def}
    1996           1 :     };
    1997           1 :     return_trace (rule_set.apply (c, lookup_context));
    1998             :   }
    1999             : 
    2000           2 :   inline bool sanitize (hb_sanitize_context_t *c) const
    2001             :   {
    2002           2 :     TRACE_SANITIZE (this);
    2003           2 :     return_trace (coverage.sanitize (c, this) &&
    2004             :                   backtrackClassDef.sanitize (c, this) &&
    2005             :                   inputClassDef.sanitize (c, this) &&
    2006             :                   lookaheadClassDef.sanitize (c, this) &&
    2007             :                   ruleSet.sanitize (c, this));
    2008             :   }
    2009             : 
    2010             :   protected:
    2011             :   USHORT        format;                 /* Format identifier--format = 2 */
    2012             :   OffsetTo<Coverage>
    2013             :                 coverage;               /* Offset to Coverage table--from
    2014             :                                          * beginning of table */
    2015             :   OffsetTo<ClassDef>
    2016             :                 backtrackClassDef;      /* Offset to glyph ClassDef table
    2017             :                                          * containing backtrack sequence
    2018             :                                          * data--from beginning of table */
    2019             :   OffsetTo<ClassDef>
    2020             :                 inputClassDef;          /* Offset to glyph ClassDef
    2021             :                                          * table containing input sequence
    2022             :                                          * data--from beginning of table */
    2023             :   OffsetTo<ClassDef>
    2024             :                 lookaheadClassDef;      /* Offset to glyph ClassDef table
    2025             :                                          * containing lookahead sequence
    2026             :                                          * data--from beginning of table */
    2027             :   OffsetArrayOf<ChainRuleSet>
    2028             :                 ruleSet;                /* Array of ChainRuleSet tables
    2029             :                                          * ordered by class */
    2030             :   public:
    2031             :   DEFINE_SIZE_ARRAY (12, ruleSet);
    2032             : };
    2033             : 
    2034             : struct ChainContextFormat3
    2035             : {
    2036           0 :   inline void closure (hb_closure_context_t *c) const
    2037             :   {
    2038           0 :     TRACE_CLOSURE (this);
    2039           0 :     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
    2040             : 
    2041           0 :     if (!(this+input[0]).intersects (c->glyphs))
    2042           0 :       return;
    2043             : 
    2044           0 :     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
    2045           0 :     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
    2046             :     struct ChainContextClosureLookupContext lookup_context = {
    2047             :       {intersects_coverage},
    2048             :       {this, this, this}
    2049           0 :     };
    2050           0 :     chain_context_closure_lookup (c,
    2051             :                                   backtrack.len, (const USHORT *) backtrack.array,
    2052           0 :                                   input.len, (const USHORT *) input.array + 1,
    2053             :                                   lookahead.len, (const USHORT *) lookahead.array,
    2054             :                                   lookup.len, lookup.array,
    2055           0 :                                   lookup_context);
    2056             :   }
    2057             : 
    2058           3 :   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
    2059             :   {
    2060           3 :     TRACE_COLLECT_GLYPHS (this);
    2061           3 :     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
    2062             : 
    2063           3 :     (this+input[0]).add_coverage (c->input);
    2064             : 
    2065           3 :     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
    2066           3 :     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
    2067             :     struct ChainContextCollectGlyphsLookupContext lookup_context = {
    2068             :       {collect_coverage},
    2069             :       {this, this, this}
    2070           3 :     };
    2071          18 :     chain_context_collect_glyphs_lookup (c,
    2072             :                                          backtrack.len, (const USHORT *) backtrack.array,
    2073           3 :                                          input.len, (const USHORT *) input.array + 1,
    2074             :                                          lookahead.len, (const USHORT *) lookahead.array,
    2075             :                                          lookup.len, lookup.array,
    2076          15 :                                          lookup_context);
    2077           3 :   }
    2078             : 
    2079           0 :   inline bool would_apply (hb_would_apply_context_t *c) const
    2080             :   {
    2081           0 :     TRACE_WOULD_APPLY (this);
    2082             : 
    2083           0 :     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
    2084           0 :     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
    2085           0 :     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
    2086             :     struct ChainContextApplyLookupContext lookup_context = {
    2087             :       {match_coverage},
    2088             :       {this, this, this}
    2089           0 :     };
    2090           0 :     return_trace (chain_context_would_apply_lookup (c,
    2091             :                                                     backtrack.len, (const USHORT *) backtrack.array,
    2092             :                                                     input.len, (const USHORT *) input.array + 1,
    2093             :                                                     lookahead.len, (const USHORT *) lookahead.array,
    2094             :                                                     lookup.len, lookup.array, lookup_context));
    2095             :   }
    2096             : 
    2097           2 :   inline const Coverage &get_coverage (void) const
    2098             :   {
    2099           2 :     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
    2100           2 :     return this+input[0];
    2101             :   }
    2102             : 
    2103           0 :   inline bool apply (hb_apply_context_t *c) const
    2104             :   {
    2105           0 :     TRACE_APPLY (this);
    2106           0 :     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
    2107             : 
    2108           0 :     unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint);
    2109           0 :     if (likely (index == NOT_COVERED)) return_trace (false);
    2110             : 
    2111           0 :     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
    2112           0 :     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
    2113             :     struct ChainContextApplyLookupContext lookup_context = {
    2114             :       {match_coverage},
    2115             :       {this, this, this}
    2116           0 :     };
    2117           0 :     return_trace (chain_context_apply_lookup (c,
    2118             :                                               backtrack.len, (const USHORT *) backtrack.array,
    2119             :                                               input.len, (const USHORT *) input.array + 1,
    2120             :                                               lookahead.len, (const USHORT *) lookahead.array,
    2121             :                                               lookup.len, lookup.array, lookup_context));
    2122             :   }
    2123             : 
    2124           2 :   inline bool sanitize (hb_sanitize_context_t *c) const
    2125             :   {
    2126           2 :     TRACE_SANITIZE (this);
    2127           2 :     if (!backtrack.sanitize (c, this)) return_trace (false);
    2128           2 :     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
    2129           2 :     if (!input.sanitize (c, this)) return_trace (false);
    2130           2 :     if (!input.len) return_trace (false); /* To be consistent with Context. */
    2131           2 :     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
    2132           2 :     if (!lookahead.sanitize (c, this)) return_trace (false);
    2133           2 :     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
    2134           2 :     return_trace (lookup.sanitize (c));
    2135             :   }
    2136             : 
    2137             :   protected:
    2138             :   USHORT        format;                 /* Format identifier--format = 3 */
    2139             :   OffsetArrayOf<Coverage>
    2140             :                 backtrack;              /* Array of coverage tables
    2141             :                                          * in backtracking sequence, in  glyph
    2142             :                                          * sequence order */
    2143             :   OffsetArrayOf<Coverage>
    2144             :                 inputX          ;       /* Array of coverage
    2145             :                                          * tables in input sequence, in glyph
    2146             :                                          * sequence order */
    2147             :   OffsetArrayOf<Coverage>
    2148             :                 lookaheadX;             /* Array of coverage tables
    2149             :                                          * in lookahead sequence, in glyph
    2150             :                                          * sequence order */
    2151             :   ArrayOf<LookupRecord>
    2152             :                 lookupX;                /* Array of LookupRecords--in
    2153             :                                          * design order) */
    2154             :   public:
    2155             :   DEFINE_SIZE_MIN (10);
    2156             : };
    2157             : 
    2158             : struct ChainContext
    2159             : {
    2160             :   template <typename context_t>
    2161          49 :   inline typename context_t::return_t dispatch (context_t *c) const
    2162             :   {
    2163          49 :     TRACE_DISPATCH (this, u.format);
    2164          49 :     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
    2165          49 :     switch (u.format) {
    2166           0 :     case 1: return_trace (c->dispatch (u.format1));
    2167          13 :     case 2: return_trace (c->dispatch (u.format2));
    2168          36 :     case 3: return_trace (c->dispatch (u.format3));
    2169           0 :     default:return_trace (c->default_return_value ());
    2170             :     }
    2171             :   }
    2172             : 
    2173             :   protected:
    2174             :   union {
    2175             :   USHORT                format; /* Format identifier */
    2176             :   ChainContextFormat1   format1;
    2177             :   ChainContextFormat2   format2;
    2178             :   ChainContextFormat3   format3;
    2179             :   } u;
    2180             : };
    2181             : 
    2182             : 
    2183             : template <typename T>
    2184             : struct ExtensionFormat1
    2185             : {
    2186           0 :   inline unsigned int get_type (void) const { return extensionLookupType; }
    2187             : 
    2188             :   template <typename X>
    2189           0 :   inline const X& get_subtable (void) const
    2190             :   {
    2191           0 :     unsigned int offset = extensionOffset;
    2192           0 :     if (unlikely (!offset)) return Null(typename T::LookupSubTable);
    2193           0 :     return StructAtOffset<typename T::LookupSubTable> (this, offset);
    2194             :   }
    2195             : 
    2196             :   template <typename context_t>
    2197           0 :   inline typename context_t::return_t dispatch (context_t *c) const
    2198             :   {
    2199           0 :     TRACE_DISPATCH (this, format);
    2200           0 :     if (unlikely (!c->may_dispatch (this, this))) return_trace (c->no_dispatch_return_value ());
    2201           0 :     return_trace (get_subtable<typename T::LookupSubTable> ().dispatch (c, get_type ()));
    2202             :   }
    2203             : 
    2204             :   /* This is called from may_dispatch() above with hb_sanitize_context_t. */
    2205           0 :   inline bool sanitize (hb_sanitize_context_t *c) const
    2206             :   {
    2207           0 :     TRACE_SANITIZE (this);
    2208           0 :     return_trace (c->check_struct (this) && extensionOffset != 0);
    2209             :   }
    2210             : 
    2211             :   protected:
    2212             :   USHORT        format;                 /* Format identifier. Set to 1. */
    2213             :   USHORT        extensionLookupType;    /* Lookup type of subtable referenced
    2214             :                                          * by ExtensionOffset (i.e. the
    2215             :                                          * extension subtable). */
    2216             :   ULONG         extensionOffset;        /* Offset to the extension subtable,
    2217             :                                          * of lookup type subtable. */
    2218             :   public:
    2219             :   DEFINE_SIZE_STATIC (8);
    2220             : };
    2221             : 
    2222             : template <typename T>
    2223             : struct Extension
    2224             : {
    2225           0 :   inline unsigned int get_type (void) const
    2226             :   {
    2227           0 :     switch (u.format) {
    2228           0 :     case 1: return u.format1.get_type ();
    2229           0 :     default:return 0;
    2230             :     }
    2231             :   }
    2232             :   template <typename X>
    2233           0 :   inline const X& get_subtable (void) const
    2234             :   {
    2235           0 :     switch (u.format) {
    2236           0 :     case 1: return u.format1.template get_subtable<typename T::LookupSubTable> ();
    2237           0 :     default:return Null(typename T::LookupSubTable);
    2238             :     }
    2239             :   }
    2240             : 
    2241             :   template <typename context_t>
    2242           0 :   inline typename context_t::return_t dispatch (context_t *c) const
    2243             :   {
    2244           0 :     TRACE_DISPATCH (this, u.format);
    2245           0 :     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
    2246           0 :     switch (u.format) {
    2247           0 :     case 1: return_trace (u.format1.dispatch (c));
    2248           0 :     default:return_trace (c->default_return_value ());
    2249             :     }
    2250             :   }
    2251             : 
    2252             :   protected:
    2253             :   union {
    2254             :   USHORT                format;         /* Format identifier */
    2255             :   ExtensionFormat1<T>     format1;
    2256             :   } u;
    2257             : };
    2258             : 
    2259             : 
    2260             : /*
    2261             :  * GSUB/GPOS Common
    2262             :  */
    2263             : 
    2264             : struct GSUBGPOS
    2265             : {
    2266             :   static const hb_tag_t GSUBTag = HB_OT_TAG_GSUB;
    2267             :   static const hb_tag_t GPOSTag = HB_OT_TAG_GPOS;
    2268             : 
    2269             :   inline unsigned int get_script_count (void) const
    2270             :   { return (this+scriptList).len; }
    2271             :   inline const Tag& get_script_tag (unsigned int i) const
    2272             :   { return (this+scriptList).get_tag (i); }
    2273           4 :   inline unsigned int get_script_tags (unsigned int start_offset,
    2274             :                                        unsigned int *script_count /* IN/OUT */,
    2275             :                                        hb_tag_t     *script_tags /* OUT */) const
    2276           4 :   { return (this+scriptList).get_tags (start_offset, script_count, script_tags); }
    2277         515 :   inline const Script& get_script (unsigned int i) const
    2278         515 :   { return (this+scriptList)[i]; }
    2279           4 :   inline bool find_script_index (hb_tag_t tag, unsigned int *index) const
    2280           4 :   { return (this+scriptList).find_index (tag, index); }
    2281             : 
    2282           0 :   inline unsigned int get_feature_count (void) const
    2283           0 :   { return (this+featureList).len; }
    2284         651 :   inline hb_tag_t get_feature_tag (unsigned int i) const
    2285         651 :   { return i == Index::NOT_FOUND_INDEX ? HB_TAG_NONE : (this+featureList).get_tag (i); }
    2286           0 :   inline unsigned int get_feature_tags (unsigned int start_offset,
    2287             :                                         unsigned int *feature_count /* IN/OUT */,
    2288             :                                         hb_tag_t     *feature_tags /* OUT */) const
    2289           0 :   { return (this+featureList).get_tags (start_offset, feature_count, feature_tags); }
    2290         321 :   inline const Feature& get_feature (unsigned int i) const
    2291         321 :   { return (this+featureList)[i]; }
    2292             :   inline bool find_feature_index (hb_tag_t tag, unsigned int *index) const
    2293             :   { return (this+featureList).find_index (tag, index); }
    2294             : 
    2295          16 :   inline unsigned int get_lookup_count (void) const
    2296          16 :   { return (this+lookupList).len; }
    2297         692 :   inline const Lookup& get_lookup (unsigned int i) const
    2298         692 :   { return (this+lookupList)[i]; }
    2299             : 
    2300           4 :   inline bool find_variations_index (const int *coords, unsigned int num_coords,
    2301             :                                      unsigned int *index) const
    2302           8 :   { return (version.to_int () >= 0x00010001u ? this+featureVars : Null(FeatureVariations))
    2303          12 :            .find_index (coords, num_coords, index); }
    2304         321 :   inline const Feature& get_feature_variation (unsigned int feature_index,
    2305             :                                                unsigned int variations_index) const
    2306             :   {
    2307         321 :     if (FeatureVariations::NOT_FOUND_INDEX != variations_index &&
    2308           0 :         version.to_int () >= 0x00010001u)
    2309             :     {
    2310           0 :       const Feature *feature = (this+featureVars).find_substitute (variations_index,
    2311           0 :                                                                    feature_index);
    2312           0 :       if (feature)
    2313           0 :         return *feature;
    2314             :     }
    2315         321 :     return get_feature (feature_index);
    2316             :   }
    2317             : 
    2318           8 :   inline bool sanitize (hb_sanitize_context_t *c) const
    2319             :   {
    2320           8 :     TRACE_SANITIZE (this);
    2321           8 :     return_trace (version.sanitize (c) &&
    2322             :                   likely (version.major == 1) &&
    2323             :                   scriptList.sanitize (c, this) &&
    2324             :                   featureList.sanitize (c, this) &&
    2325             :                   lookupList.sanitize (c, this) &&
    2326             :                   (version.to_int () < 0x00010001u || featureVars.sanitize (c, this)));
    2327             :   }
    2328             : 
    2329             :   protected:
    2330             :   FixedVersion<>version;  /* Version of the GSUB/GPOS table--initially set
    2331             :                                  * to 0x00010000u */
    2332             :   OffsetTo<ScriptList>
    2333             :                 scriptList;     /* ScriptList table */
    2334             :   OffsetTo<FeatureList>
    2335             :                 featureList;    /* FeatureList table */
    2336             :   OffsetTo<LookupList>
    2337             :                 lookupList;     /* LookupList table */
    2338             :   LOffsetTo<FeatureVariations>
    2339             :                 featureVars;    /* Offset to Feature Variations
    2340             :                                    table--from beginning of table
    2341             :                                  * (may be NULL).  Introduced
    2342             :                                  * in version 0x00010001. */
    2343             :   public:
    2344             :   DEFINE_SIZE_MIN (10);
    2345             : };
    2346             : 
    2347             : 
    2348             : } /* namespace OT */
    2349             : 
    2350             : 
    2351             : #endif /* HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH */

Generated by: LCOV version 1.13