gfx/harfbuzz/src/hb-ot-layout-gsubgpos-private.hh

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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  */
    29 #ifndef HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH
    30 #define HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH
    32 #include "hb-buffer-private.hh"
    33 #include "hb-ot-layout-gdef-table.hh"
    34 #include "hb-set-private.hh"
    37 namespace OT {
    41 #define TRACE_DISPATCH(this) \
    42 	hb_auto_trace_t<context_t::max_debug_depth, typename context_t::return_t> trace \
    43 	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
    44 	 "");
    46 #ifndef HB_DEBUG_CLOSURE
    47 #define HB_DEBUG_CLOSURE (HB_DEBUG+0)
    48 #endif
    50 #define TRACE_CLOSURE(this) \
    51 	hb_auto_trace_t<HB_DEBUG_CLOSURE, hb_void_t> trace \
    52 	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
    53 	 "");
    55 struct hb_closure_context_t
    56 {
    57   inline const char *get_name (void) { return "CLOSURE"; }
    58   static const unsigned int max_debug_depth = HB_DEBUG_CLOSURE;
    59   typedef hb_void_t return_t;
    60   typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
    61   template <typename T>
    62   inline return_t dispatch (const T &obj) { obj.closure (this); return HB_VOID; }
    63   static return_t default_return_value (void) { return HB_VOID; }
    64   bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
    65   return_t recurse (unsigned int lookup_index)
    66   {
    67     if (unlikely (nesting_level_left == 0 || !recurse_func))
    68       return default_return_value ();
    70     nesting_level_left--;
    71     recurse_func (this, lookup_index);
    72     nesting_level_left++;
    73     return HB_VOID;
    74   }
    76   hb_face_t *face;
    77   hb_set_t *glyphs;
    78   recurse_func_t recurse_func;
    79   unsigned int nesting_level_left;
    80   unsigned int debug_depth;
    82   hb_closure_context_t (hb_face_t *face_,
    83 			hb_set_t *glyphs_,
    84 		        unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) :
    85 			  face (face_),
    86 			  glyphs (glyphs_),
    87 			  recurse_func (NULL),
    88 			  nesting_level_left (nesting_level_left_),
    89 			  debug_depth (0) {}
    91   void set_recurse_func (recurse_func_t func) { recurse_func = func; }
    92 };
    96 #ifndef HB_DEBUG_WOULD_APPLY
    97 #define HB_DEBUG_WOULD_APPLY (HB_DEBUG+0)
    98 #endif
   100 #define TRACE_WOULD_APPLY(this) \
   101 	hb_auto_trace_t<HB_DEBUG_WOULD_APPLY, bool> trace \
   102 	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
   103 	 "%d glyphs", c->len);
   105 struct hb_would_apply_context_t
   106 {
   107   inline const char *get_name (void) { return "WOULD_APPLY"; }
   108   static const unsigned int max_debug_depth = HB_DEBUG_WOULD_APPLY;
   109   typedef bool return_t;
   110   template <typename T>
   111   inline return_t dispatch (const T &obj) { return obj.would_apply (this); }
   112   static return_t default_return_value (void) { return false; }
   113   bool stop_sublookup_iteration (return_t r) const { return r; }
   115   hb_face_t *face;
   116   const hb_codepoint_t *glyphs;
   117   unsigned int len;
   118   bool zero_context;
   119   unsigned int debug_depth;
   121   hb_would_apply_context_t (hb_face_t *face_,
   122 			    const hb_codepoint_t *glyphs_,
   123 			    unsigned int len_,
   124 			    bool zero_context_) :
   125 			      face (face_),
   126 			      glyphs (glyphs_),
   127 			      len (len_),
   128 			      zero_context (zero_context_),
   129 			      debug_depth (0) {}
   130 };
   134 #ifndef HB_DEBUG_COLLECT_GLYPHS
   135 #define HB_DEBUG_COLLECT_GLYPHS (HB_DEBUG+0)
   136 #endif
   138 #define TRACE_COLLECT_GLYPHS(this) \
   139 	hb_auto_trace_t<HB_DEBUG_COLLECT_GLYPHS, hb_void_t> trace \
   140 	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
   141 	 "");
   143 struct hb_collect_glyphs_context_t
   144 {
   145   inline const char *get_name (void) { return "COLLECT_GLYPHS"; }
   146   static const unsigned int max_debug_depth = HB_DEBUG_COLLECT_GLYPHS;
   147   typedef hb_void_t return_t;
   148   typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index);
   149   template <typename T>
   150   inline return_t dispatch (const T &obj) { obj.collect_glyphs (this); return HB_VOID; }
   151   static return_t default_return_value (void) { return HB_VOID; }
   152   bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
   153   return_t recurse (unsigned int lookup_index)
   154   {
   155     if (unlikely (nesting_level_left == 0 || !recurse_func))
   156       return default_return_value ();
   158     /* Note that GPOS sets recurse_func to NULL already, so it doesn't get
   159      * past the previous check.  For GSUB, we only want to collect the output
   160      * glyphs in the recursion.  If output is not requested, we can go home now.
   161      *
   162      * Note further, that the above is not exactly correct.  A recursed lookup
   163      * is allowed to match input that is not matched in the context, but that's
   164      * not how most fonts are built.  It's possible to relax that and recurse
   165      * with all sets here if it proves to be an issue.
   166      */
   168     if (output == hb_set_get_empty ())
   169       return HB_VOID;
   171     hb_set_t *old_before = before;
   172     hb_set_t *old_input  = input;
   173     hb_set_t *old_after  = after;
   174     before = input = after = hb_set_get_empty ();
   176     nesting_level_left--;
   177     recurse_func (this, lookup_index);
   178     nesting_level_left++;
   180     before = old_before;
   181     input  = old_input;
   182     after  = old_after;
   184     return HB_VOID;
   185   }
   187   hb_face_t *face;
   188   hb_set_t *before;
   189   hb_set_t *input;
   190   hb_set_t *after;
   191   hb_set_t *output;
   192   recurse_func_t recurse_func;
   193   unsigned int nesting_level_left;
   194   unsigned int debug_depth;
   196   hb_collect_glyphs_context_t (hb_face_t *face_,
   197 			       hb_set_t  *glyphs_before, /* OUT. May be NULL */
   198 			       hb_set_t  *glyphs_input,  /* OUT. May be NULL */
   199 			       hb_set_t  *glyphs_after,  /* OUT. May be NULL */
   200 			       hb_set_t  *glyphs_output, /* OUT. May be NULL */
   201 			       unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) :
   202 			      face (face_),
   203 			      before (glyphs_before ? glyphs_before : hb_set_get_empty ()),
   204 			      input  (glyphs_input  ? glyphs_input  : hb_set_get_empty ()),
   205 			      after  (glyphs_after  ? glyphs_after  : hb_set_get_empty ()),
   206 			      output (glyphs_output ? glyphs_output : hb_set_get_empty ()),
   207 			      recurse_func (NULL),
   208 			      nesting_level_left (nesting_level_left_),
   209 			      debug_depth (0) {}
   211   void set_recurse_func (recurse_func_t func) { recurse_func = func; }
   212 };
   216 struct hb_get_coverage_context_t
   217 {
   218   inline const char *get_name (void) { return "GET_COVERAGE"; }
   219   static const unsigned int max_debug_depth = 0;
   220   typedef const Coverage &return_t;
   221   template <typename T>
   222   inline return_t dispatch (const T &obj) { return obj.get_coverage (); }
   223   static return_t default_return_value (void) { return Null(Coverage); }
   225   hb_get_coverage_context_t (void) :
   226 			    debug_depth (0) {}
   228   unsigned int debug_depth;
   229 };
   233 #ifndef HB_DEBUG_APPLY
   234 #define HB_DEBUG_APPLY (HB_DEBUG+0)
   235 #endif
   237 #define TRACE_APPLY(this) \
   238 	hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace \
   239 	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
   240 	 "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);
   242 struct hb_apply_context_t
   243 {
   244   inline const char *get_name (void) { return "APPLY"; }
   245   static const unsigned int max_debug_depth = HB_DEBUG_APPLY;
   246   typedef bool return_t;
   247   typedef return_t (*recurse_func_t) (hb_apply_context_t *c, unsigned int lookup_index);
   248   template <typename T>
   249   inline return_t dispatch (const T &obj) { return obj.apply (this); }
   250   static return_t default_return_value (void) { return false; }
   251   bool stop_sublookup_iteration (return_t r) const { return r; }
   252   return_t recurse (unsigned int lookup_index)
   253   {
   254     if (unlikely (nesting_level_left == 0 || !recurse_func))
   255       return default_return_value ();
   257     nesting_level_left--;
   258     bool ret = recurse_func (this, lookup_index);
   259     nesting_level_left++;
   260     return ret;
   261   }
   263   unsigned int table_index; /* GSUB/GPOS */
   264   hb_font_t *font;
   265   hb_face_t *face;
   266   hb_buffer_t *buffer;
   267   hb_direction_t direction;
   268   hb_mask_t lookup_mask;
   269   bool auto_zwj;
   270   recurse_func_t recurse_func;
   271   unsigned int nesting_level_left;
   272   unsigned int lookup_props;
   273   const GDEF &gdef;
   274   bool has_glyph_classes;
   275   unsigned int debug_depth;
   278   hb_apply_context_t (unsigned int table_index_,
   279 		      hb_font_t *font_,
   280 		      hb_buffer_t *buffer_) :
   281 			table_index (table_index_),
   282 			font (font_), face (font->face), buffer (buffer_),
   283 			direction (buffer_->props.direction),
   284 			lookup_mask (1),
   285 			auto_zwj (true),
   286 			recurse_func (NULL),
   287 			nesting_level_left (MAX_NESTING_LEVEL),
   288 			lookup_props (0),
   289 			gdef (*hb_ot_layout_from_face (face)->gdef),
   290 			has_glyph_classes (gdef.has_glyph_classes ()),
   291 			debug_depth (0) {}
   293   inline void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; }
   294   inline void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; }
   295   inline void set_recurse_func (recurse_func_t func) { recurse_func = func; }
   296   inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
   297   inline void set_lookup (const Lookup &l) { lookup_props = l.get_props (); }
   299   struct matcher_t
   300   {
   301     inline matcher_t (void) :
   302 	     lookup_props (0),
   303 	     ignore_zwnj (false),
   304 	     ignore_zwj (false),
   305 	     mask (-1),
   306 #define arg1(arg) (arg) /* Remove the macro to see why it's needed! */
   307 	     syllable arg1(0),
   308 #undef arg1
   309 	     match_func (NULL),
   310 	     match_data (NULL) {};
   312     typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data);
   314     inline void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; }
   315     inline void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
   316     inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
   317     inline void set_mask (hb_mask_t mask_) { mask = mask_; }
   318     inline void set_syllable (uint8_t syllable_)  { syllable = syllable_; }
   319     inline void set_match_func (match_func_t match_func_,
   320 				const void *match_data_)
   321     { match_func = match_func_; match_data = match_data_; }
   323     enum may_match_t {
   324       MATCH_NO,
   325       MATCH_YES,
   326       MATCH_MAYBE
   327     };
   329     inline may_match_t may_match (const hb_glyph_info_t &info,
   330 				  const USHORT          *glyph_data) const
   331     {
   332       if (!(info.mask & mask) ||
   333 	  (syllable && syllable != info.syllable ()))
   334 	return MATCH_NO;
   336       if (match_func)
   337         return match_func (info.codepoint, *glyph_data, match_data) ? MATCH_YES : MATCH_NO;
   339       return MATCH_MAYBE;
   340     }
   342     enum may_skip_t {
   343       SKIP_NO,
   344       SKIP_YES,
   345       SKIP_MAYBE
   346     };
   348     inline may_skip_t
   349     may_skip (const hb_apply_context_t *c,
   350 	      const hb_glyph_info_t    &info) const
   351     {
   352       unsigned int property;
   354       property = _hb_glyph_info_get_glyph_props (&info);
   356       if (!c->match_properties (info.codepoint, property, lookup_props))
   357 	return SKIP_YES;
   359       if (unlikely (_hb_glyph_info_is_default_ignorable (&info) &&
   360 		    (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) &&
   361 		    (ignore_zwj || !_hb_glyph_info_is_zwj (&info)) &&
   362 		    !_hb_glyph_info_ligated (&info)))
   363 	return SKIP_MAYBE;
   365       return SKIP_NO;
   366     }
   368     protected:
   369     unsigned int lookup_props;
   370     bool ignore_zwnj;
   371     bool ignore_zwj;
   372     hb_mask_t mask;
   373     uint8_t syllable;
   374     match_func_t match_func;
   375     const void *match_data;
   376   };
   378   struct skipping_forward_iterator_t
   379   {
   380     inline skipping_forward_iterator_t (hb_apply_context_t *c_,
   381 					unsigned int start_index_,
   382 					unsigned int num_items_,
   383 					bool context_match = false) :
   384 					 idx (start_index_),
   385 					 c (c_),
   386 					 match_glyph_data (NULL),
   387 					 num_items (num_items_),
   388 					 end (c->buffer->len)
   389     {
   390       matcher.set_lookup_props (c->lookup_props);
   391       /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
   392       matcher.set_ignore_zwnj (context_match || c->table_index == 1);
   393       /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */
   394       matcher.set_ignore_zwj (context_match || c->table_index == 1 || c->auto_zwj);
   395       if (!context_match)
   396 	matcher.set_mask (c->lookup_mask);
   397       matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
   398     }
   399     inline void set_lookup_props (unsigned int lookup_props) { matcher.set_lookup_props (lookup_props); }
   400     inline void set_syllable (unsigned int syllable) { matcher.set_syllable (syllable); }
   401     inline void set_match_func (matcher_t::match_func_t match_func,
   402 				const void *match_data,
   403 				const USHORT glyph_data[])
   404     {
   405       matcher.set_match_func (match_func, match_data);
   406       match_glyph_data = glyph_data;
   407     }
   409     inline bool has_no_chance (void) const { return unlikely (num_items && idx + num_items >= end); }
   410     inline void reject (void) { num_items++; match_glyph_data--; }
   411     inline bool next (void)
   412     {
   413       assert (num_items > 0);
   414       while (!has_no_chance ())
   415       {
   416 	idx++;
   417 	const hb_glyph_info_t &info = c->buffer->info[idx];
   419 	matcher_t::may_skip_t skip = matcher.may_skip (c, info);
   420 	if (unlikely (skip == matcher_t::SKIP_YES))
   421 	  continue;
   423 	matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
   424 	if (match == matcher_t::MATCH_YES ||
   425 	    (match == matcher_t::MATCH_MAYBE &&
   426 	     skip == matcher_t::SKIP_NO))
   427 	{
   428 	  num_items--;
   429 	  match_glyph_data++;
   430 	  return true;
   431 	}
   433 	if (skip == matcher_t::SKIP_NO)
   434 	  return false;
   435       }
   436       return false;
   437     }
   439     unsigned int idx;
   440     protected:
   441     hb_apply_context_t *c;
   442     matcher_t matcher;
   443     const USHORT *match_glyph_data;
   445     unsigned int num_items;
   446     unsigned int end;
   447   };
   449   struct skipping_backward_iterator_t
   450   {
   451     inline skipping_backward_iterator_t (hb_apply_context_t *c_,
   452 					 unsigned int start_index_,
   453 					 unsigned int num_items_,
   454 					 bool context_match = false) :
   455 					  idx (start_index_),
   456 					  c (c_),
   457 					  match_glyph_data (NULL),
   458 					  num_items (num_items_)
   459     {
   460       matcher.set_lookup_props (c->lookup_props);
   461       /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
   462       matcher.set_ignore_zwnj (context_match || c->table_index == 1);
   463       /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */
   464       matcher.set_ignore_zwj (context_match || c->table_index == 1 || c->auto_zwj);
   465       if (!context_match)
   466 	matcher.set_mask (c->lookup_mask);
   467       matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
   468     }
   469     inline void set_lookup_props (unsigned int lookup_props) { matcher.set_lookup_props (lookup_props); }
   470     inline void set_syllable (unsigned int syllable) { matcher.set_syllable (syllable); }
   471     inline void set_match_func (matcher_t::match_func_t match_func,
   472 				const void *match_data,
   473 				const USHORT glyph_data[])
   474     {
   475       matcher.set_match_func (match_func, match_data);
   476       match_glyph_data = glyph_data;
   477     }
   479     inline bool has_no_chance (void) const { return unlikely (idx < num_items); }
   480     inline void reject (void) { num_items++; }
   481     inline bool prev (void)
   482     {
   483       assert (num_items > 0);
   484       while (!has_no_chance ())
   485       {
   486 	idx--;
   487 	const hb_glyph_info_t &info = c->buffer->out_info[idx];
   489 	matcher_t::may_skip_t skip = matcher.may_skip (c, info);
   491 	if (unlikely (skip == matcher_t::SKIP_YES))
   492 	  continue;
   494 	matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
   495 	if (match == matcher_t::MATCH_YES ||
   496 	    (match == matcher_t::MATCH_MAYBE &&
   497 	     skip == matcher_t::SKIP_NO))
   498 	{
   499 	  num_items--;
   500 	  match_glyph_data++;
   501 	  return true;
   502 	}
   504 	if (skip == matcher_t::SKIP_NO)
   505 	  return false;
   506       }
   507       return false;
   508     }
   510     unsigned int idx;
   511     protected:
   512     hb_apply_context_t *c;
   513     matcher_t matcher;
   514     const USHORT *match_glyph_data;
   516     unsigned int num_items;
   517   };
   519   inline bool
   520   match_properties_mark (hb_codepoint_t  glyph,
   521 			 unsigned int    glyph_props,
   522 			 unsigned int    lookup_props) const
   523   {
   524     /* If using mark filtering sets, the high short of
   525      * lookup_props has the set index.
   526      */
   527     if (lookup_props & LookupFlag::UseMarkFilteringSet)
   528       return gdef.mark_set_covers (lookup_props >> 16, glyph);
   530     /* The second byte of lookup_props has the meaning
   531      * "ignore marks of attachment type different than
   532      * the attachment type specified."
   533      */
   534     if (lookup_props & LookupFlag::MarkAttachmentType)
   535       return (lookup_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);
   537     return true;
   538   }
   540   inline bool
   541   match_properties (hb_codepoint_t  glyph,
   542 		    unsigned int    glyph_props,
   543 		    unsigned int    lookup_props) const
   544   {
   545     /* Not covered, if, for example, glyph class is ligature and
   546      * lookup_props includes LookupFlags::IgnoreLigatures
   547      */
   548     if (glyph_props & lookup_props & LookupFlag::IgnoreFlags)
   549       return false;
   551     if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK))
   552       return match_properties_mark (glyph, glyph_props, lookup_props);
   554     return true;
   555   }
   557   inline bool
   558   check_glyph_property (hb_glyph_info_t *info,
   559 			unsigned int  lookup_props) const
   560   {
   561     unsigned int property;
   563     property = _hb_glyph_info_get_glyph_props (info);
   565     return match_properties (info->codepoint, property, lookup_props);
   566   }
   568   inline void _set_glyph_props (hb_codepoint_t glyph_index,
   569 			  unsigned int class_guess = 0,
   570 			  bool ligature = false) const
   571   {
   572     unsigned int add_in = _hb_glyph_info_get_glyph_props (&buffer->cur()) &
   573 			  HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE;
   574     add_in |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED;
   575     if (ligature)
   576       add_in |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED;
   577     if (likely (has_glyph_classes))
   578       _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | gdef.get_glyph_props (glyph_index));
   579     else if (class_guess)
   580       _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | class_guess);
   581   }
   583   inline void replace_glyph (hb_codepoint_t glyph_index) const
   584   {
   585     _set_glyph_props (glyph_index);
   586     buffer->replace_glyph (glyph_index);
   587   }
   588   inline void replace_glyph_inplace (hb_codepoint_t glyph_index) const
   589   {
   590     _set_glyph_props (glyph_index);
   591     buffer->cur().codepoint = glyph_index;
   592   }
   593   inline void replace_glyph_with_ligature (hb_codepoint_t glyph_index,
   594 					   unsigned int class_guess) const
   595   {
   596     _set_glyph_props (glyph_index, class_guess, true);
   597     buffer->replace_glyph (glyph_index);
   598   }
   599   inline void output_glyph (hb_codepoint_t glyph_index,
   600 			    unsigned int class_guess) const
   601   {
   602     _set_glyph_props (glyph_index, class_guess);
   603     buffer->output_glyph (glyph_index);
   604   }
   605 };
   609 typedef bool (*intersects_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data);
   610 typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data);
   611 typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data);
   613 struct ContextClosureFuncs
   614 {
   615   intersects_func_t intersects;
   616 };
   617 struct ContextCollectGlyphsFuncs
   618 {
   619   collect_glyphs_func_t collect;
   620 };
   621 struct ContextApplyFuncs
   622 {
   623   match_func_t match;
   624 };
   627 static inline bool intersects_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED)
   628 {
   629   return glyphs->has (value);
   630 }
   631 static inline bool intersects_class (hb_set_t *glyphs, const USHORT &value, const void *data)
   632 {
   633   const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
   634   return class_def.intersects_class (glyphs, value);
   635 }
   636 static inline bool intersects_coverage (hb_set_t *glyphs, const USHORT &value, const void *data)
   637 {
   638   const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
   639   return (data+coverage).intersects (glyphs);
   640 }
   642 static inline bool intersects_array (hb_closure_context_t *c,
   643 				     unsigned int count,
   644 				     const USHORT values[],
   645 				     intersects_func_t intersects_func,
   646 				     const void *intersects_data)
   647 {
   648   for (unsigned int i = 0; i < count; i++)
   649     if (likely (!intersects_func (c->glyphs, values[i], intersects_data)))
   650       return false;
   651   return true;
   652 }
   655 static inline void collect_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED)
   656 {
   657   glyphs->add (value);
   658 }
   659 static inline void collect_class (hb_set_t *glyphs, const USHORT &value, const void *data)
   660 {
   661   const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
   662   class_def.add_class (glyphs, value);
   663 }
   664 static inline void collect_coverage (hb_set_t *glyphs, const USHORT &value, const void *data)
   665 {
   666   const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
   667   (data+coverage).add_coverage (glyphs);
   668 }
   669 static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
   670 				  hb_set_t *glyphs,
   671 				  unsigned int count,
   672 				  const USHORT values[],
   673 				  collect_glyphs_func_t collect_func,
   674 				  const void *collect_data)
   675 {
   676   for (unsigned int i = 0; i < count; i++)
   677     collect_func (glyphs, values[i], collect_data);
   678 }
   681 static inline bool match_glyph (hb_codepoint_t glyph_id, const USHORT &value, const void *data HB_UNUSED)
   682 {
   683   return glyph_id == value;
   684 }
   685 static inline bool match_class (hb_codepoint_t glyph_id, const USHORT &value, const void *data)
   686 {
   687   const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
   688   return class_def.get_class (glyph_id) == value;
   689 }
   690 static inline bool match_coverage (hb_codepoint_t glyph_id, const USHORT &value, const void *data)
   691 {
   692   const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
   693   return (data+coverage).get_coverage (glyph_id) != NOT_COVERED;
   694 }
   696 static inline bool would_match_input (hb_would_apply_context_t *c,
   697 				      unsigned int count, /* Including the first glyph (not matched) */
   698 				      const USHORT input[], /* Array of input values--start with second glyph */
   699 				      match_func_t match_func,
   700 				      const void *match_data)
   701 {
   702   if (count != c->len)
   703     return false;
   705   for (unsigned int i = 1; i < count; i++)
   706     if (likely (!match_func (c->glyphs[i], input[i - 1], match_data)))
   707       return false;
   709   return true;
   710 }
   711 static inline bool match_input (hb_apply_context_t *c,
   712 				unsigned int count, /* Including the first glyph (not matched) */
   713 				const USHORT input[], /* Array of input values--start with second glyph */
   714 				match_func_t match_func,
   715 				const void *match_data,
   716 				unsigned int *end_offset,
   717 				unsigned int match_positions[MAX_CONTEXT_LENGTH],
   718 				bool *p_is_mark_ligature = NULL,
   719 				unsigned int *p_total_component_count = NULL)
   720 {
   721   TRACE_APPLY (NULL);
   723   if (unlikely (count > MAX_CONTEXT_LENGTH)) TRACE_RETURN (false);
   725   hb_buffer_t *buffer = c->buffer;
   727   hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, buffer->idx, count - 1);
   728   skippy_iter.set_match_func (match_func, match_data, input);
   729   if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
   731   /*
   732    * This is perhaps the trickiest part of OpenType...  Remarks:
   733    *
   734    * - If all components of the ligature were marks, we call this a mark ligature.
   735    *
   736    * - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize
   737    *   it as a ligature glyph.
   738    *
   739    * - Ligatures cannot be formed across glyphs attached to different components
   740    *   of previous ligatures.  Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and
   741    *   LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother.
   742    *   However, it would be wrong to ligate that SHADDA,FATHA sequence.o
   743    *   There is an exception to this: If a ligature tries ligating with marks that
   744    *   belong to it itself, go ahead, assuming that the font designer knows what
   745    *   they are doing (otherwise it can break Indic stuff when a matra wants to
   746    *   ligate with a conjunct...)
   747    */
   749   bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->cur());
   751   unsigned int total_component_count = 0;
   752   total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur());
   754   unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
   755   unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
   757   match_positions[0] = buffer->idx;
   758   for (unsigned int i = 1; i < count; i++)
   759   {
   760     if (!skippy_iter.next ()) return TRACE_RETURN (false);
   762     match_positions[i] = skippy_iter.idx;
   764     unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]);
   765     unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]);
   767     if (first_lig_id && first_lig_comp) {
   768       /* If first component was attached to a previous ligature component,
   769        * all subsequent components should be attached to the same ligature
   770        * component, otherwise we shouldn't ligate them. */
   771       if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
   772 	return TRACE_RETURN (false);
   773     } else {
   774       /* If first component was NOT attached to a previous ligature component,
   775        * all subsequent components should also NOT be attached to any ligature
   776        * component, unless they are attached to the first component itself! */
   777       if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id))
   778 	return TRACE_RETURN (false);
   779     }
   781     is_mark_ligature = is_mark_ligature && _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx]);
   782     total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]);
   783   }
   785   *end_offset = skippy_iter.idx - buffer->idx + 1;
   787   if (p_is_mark_ligature)
   788     *p_is_mark_ligature = is_mark_ligature;
   790   if (p_total_component_count)
   791     *p_total_component_count = total_component_count;
   793   return TRACE_RETURN (true);
   794 }
   795 static inline void ligate_input (hb_apply_context_t *c,
   796 				 unsigned int count, /* Including the first glyph */
   797 				 unsigned int match_positions[MAX_CONTEXT_LENGTH], /* Including the first glyph */
   798 				 unsigned int match_length,
   799 				 hb_codepoint_t lig_glyph,
   800 				 bool is_mark_ligature,
   801 				 unsigned int total_component_count)
   802 {
   803   TRACE_APPLY (NULL);
   805   hb_buffer_t *buffer = c->buffer;
   807   buffer->merge_clusters (buffer->idx, buffer->idx + match_length);
   809   /*
   810    * - If it *is* a mark ligature, we don't allocate a new ligature id, and leave
   811    *   the ligature to keep its old ligature id.  This will allow it to attach to
   812    *   a base ligature in GPOS.  Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH,
   813    *   and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA wit a
   814    *   ligature id and component value of 2.  Then if SHADDA,FATHA form a ligature
   815    *   later, we don't want them to lose their ligature id/component, otherwise
   816    *   GPOS will fail to correctly position the mark ligature on top of the
   817    *   LAM,LAM,HEH ligature.  See:
   818    *     https://bugzilla.gnome.org/show_bug.cgi?id=676343
   819    *
   820    * - If a ligature is formed of components that some of which are also ligatures
   821    *   themselves, and those ligature components had marks attached to *their*
   822    *   components, we have to attach the marks to the new ligature component
   823    *   positions!  Now *that*'s tricky!  And these marks may be following the
   824    *   last component of the whole sequence, so we should loop forward looking
   825    *   for them and update them.
   826    *
   827    *   Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a
   828    *   'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature
   829    *   id and component == 1.  Now, during 'liga', the LAM and the LAM-HEH ligature
   830    *   form a LAM-LAM-HEH ligature.  We need to reassign the SHADDA and FATHA to
   831    *   the new ligature with a component value of 2.
   832    *
   833    *   This in fact happened to a font...  See:
   834    *   https://bugzilla.gnome.org/show_bug.cgi?id=437633
   835    */
   837   unsigned int klass = is_mark_ligature ? 0 : HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
   838   unsigned int lig_id = is_mark_ligature ? 0 : _hb_allocate_lig_id (buffer);
   839   unsigned int last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
   840   unsigned int last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
   841   unsigned int components_so_far = last_num_components;
   843   if (!is_mark_ligature)
   844   {
   845     _hb_glyph_info_set_lig_props_for_ligature (&buffer->cur(), lig_id, total_component_count);
   846     if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
   847     {
   848       _hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER);
   849       _hb_glyph_info_set_modified_combining_class (&buffer->cur(), 0);
   850     }
   851   }
   852   c->replace_glyph_with_ligature (lig_glyph, klass);
   854   for (unsigned int i = 1; i < count; i++)
   855   {
   856     while (buffer->idx < match_positions[i])
   857     {
   858       if (!is_mark_ligature) {
   859 	unsigned int new_lig_comp = components_so_far - last_num_components +
   860 				    MIN (MAX (_hb_glyph_info_get_lig_comp (&buffer->cur()), 1u), last_num_components);
   861 	_hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
   862       }
   863       buffer->next_glyph ();
   864     }
   866     last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
   867     last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
   868     components_so_far += last_num_components;
   870     /* Skip the base glyph */
   871     buffer->idx++;
   872   }
   874   if (!is_mark_ligature && last_lig_id) {
   875     /* Re-adjust components for any marks following. */
   876     for (unsigned int i = buffer->idx; i < buffer->len; i++) {
   877       if (last_lig_id == _hb_glyph_info_get_lig_id (&buffer->info[i])) {
   878 	unsigned int new_lig_comp = components_so_far - last_num_components +
   879 				    MIN (MAX (_hb_glyph_info_get_lig_comp (&buffer->info[i]), 1u), last_num_components);
   880 	_hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
   881       } else
   882 	break;
   883     }
   884   }
   885 }
   887 static inline bool match_backtrack (hb_apply_context_t *c,
   888 				    unsigned int count,
   889 				    const USHORT backtrack[],
   890 				    match_func_t match_func,
   891 				    const void *match_data)
   892 {
   893   TRACE_APPLY (NULL);
   895   hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, c->buffer->backtrack_len (), count, true);
   896   skippy_iter.set_match_func (match_func, match_data, backtrack);
   897   if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
   899   for (unsigned int i = 0; i < count; i++)
   900     if (!skippy_iter.prev ())
   901       return TRACE_RETURN (false);
   903   return TRACE_RETURN (true);
   904 }
   906 static inline bool match_lookahead (hb_apply_context_t *c,
   907 				    unsigned int count,
   908 				    const USHORT lookahead[],
   909 				    match_func_t match_func,
   910 				    const void *match_data,
   911 				    unsigned int offset)
   912 {
   913   TRACE_APPLY (NULL);
   915   hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx + offset - 1, count, true);
   916   skippy_iter.set_match_func (match_func, match_data, lookahead);
   917   if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
   919   for (unsigned int i = 0; i < count; i++)
   920     if (!skippy_iter.next ())
   921       return TRACE_RETURN (false);
   923   return TRACE_RETURN (true);
   924 }
   928 struct LookupRecord
   929 {
   930   inline bool sanitize (hb_sanitize_context_t *c) {
   931     TRACE_SANITIZE (this);
   932     return TRACE_RETURN (c->check_struct (this));
   933   }
   935   USHORT	sequenceIndex;		/* Index into current glyph
   936 					 * sequence--first glyph = 0 */
   937   USHORT	lookupListIndex;	/* Lookup to apply to that
   938 					 * position--zero--based */
   939   public:
   940   DEFINE_SIZE_STATIC (4);
   941 };
   944 template <typename context_t>
   945 static inline void recurse_lookups (context_t *c,
   946 				    unsigned int lookupCount,
   947 				    const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
   948 {
   949   for (unsigned int i = 0; i < lookupCount; i++)
   950     c->recurse (lookupRecord[i].lookupListIndex);
   951 }
   953 static inline bool apply_lookup (hb_apply_context_t *c,
   954 				 unsigned int count, /* Including the first glyph */
   955 				 unsigned int match_positions[MAX_CONTEXT_LENGTH], /* Including the first glyph */
   956 				 unsigned int lookupCount,
   957 				 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
   958 				 unsigned int match_length)
   959 {
   960   TRACE_APPLY (NULL);
   962   hb_buffer_t *buffer = c->buffer;
   963   unsigned int end;
   965   /* All positions are distance from beginning of *output* buffer.
   966    * Adjust. */
   967   {
   968     unsigned int bl = buffer->backtrack_len ();
   969     end = bl + match_length;
   971     int delta = bl - buffer->idx;
   972     /* Convert positions to new indexing. */
   973     for (unsigned int j = 0; j < count; j++)
   974       match_positions[j] += delta;
   975   }
   977   for (unsigned int i = 0; i < lookupCount; i++)
   978   {
   979     unsigned int idx = lookupRecord[i].sequenceIndex;
   980     if (idx >= count)
   981       continue;
   983     buffer->move_to (match_positions[idx]);
   985     unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
   986     if (!c->recurse (lookupRecord[i].lookupListIndex))
   987       continue;
   989     unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len ();
   990     int delta = new_len - orig_len;
   992     if (!delta)
   993         continue;
   995     /* Recursed lookup changed buffer len.  Adjust. */
   997     /* end can't go back past the current match position. */
   998     end = MAX ((int) match_positions[idx] + 1, int (end) + delta);
  1000     unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */
  1002     if (delta > 0)
  1004       if (unlikely (delta + count > MAX_CONTEXT_LENGTH))
  1005 	break;
  1007     else
  1009       /* NOTE: delta is negative. */
  1010       delta = MAX (delta, (int) next - (int) count);
  1011       next -= delta;
  1014     /* Shift! */
  1015     memmove (match_positions + next + delta, match_positions + next,
  1016 	     (count - next) * sizeof (match_positions[0]));
  1017     next += delta;
  1018     count += delta;
  1020     /* Fill in new entries. */
  1021     for (unsigned int j = idx + 1; j < next; j++)
  1022       match_positions[j] = match_positions[j - 1] + 1;
  1024     /* And fixup the rest. */
  1025     for (; next < count; next++)
  1026       match_positions[next] += delta;
  1029   buffer->move_to (end);
  1031   return TRACE_RETURN (true);
  1036 /* Contextual lookups */
  1038 struct ContextClosureLookupContext
  1040   ContextClosureFuncs funcs;
  1041   const void *intersects_data;
  1042 };
  1044 struct ContextCollectGlyphsLookupContext
  1046   ContextCollectGlyphsFuncs funcs;
  1047   const void *collect_data;
  1048 };
  1050 struct ContextApplyLookupContext
  1052   ContextApplyFuncs funcs;
  1053   const void *match_data;
  1054 };
  1056 static inline void context_closure_lookup (hb_closure_context_t *c,
  1057 					   unsigned int inputCount, /* Including the first glyph (not matched) */
  1058 					   const USHORT input[], /* Array of input values--start with second glyph */
  1059 					   unsigned int lookupCount,
  1060 					   const LookupRecord lookupRecord[],
  1061 					   ContextClosureLookupContext &lookup_context)
  1063   if (intersects_array (c,
  1064 			inputCount ? inputCount - 1 : 0, input,
  1065 			lookup_context.funcs.intersects, lookup_context.intersects_data))
  1066     recurse_lookups (c,
  1067 		     lookupCount, lookupRecord);
  1070 static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
  1071 						  unsigned int inputCount, /* Including the first glyph (not matched) */
  1072 						  const USHORT input[], /* Array of input values--start with second glyph */
  1073 						  unsigned int lookupCount,
  1074 						  const LookupRecord lookupRecord[],
  1075 						  ContextCollectGlyphsLookupContext &lookup_context)
  1077   collect_array (c, c->input,
  1078 		 inputCount ? inputCount - 1 : 0, input,
  1079 		 lookup_context.funcs.collect, lookup_context.collect_data);
  1080   recurse_lookups (c,
  1081 		   lookupCount, lookupRecord);
  1084 static inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
  1085 					       unsigned int inputCount, /* Including the first glyph (not matched) */
  1086 					       const USHORT input[], /* Array of input values--start with second glyph */
  1087 					       unsigned int lookupCount HB_UNUSED,
  1088 					       const LookupRecord lookupRecord[] HB_UNUSED,
  1089 					       ContextApplyLookupContext &lookup_context)
  1091   return would_match_input (c,
  1092 			    inputCount, input,
  1093 			    lookup_context.funcs.match, lookup_context.match_data);
  1095 static inline bool context_apply_lookup (hb_apply_context_t *c,
  1096 					 unsigned int inputCount, /* Including the first glyph (not matched) */
  1097 					 const USHORT input[], /* Array of input values--start with second glyph */
  1098 					 unsigned int lookupCount,
  1099 					 const LookupRecord lookupRecord[],
  1100 					 ContextApplyLookupContext &lookup_context)
  1102   unsigned int match_length = 0;
  1103   unsigned int match_positions[MAX_CONTEXT_LENGTH];
  1104   return match_input (c,
  1105 		      inputCount, input,
  1106 		      lookup_context.funcs.match, lookup_context.match_data,
  1107 		      &match_length, match_positions)
  1108       && apply_lookup (c,
  1109 		       inputCount, match_positions,
  1110 		       lookupCount, lookupRecord,
  1111 		       match_length);
  1114 struct Rule
  1116   inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
  1118     TRACE_CLOSURE (this);
  1119     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
  1120     context_closure_lookup (c,
  1121 			    inputCount, input,
  1122 			    lookupCount, lookupRecord,
  1123 			    lookup_context);
  1126   inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const
  1128     TRACE_COLLECT_GLYPHS (this);
  1129     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
  1130     context_collect_glyphs_lookup (c,
  1131 				   inputCount, input,
  1132 				   lookupCount, lookupRecord,
  1133 				   lookup_context);
  1136   inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
  1138     TRACE_WOULD_APPLY (this);
  1139     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
  1140     return TRACE_RETURN (context_would_apply_lookup (c, inputCount, input, lookupCount, lookupRecord, lookup_context));
  1143   inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
  1145     TRACE_APPLY (this);
  1146     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
  1147     return TRACE_RETURN (context_apply_lookup (c, inputCount, input, lookupCount, lookupRecord, lookup_context));
  1150   public:
  1151   inline bool sanitize (hb_sanitize_context_t *c) {
  1152     TRACE_SANITIZE (this);
  1153     return inputCount.sanitize (c)
  1154 	&& lookupCount.sanitize (c)
  1155 	&& c->check_range (input,
  1156 			   input[0].static_size * inputCount
  1157 			   + lookupRecordX[0].static_size * lookupCount);
  1160   protected:
  1161   USHORT	inputCount;		/* Total number of glyphs in input
  1162 					 * glyph sequence--includes the first
  1163 					 * glyph */
  1164   USHORT	lookupCount;		/* Number of LookupRecords */
  1165   USHORT	input[VAR];		/* Array of match inputs--start with
  1166 					 * second glyph */
  1167   LookupRecord	lookupRecordX[VAR];	/* Array of LookupRecords--in
  1168 					 * design order */
  1169   public:
  1170   DEFINE_SIZE_ARRAY2 (4, input, lookupRecordX);
  1171 };
  1173 struct RuleSet
  1175   inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
  1177     TRACE_CLOSURE (this);
  1178     unsigned int num_rules = rule.len;
  1179     for (unsigned int i = 0; i < num_rules; i++)
  1180       (this+rule[i]).closure (c, lookup_context);
  1183   inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const
  1185     TRACE_COLLECT_GLYPHS (this);
  1186     unsigned int num_rules = rule.len;
  1187     for (unsigned int i = 0; i < num_rules; i++)
  1188       (this+rule[i]).collect_glyphs (c, lookup_context);
  1191   inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
  1193     TRACE_WOULD_APPLY (this);
  1194     unsigned int num_rules = rule.len;
  1195     for (unsigned int i = 0; i < num_rules; i++)
  1197       if ((this+rule[i]).would_apply (c, lookup_context))
  1198         return TRACE_RETURN (true);
  1200     return TRACE_RETURN (false);
  1203   inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
  1205     TRACE_APPLY (this);
  1206     unsigned int num_rules = rule.len;
  1207     for (unsigned int i = 0; i < num_rules; i++)
  1209       if ((this+rule[i]).apply (c, lookup_context))
  1210         return TRACE_RETURN (true);
  1212     return TRACE_RETURN (false);
  1215   inline bool sanitize (hb_sanitize_context_t *c) {
  1216     TRACE_SANITIZE (this);
  1217     return TRACE_RETURN (rule.sanitize (c, this));
  1220   protected:
  1221   OffsetArrayOf<Rule>
  1222 		rule;			/* Array of Rule tables
  1223 					 * ordered by preference */
  1224   public:
  1225   DEFINE_SIZE_ARRAY (2, rule);
  1226 };
  1229 struct ContextFormat1
  1231   inline void closure (hb_closure_context_t *c) const
  1233     TRACE_CLOSURE (this);
  1235     const Coverage &cov = (this+coverage);
  1237     struct ContextClosureLookupContext lookup_context = {
  1238       {intersects_glyph},
  1239       NULL
  1240     };
  1242     unsigned int count = ruleSet.len;
  1243     for (unsigned int i = 0; i < count; i++)
  1244       if (cov.intersects_coverage (c->glyphs, i)) {
  1245 	const RuleSet &rule_set = this+ruleSet[i];
  1246 	rule_set.closure (c, lookup_context);
  1250   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  1252     TRACE_COLLECT_GLYPHS (this);
  1253     (this+coverage).add_coverage (c->input);
  1255     struct ContextCollectGlyphsLookupContext lookup_context = {
  1256       {collect_glyph},
  1257       NULL
  1258     };
  1260     unsigned int count = ruleSet.len;
  1261     for (unsigned int i = 0; i < count; i++)
  1262       (this+ruleSet[i]).collect_glyphs (c, lookup_context);
  1265   inline bool would_apply (hb_would_apply_context_t *c) const
  1267     TRACE_WOULD_APPLY (this);
  1269     const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
  1270     struct ContextApplyLookupContext lookup_context = {
  1271       {match_glyph},
  1272       NULL
  1273     };
  1274     return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
  1277   inline const Coverage &get_coverage (void) const
  1279     return this+coverage;
  1282   inline bool apply (hb_apply_context_t *c) const
  1284     TRACE_APPLY (this);
  1285     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
  1286     if (likely (index == NOT_COVERED))
  1287       return TRACE_RETURN (false);
  1289     const RuleSet &rule_set = this+ruleSet[index];
  1290     struct ContextApplyLookupContext lookup_context = {
  1291       {match_glyph},
  1292       NULL
  1293     };
  1294     return TRACE_RETURN (rule_set.apply (c, lookup_context));
  1297   inline bool sanitize (hb_sanitize_context_t *c) {
  1298     TRACE_SANITIZE (this);
  1299     return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
  1302   protected:
  1303   USHORT	format;			/* Format identifier--format = 1 */
  1304   OffsetTo<Coverage>
  1305 		coverage;		/* Offset to Coverage table--from
  1306 					 * beginning of table */
  1307   OffsetArrayOf<RuleSet>
  1308 		ruleSet;		/* Array of RuleSet tables
  1309 					 * ordered by Coverage Index */
  1310   public:
  1311   DEFINE_SIZE_ARRAY (6, ruleSet);
  1312 };
  1315 struct ContextFormat2
  1317   inline void closure (hb_closure_context_t *c) const
  1319     TRACE_CLOSURE (this);
  1320     if (!(this+coverage).intersects (c->glyphs))
  1321       return;
  1323     const ClassDef &class_def = this+classDef;
  1325     struct ContextClosureLookupContext lookup_context = {
  1326       {intersects_class},
  1327       &class_def
  1328     };
  1330     unsigned int count = ruleSet.len;
  1331     for (unsigned int i = 0; i < count; i++)
  1332       if (class_def.intersects_class (c->glyphs, i)) {
  1333 	const RuleSet &rule_set = this+ruleSet[i];
  1334 	rule_set.closure (c, lookup_context);
  1338   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  1340     TRACE_COLLECT_GLYPHS (this);
  1341     (this+coverage).add_coverage (c->input);
  1343     const ClassDef &class_def = this+classDef;
  1344     struct ContextCollectGlyphsLookupContext lookup_context = {
  1345       {collect_class},
  1346       &class_def
  1347     };
  1349     unsigned int count = ruleSet.len;
  1350     for (unsigned int i = 0; i < count; i++)
  1351       (this+ruleSet[i]).collect_glyphs (c, lookup_context);
  1354   inline bool would_apply (hb_would_apply_context_t *c) const
  1356     TRACE_WOULD_APPLY (this);
  1358     const ClassDef &class_def = this+classDef;
  1359     unsigned int index = class_def.get_class (c->glyphs[0]);
  1360     const RuleSet &rule_set = this+ruleSet[index];
  1361     struct ContextApplyLookupContext lookup_context = {
  1362       {match_class},
  1363       &class_def
  1364     };
  1365     return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
  1368   inline const Coverage &get_coverage (void) const
  1370     return this+coverage;
  1373   inline bool apply (hb_apply_context_t *c) const
  1375     TRACE_APPLY (this);
  1376     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
  1377     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
  1379     const ClassDef &class_def = this+classDef;
  1380     index = class_def.get_class (c->buffer->cur().codepoint);
  1381     const RuleSet &rule_set = this+ruleSet[index];
  1382     struct ContextApplyLookupContext lookup_context = {
  1383       {match_class},
  1384       &class_def
  1385     };
  1386     return TRACE_RETURN (rule_set.apply (c, lookup_context));
  1389   inline bool sanitize (hb_sanitize_context_t *c) {
  1390     TRACE_SANITIZE (this);
  1391     return TRACE_RETURN (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
  1394   protected:
  1395   USHORT	format;			/* Format identifier--format = 2 */
  1396   OffsetTo<Coverage>
  1397 		coverage;		/* Offset to Coverage table--from
  1398 					 * beginning of table */
  1399   OffsetTo<ClassDef>
  1400 		classDef;		/* Offset to glyph ClassDef table--from
  1401 					 * beginning of table */
  1402   OffsetArrayOf<RuleSet>
  1403 		ruleSet;		/* Array of RuleSet tables
  1404 					 * ordered by class */
  1405   public:
  1406   DEFINE_SIZE_ARRAY (8, ruleSet);
  1407 };
  1410 struct ContextFormat3
  1412   inline void closure (hb_closure_context_t *c) const
  1414     TRACE_CLOSURE (this);
  1415     if (!(this+coverage[0]).intersects (c->glyphs))
  1416       return;
  1418     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
  1419     struct ContextClosureLookupContext lookup_context = {
  1420       {intersects_coverage},
  1421       this
  1422     };
  1423     context_closure_lookup (c,
  1424 			    glyphCount, (const USHORT *) (coverage + 1),
  1425 			    lookupCount, lookupRecord,
  1426 			    lookup_context);
  1429   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  1431     TRACE_COLLECT_GLYPHS (this);
  1432     (this+coverage[0]).add_coverage (c->input);
  1434     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
  1435     struct ContextCollectGlyphsLookupContext lookup_context = {
  1436       {collect_coverage},
  1437       this
  1438     };
  1440     context_collect_glyphs_lookup (c,
  1441 				   glyphCount, (const USHORT *) (coverage + 1),
  1442 				   lookupCount, lookupRecord,
  1443 				   lookup_context);
  1446   inline bool would_apply (hb_would_apply_context_t *c) const
  1448     TRACE_WOULD_APPLY (this);
  1450     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
  1451     struct ContextApplyLookupContext lookup_context = {
  1452       {match_coverage},
  1453       this
  1454     };
  1455     return TRACE_RETURN (context_would_apply_lookup (c, glyphCount, (const USHORT *) (coverage + 1), lookupCount, lookupRecord, lookup_context));
  1458   inline const Coverage &get_coverage (void) const
  1460     return this+coverage[0];
  1463   inline bool apply (hb_apply_context_t *c) const
  1465     TRACE_APPLY (this);
  1466     unsigned int index = (this+coverage[0]).get_coverage (c->buffer->cur().codepoint);
  1467     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
  1469     const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
  1470     struct ContextApplyLookupContext lookup_context = {
  1471       {match_coverage},
  1472       this
  1473     };
  1474     return TRACE_RETURN (context_apply_lookup (c, glyphCount, (const USHORT *) (coverage + 1), lookupCount, lookupRecord, lookup_context));
  1477   inline bool sanitize (hb_sanitize_context_t *c) {
  1478     TRACE_SANITIZE (this);
  1479     if (!c->check_struct (this)) return TRACE_RETURN (false);
  1480     unsigned int count = glyphCount;
  1481     if (!c->check_array (coverage, coverage[0].static_size, count)) return TRACE_RETURN (false);
  1482     for (unsigned int i = 0; i < count; i++)
  1483       if (!coverage[i].sanitize (c, this)) return TRACE_RETURN (false);
  1484     LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * count);
  1485     return TRACE_RETURN (c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount));
  1488   protected:
  1489   USHORT	format;			/* Format identifier--format = 3 */
  1490   USHORT	glyphCount;		/* Number of glyphs in the input glyph
  1491 					 * sequence */
  1492   USHORT	lookupCount;		/* Number of LookupRecords */
  1493   OffsetTo<Coverage>
  1494 		coverage[VAR];		/* Array of offsets to Coverage
  1495 					 * table in glyph sequence order */
  1496   LookupRecord	lookupRecordX[VAR];	/* Array of LookupRecords--in
  1497 					 * design order */
  1498   public:
  1499   DEFINE_SIZE_ARRAY2 (6, coverage, lookupRecordX);
  1500 };
  1502 struct Context
  1504   template <typename context_t>
  1505   inline typename context_t::return_t dispatch (context_t *c) const
  1507     TRACE_DISPATCH (this);
  1508     switch (u.format) {
  1509     case 1: return TRACE_RETURN (c->dispatch (u.format1));
  1510     case 2: return TRACE_RETURN (c->dispatch (u.format2));
  1511     case 3: return TRACE_RETURN (c->dispatch (u.format3));
  1512     default:return TRACE_RETURN (c->default_return_value ());
  1516   inline bool sanitize (hb_sanitize_context_t *c) {
  1517     TRACE_SANITIZE (this);
  1518     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
  1519     switch (u.format) {
  1520     case 1: return TRACE_RETURN (u.format1.sanitize (c));
  1521     case 2: return TRACE_RETURN (u.format2.sanitize (c));
  1522     case 3: return TRACE_RETURN (u.format3.sanitize (c));
  1523     default:return TRACE_RETURN (true);
  1527   protected:
  1528   union {
  1529   USHORT		format;		/* Format identifier */
  1530   ContextFormat1	format1;
  1531   ContextFormat2	format2;
  1532   ContextFormat3	format3;
  1533   } u;
  1534 };
  1537 /* Chaining Contextual lookups */
  1539 struct ChainContextClosureLookupContext
  1541   ContextClosureFuncs funcs;
  1542   const void *intersects_data[3];
  1543 };
  1545 struct ChainContextCollectGlyphsLookupContext
  1547   ContextCollectGlyphsFuncs funcs;
  1548   const void *collect_data[3];
  1549 };
  1551 struct ChainContextApplyLookupContext
  1553   ContextApplyFuncs funcs;
  1554   const void *match_data[3];
  1555 };
  1557 static inline void chain_context_closure_lookup (hb_closure_context_t *c,
  1558 						 unsigned int backtrackCount,
  1559 						 const USHORT backtrack[],
  1560 						 unsigned int inputCount, /* Including the first glyph (not matched) */
  1561 						 const USHORT input[], /* Array of input values--start with second glyph */
  1562 						 unsigned int lookaheadCount,
  1563 						 const USHORT lookahead[],
  1564 						 unsigned int lookupCount,
  1565 						 const LookupRecord lookupRecord[],
  1566 						 ChainContextClosureLookupContext &lookup_context)
  1568   if (intersects_array (c,
  1569 			backtrackCount, backtrack,
  1570 			lookup_context.funcs.intersects, lookup_context.intersects_data[0])
  1571    && intersects_array (c,
  1572 			inputCount ? inputCount - 1 : 0, input,
  1573 			lookup_context.funcs.intersects, lookup_context.intersects_data[1])
  1574    && intersects_array (c,
  1575 		       lookaheadCount, lookahead,
  1576 		       lookup_context.funcs.intersects, lookup_context.intersects_data[2]))
  1577     recurse_lookups (c,
  1578 		     lookupCount, lookupRecord);
  1581 static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
  1582 						        unsigned int backtrackCount,
  1583 						        const USHORT backtrack[],
  1584 						        unsigned int inputCount, /* Including the first glyph (not matched) */
  1585 						        const USHORT input[], /* Array of input values--start with second glyph */
  1586 						        unsigned int lookaheadCount,
  1587 						        const USHORT lookahead[],
  1588 						        unsigned int lookupCount,
  1589 						        const LookupRecord lookupRecord[],
  1590 						        ChainContextCollectGlyphsLookupContext &lookup_context)
  1592   collect_array (c, c->before,
  1593 		 backtrackCount, backtrack,
  1594 		 lookup_context.funcs.collect, lookup_context.collect_data[0]);
  1595   collect_array (c, c->input,
  1596 		 inputCount ? inputCount - 1 : 0, input,
  1597 		 lookup_context.funcs.collect, lookup_context.collect_data[1]);
  1598   collect_array (c, c->after,
  1599 		 lookaheadCount, lookahead,
  1600 		 lookup_context.funcs.collect, lookup_context.collect_data[2]);
  1601   recurse_lookups (c,
  1602 		   lookupCount, lookupRecord);
  1605 static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c,
  1606 						     unsigned int backtrackCount,
  1607 						     const USHORT backtrack[] HB_UNUSED,
  1608 						     unsigned int inputCount, /* Including the first glyph (not matched) */
  1609 						     const USHORT input[], /* Array of input values--start with second glyph */
  1610 						     unsigned int lookaheadCount,
  1611 						     const USHORT lookahead[] HB_UNUSED,
  1612 						     unsigned int lookupCount HB_UNUSED,
  1613 						     const LookupRecord lookupRecord[] HB_UNUSED,
  1614 						     ChainContextApplyLookupContext &lookup_context)
  1616   return (c->zero_context ? !backtrackCount && !lookaheadCount : true)
  1617       && would_match_input (c,
  1618 			    inputCount, input,
  1619 			    lookup_context.funcs.match, lookup_context.match_data[1]);
  1622 static inline bool chain_context_apply_lookup (hb_apply_context_t *c,
  1623 					       unsigned int backtrackCount,
  1624 					       const USHORT backtrack[],
  1625 					       unsigned int inputCount, /* Including the first glyph (not matched) */
  1626 					       const USHORT input[], /* Array of input values--start with second glyph */
  1627 					       unsigned int lookaheadCount,
  1628 					       const USHORT lookahead[],
  1629 					       unsigned int lookupCount,
  1630 					       const LookupRecord lookupRecord[],
  1631 					       ChainContextApplyLookupContext &lookup_context)
  1633   unsigned int match_length = 0;
  1634   unsigned int match_positions[MAX_CONTEXT_LENGTH];
  1635   return match_input (c,
  1636 		      inputCount, input,
  1637 		      lookup_context.funcs.match, lookup_context.match_data[1],
  1638 		      &match_length, match_positions)
  1639       && match_backtrack (c,
  1640 			  backtrackCount, backtrack,
  1641 			  lookup_context.funcs.match, lookup_context.match_data[0])
  1642       && match_lookahead (c,
  1643 			  lookaheadCount, lookahead,
  1644 			  lookup_context.funcs.match, lookup_context.match_data[2],
  1645 			  match_length)
  1646       && apply_lookup (c,
  1647 		       inputCount, match_positions,
  1648 		       lookupCount, lookupRecord,
  1649 		       match_length);
  1652 struct ChainRule
  1654   inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
  1656     TRACE_CLOSURE (this);
  1657     const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
  1658     const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
  1659     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
  1660     chain_context_closure_lookup (c,
  1661 				  backtrack.len, backtrack.array,
  1662 				  input.len, input.array,
  1663 				  lookahead.len, lookahead.array,
  1664 				  lookup.len, lookup.array,
  1665 				  lookup_context);
  1668   inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
  1670     TRACE_COLLECT_GLYPHS (this);
  1671     const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
  1672     const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
  1673     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
  1674     chain_context_collect_glyphs_lookup (c,
  1675 					 backtrack.len, backtrack.array,
  1676 					 input.len, input.array,
  1677 					 lookahead.len, lookahead.array,
  1678 					 lookup.len, lookup.array,
  1679 					 lookup_context);
  1682   inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
  1684     TRACE_WOULD_APPLY (this);
  1685     const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
  1686     const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
  1687     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
  1688     return TRACE_RETURN (chain_context_would_apply_lookup (c,
  1689 							   backtrack.len, backtrack.array,
  1690 							   input.len, input.array,
  1691 							   lookahead.len, lookahead.array, lookup.len,
  1692 							   lookup.array, lookup_context));
  1695   inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
  1697     TRACE_APPLY (this);
  1698     const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
  1699     const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
  1700     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
  1701     return TRACE_RETURN (chain_context_apply_lookup (c,
  1702 						     backtrack.len, backtrack.array,
  1703 						     input.len, input.array,
  1704 						     lookahead.len, lookahead.array, lookup.len,
  1705 						     lookup.array, lookup_context));
  1708   inline bool sanitize (hb_sanitize_context_t *c) {
  1709     TRACE_SANITIZE (this);
  1710     if (!backtrack.sanitize (c)) return TRACE_RETURN (false);
  1711     HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
  1712     if (!input.sanitize (c)) return TRACE_RETURN (false);
  1713     ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
  1714     if (!lookahead.sanitize (c)) return TRACE_RETURN (false);
  1715     ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
  1716     return TRACE_RETURN (lookup.sanitize (c));
  1719   protected:
  1720   ArrayOf<USHORT>
  1721 		backtrack;		/* Array of backtracking values
  1722 					 * (to be matched before the input
  1723 					 * sequence) */
  1724   HeadlessArrayOf<USHORT>
  1725 		inputX;			/* Array of input values (start with
  1726 					 * second glyph) */
  1727   ArrayOf<USHORT>
  1728 		lookaheadX;		/* Array of lookahead values's (to be
  1729 					 * matched after the input sequence) */
  1730   ArrayOf<LookupRecord>
  1731 		lookupX;		/* Array of LookupRecords--in
  1732 					 * design order) */
  1733   public:
  1734   DEFINE_SIZE_MIN (8);
  1735 };
  1737 struct ChainRuleSet
  1739   inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
  1741     TRACE_CLOSURE (this);
  1742     unsigned int num_rules = rule.len;
  1743     for (unsigned int i = 0; i < num_rules; i++)
  1744       (this+rule[i]).closure (c, lookup_context);
  1747   inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
  1749     TRACE_COLLECT_GLYPHS (this);
  1750     unsigned int num_rules = rule.len;
  1751     for (unsigned int i = 0; i < num_rules; i++)
  1752       (this+rule[i]).collect_glyphs (c, lookup_context);
  1755   inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
  1757     TRACE_WOULD_APPLY (this);
  1758     unsigned int num_rules = rule.len;
  1759     for (unsigned int i = 0; i < num_rules; i++)
  1760       if ((this+rule[i]).would_apply (c, lookup_context))
  1761         return TRACE_RETURN (true);
  1763     return TRACE_RETURN (false);
  1766   inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
  1768     TRACE_APPLY (this);
  1769     unsigned int num_rules = rule.len;
  1770     for (unsigned int i = 0; i < num_rules; i++)
  1771       if ((this+rule[i]).apply (c, lookup_context))
  1772         return TRACE_RETURN (true);
  1774     return TRACE_RETURN (false);
  1777   inline bool sanitize (hb_sanitize_context_t *c) {
  1778     TRACE_SANITIZE (this);
  1779     return TRACE_RETURN (rule.sanitize (c, this));
  1782   protected:
  1783   OffsetArrayOf<ChainRule>
  1784 		rule;			/* Array of ChainRule tables
  1785 					 * ordered by preference */
  1786   public:
  1787   DEFINE_SIZE_ARRAY (2, rule);
  1788 };
  1790 struct ChainContextFormat1
  1792   inline void closure (hb_closure_context_t *c) const
  1794     TRACE_CLOSURE (this);
  1795     const Coverage &cov = (this+coverage);
  1797     struct ChainContextClosureLookupContext lookup_context = {
  1798       {intersects_glyph},
  1799       {NULL, NULL, NULL}
  1800     };
  1802     unsigned int count = ruleSet.len;
  1803     for (unsigned int i = 0; i < count; i++)
  1804       if (cov.intersects_coverage (c->glyphs, i)) {
  1805 	const ChainRuleSet &rule_set = this+ruleSet[i];
  1806 	rule_set.closure (c, lookup_context);
  1810   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  1812     TRACE_COLLECT_GLYPHS (this);
  1813     (this+coverage).add_coverage (c->input);
  1815     struct ChainContextCollectGlyphsLookupContext lookup_context = {
  1816       {collect_glyph},
  1817       {NULL, NULL, NULL}
  1818     };
  1820     unsigned int count = ruleSet.len;
  1821     for (unsigned int i = 0; i < count; i++)
  1822       (this+ruleSet[i]).collect_glyphs (c, lookup_context);
  1825   inline bool would_apply (hb_would_apply_context_t *c) const
  1827     TRACE_WOULD_APPLY (this);
  1829     const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
  1830     struct ChainContextApplyLookupContext lookup_context = {
  1831       {match_glyph},
  1832       {NULL, NULL, NULL}
  1833     };
  1834     return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
  1837   inline const Coverage &get_coverage (void) const
  1839     return this+coverage;
  1842   inline bool apply (hb_apply_context_t *c) const
  1844     TRACE_APPLY (this);
  1845     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
  1846     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
  1848     const ChainRuleSet &rule_set = this+ruleSet[index];
  1849     struct ChainContextApplyLookupContext lookup_context = {
  1850       {match_glyph},
  1851       {NULL, NULL, NULL}
  1852     };
  1853     return TRACE_RETURN (rule_set.apply (c, lookup_context));
  1856   inline bool sanitize (hb_sanitize_context_t *c) {
  1857     TRACE_SANITIZE (this);
  1858     return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
  1861   protected:
  1862   USHORT	format;			/* Format identifier--format = 1 */
  1863   OffsetTo<Coverage>
  1864 		coverage;		/* Offset to Coverage table--from
  1865 					 * beginning of table */
  1866   OffsetArrayOf<ChainRuleSet>
  1867 		ruleSet;		/* Array of ChainRuleSet tables
  1868 					 * ordered by Coverage Index */
  1869   public:
  1870   DEFINE_SIZE_ARRAY (6, ruleSet);
  1871 };
  1873 struct ChainContextFormat2
  1875   inline void closure (hb_closure_context_t *c) const
  1877     TRACE_CLOSURE (this);
  1878     if (!(this+coverage).intersects (c->glyphs))
  1879       return;
  1881     const ClassDef &backtrack_class_def = this+backtrackClassDef;
  1882     const ClassDef &input_class_def = this+inputClassDef;
  1883     const ClassDef &lookahead_class_def = this+lookaheadClassDef;
  1885     struct ChainContextClosureLookupContext lookup_context = {
  1886       {intersects_class},
  1887       {&backtrack_class_def,
  1888        &input_class_def,
  1889        &lookahead_class_def}
  1890     };
  1892     unsigned int count = ruleSet.len;
  1893     for (unsigned int i = 0; i < count; i++)
  1894       if (input_class_def.intersects_class (c->glyphs, i)) {
  1895 	const ChainRuleSet &rule_set = this+ruleSet[i];
  1896 	rule_set.closure (c, lookup_context);
  1900   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  1902     TRACE_COLLECT_GLYPHS (this);
  1903     (this+coverage).add_coverage (c->input);
  1905     const ClassDef &backtrack_class_def = this+backtrackClassDef;
  1906     const ClassDef &input_class_def = this+inputClassDef;
  1907     const ClassDef &lookahead_class_def = this+lookaheadClassDef;
  1909     struct ChainContextCollectGlyphsLookupContext lookup_context = {
  1910       {collect_class},
  1911       {&backtrack_class_def,
  1912        &input_class_def,
  1913        &lookahead_class_def}
  1914     };
  1916     unsigned int count = ruleSet.len;
  1917     for (unsigned int i = 0; i < count; i++)
  1918       (this+ruleSet[i]).collect_glyphs (c, lookup_context);
  1921   inline bool would_apply (hb_would_apply_context_t *c) const
  1923     TRACE_WOULD_APPLY (this);
  1925     const ClassDef &backtrack_class_def = this+backtrackClassDef;
  1926     const ClassDef &input_class_def = this+inputClassDef;
  1927     const ClassDef &lookahead_class_def = this+lookaheadClassDef;
  1929     unsigned int index = input_class_def.get_class (c->glyphs[0]);
  1930     const ChainRuleSet &rule_set = this+ruleSet[index];
  1931     struct ChainContextApplyLookupContext lookup_context = {
  1932       {match_class},
  1933       {&backtrack_class_def,
  1934        &input_class_def,
  1935        &lookahead_class_def}
  1936     };
  1937     return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
  1940   inline const Coverage &get_coverage (void) const
  1942     return this+coverage;
  1945   inline bool apply (hb_apply_context_t *c) const
  1947     TRACE_APPLY (this);
  1948     unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
  1949     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
  1951     const ClassDef &backtrack_class_def = this+backtrackClassDef;
  1952     const ClassDef &input_class_def = this+inputClassDef;
  1953     const ClassDef &lookahead_class_def = this+lookaheadClassDef;
  1955     index = input_class_def.get_class (c->buffer->cur().codepoint);
  1956     const ChainRuleSet &rule_set = this+ruleSet[index];
  1957     struct ChainContextApplyLookupContext lookup_context = {
  1958       {match_class},
  1959       {&backtrack_class_def,
  1960        &input_class_def,
  1961        &lookahead_class_def}
  1962     };
  1963     return TRACE_RETURN (rule_set.apply (c, lookup_context));
  1966   inline bool sanitize (hb_sanitize_context_t *c) {
  1967     TRACE_SANITIZE (this);
  1968     return TRACE_RETURN (coverage.sanitize (c, this) && backtrackClassDef.sanitize (c, this) &&
  1969 			 inputClassDef.sanitize (c, this) && lookaheadClassDef.sanitize (c, this) &&
  1970 			 ruleSet.sanitize (c, this));
  1973   protected:
  1974   USHORT	format;			/* Format identifier--format = 2 */
  1975   OffsetTo<Coverage>
  1976 		coverage;		/* Offset to Coverage table--from
  1977 					 * beginning of table */
  1978   OffsetTo<ClassDef>
  1979 		backtrackClassDef;	/* Offset to glyph ClassDef table
  1980 					 * containing backtrack sequence
  1981 					 * data--from beginning of table */
  1982   OffsetTo<ClassDef>
  1983 		inputClassDef;		/* Offset to glyph ClassDef
  1984 					 * table containing input sequence
  1985 					 * data--from beginning of table */
  1986   OffsetTo<ClassDef>
  1987 		lookaheadClassDef;	/* Offset to glyph ClassDef table
  1988 					 * containing lookahead sequence
  1989 					 * data--from beginning of table */
  1990   OffsetArrayOf<ChainRuleSet>
  1991 		ruleSet;		/* Array of ChainRuleSet tables
  1992 					 * ordered by class */
  1993   public:
  1994   DEFINE_SIZE_ARRAY (12, ruleSet);
  1995 };
  1997 struct ChainContextFormat3
  1999   inline void closure (hb_closure_context_t *c) const
  2001     TRACE_CLOSURE (this);
  2002     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
  2004     if (!(this+input[0]).intersects (c->glyphs))
  2005       return;
  2007     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
  2008     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
  2009     struct ChainContextClosureLookupContext lookup_context = {
  2010       {intersects_coverage},
  2011       {this, this, this}
  2012     };
  2013     chain_context_closure_lookup (c,
  2014 				  backtrack.len, (const USHORT *) backtrack.array,
  2015 				  input.len, (const USHORT *) input.array + 1,
  2016 				  lookahead.len, (const USHORT *) lookahead.array,
  2017 				  lookup.len, lookup.array,
  2018 				  lookup_context);
  2021   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  2023     TRACE_COLLECT_GLYPHS (this);
  2024     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
  2026     (this+input[0]).add_coverage (c->input);
  2028     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
  2029     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
  2030     struct ChainContextCollectGlyphsLookupContext lookup_context = {
  2031       {collect_coverage},
  2032       {this, this, this}
  2033     };
  2034     chain_context_collect_glyphs_lookup (c,
  2035 					 backtrack.len, (const USHORT *) backtrack.array,
  2036 					 input.len, (const USHORT *) input.array + 1,
  2037 					 lookahead.len, (const USHORT *) lookahead.array,
  2038 					 lookup.len, lookup.array,
  2039 					 lookup_context);
  2042   inline bool would_apply (hb_would_apply_context_t *c) const
  2044     TRACE_WOULD_APPLY (this);
  2046     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
  2047     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
  2048     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
  2049     struct ChainContextApplyLookupContext lookup_context = {
  2050       {match_coverage},
  2051       {this, this, this}
  2052     };
  2053     return TRACE_RETURN (chain_context_would_apply_lookup (c,
  2054 							   backtrack.len, (const USHORT *) backtrack.array,
  2055 							   input.len, (const USHORT *) input.array + 1,
  2056 							   lookahead.len, (const USHORT *) lookahead.array,
  2057 							   lookup.len, lookup.array, lookup_context));
  2060   inline const Coverage &get_coverage (void) const
  2062     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
  2063     return this+input[0];
  2066   inline bool apply (hb_apply_context_t *c) const
  2068     TRACE_APPLY (this);
  2069     const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
  2071     unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint);
  2072     if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
  2074     const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
  2075     const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
  2076     struct ChainContextApplyLookupContext lookup_context = {
  2077       {match_coverage},
  2078       {this, this, this}
  2079     };
  2080     return TRACE_RETURN (chain_context_apply_lookup (c,
  2081 						     backtrack.len, (const USHORT *) backtrack.array,
  2082 						     input.len, (const USHORT *) input.array + 1,
  2083 						     lookahead.len, (const USHORT *) lookahead.array,
  2084 						     lookup.len, lookup.array, lookup_context));
  2087   inline bool sanitize (hb_sanitize_context_t *c) {
  2088     TRACE_SANITIZE (this);
  2089     if (!backtrack.sanitize (c, this)) return TRACE_RETURN (false);
  2090     OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
  2091     if (!input.sanitize (c, this)) return TRACE_RETURN (false);
  2092     OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
  2093     if (!lookahead.sanitize (c, this)) return TRACE_RETURN (false);
  2094     ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
  2095     return TRACE_RETURN (lookup.sanitize (c));
  2098   protected:
  2099   USHORT	format;			/* Format identifier--format = 3 */
  2100   OffsetArrayOf<Coverage>
  2101 		backtrack;		/* Array of coverage tables
  2102 					 * in backtracking sequence, in  glyph
  2103 					 * sequence order */
  2104   OffsetArrayOf<Coverage>
  2105 		inputX		;	/* Array of coverage
  2106 					 * tables in input sequence, in glyph
  2107 					 * sequence order */
  2108   OffsetArrayOf<Coverage>
  2109 		lookaheadX;		/* Array of coverage tables
  2110 					 * in lookahead sequence, in glyph
  2111 					 * sequence order */
  2112   ArrayOf<LookupRecord>
  2113 		lookupX;		/* Array of LookupRecords--in
  2114 					 * design order) */
  2115   public:
  2116   DEFINE_SIZE_MIN (10);
  2117 };
  2119 struct ChainContext
  2121   template <typename context_t>
  2122   inline typename context_t::return_t dispatch (context_t *c) const
  2124     TRACE_DISPATCH (this);
  2125     switch (u.format) {
  2126     case 1: return TRACE_RETURN (c->dispatch (u.format1));
  2127     case 2: return TRACE_RETURN (c->dispatch (u.format2));
  2128     case 3: return TRACE_RETURN (c->dispatch (u.format3));
  2129     default:return TRACE_RETURN (c->default_return_value ());
  2133   inline bool sanitize (hb_sanitize_context_t *c) {
  2134     TRACE_SANITIZE (this);
  2135     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
  2136     switch (u.format) {
  2137     case 1: return TRACE_RETURN (u.format1.sanitize (c));
  2138     case 2: return TRACE_RETURN (u.format2.sanitize (c));
  2139     case 3: return TRACE_RETURN (u.format3.sanitize (c));
  2140     default:return TRACE_RETURN (true);
  2144   protected:
  2145   union {
  2146   USHORT		format;	/* Format identifier */
  2147   ChainContextFormat1	format1;
  2148   ChainContextFormat2	format2;
  2149   ChainContextFormat3	format3;
  2150   } u;
  2151 };
  2154 struct ExtensionFormat1
  2156   inline unsigned int get_type (void) const { return extensionLookupType; }
  2157   inline unsigned int get_offset (void) const { return extensionOffset; }
  2159   inline bool sanitize (hb_sanitize_context_t *c) {
  2160     TRACE_SANITIZE (this);
  2161     return TRACE_RETURN (c->check_struct (this));
  2164   protected:
  2165   USHORT	format;			/* Format identifier. Set to 1. */
  2166   USHORT	extensionLookupType;	/* Lookup type of subtable referenced
  2167 					 * by ExtensionOffset (i.e. the
  2168 					 * extension subtable). */
  2169   ULONG		extensionOffset;	/* Offset to the extension subtable,
  2170 					 * of lookup type subtable. */
  2171   public:
  2172   DEFINE_SIZE_STATIC (8);
  2173 };
  2175 template <typename T>
  2176 struct Extension
  2178   inline unsigned int get_type (void) const
  2180     switch (u.format) {
  2181     case 1: return u.format1.get_type ();
  2182     default:return 0;
  2185   inline unsigned int get_offset (void) const
  2187     switch (u.format) {
  2188     case 1: return u.format1.get_offset ();
  2189     default:return 0;
  2193   template <typename X>
  2194   inline const X& get_subtable (void) const
  2196     unsigned int offset = get_offset ();
  2197     if (unlikely (!offset)) return Null(typename T::LookupSubTable);
  2198     return StructAtOffset<typename T::LookupSubTable> (this, offset);
  2201   template <typename context_t>
  2202   inline typename context_t::return_t dispatch (context_t *c) const
  2204     return get_subtable<typename T::LookupSubTable> ().dispatch (c, get_type ());
  2207   inline bool sanitize_self (hb_sanitize_context_t *c) {
  2208     TRACE_SANITIZE (this);
  2209     if (!u.format.sanitize (c)) return TRACE_RETURN (false);
  2210     switch (u.format) {
  2211     case 1: return TRACE_RETURN (u.format1.sanitize (c));
  2212     default:return TRACE_RETURN (true);
  2216   inline bool sanitize (hb_sanitize_context_t *c) {
  2217     TRACE_SANITIZE (this);
  2218     if (!sanitize_self (c)) return TRACE_RETURN (false);
  2219     unsigned int offset = get_offset ();
  2220     if (unlikely (!offset)) return TRACE_RETURN (true);
  2221     return TRACE_RETURN (StructAtOffset<typename T::LookupSubTable> (this, offset).sanitize (c, get_type ()));
  2224   protected:
  2225   union {
  2226   USHORT		format;		/* Format identifier */
  2227   ExtensionFormat1	format1;
  2228   } u;
  2229 };
  2232 /*
  2233  * GSUB/GPOS Common
  2234  */
  2236 struct GSUBGPOS
  2238   static const hb_tag_t GSUBTag	= HB_OT_TAG_GSUB;
  2239   static const hb_tag_t GPOSTag	= HB_OT_TAG_GPOS;
  2241   inline unsigned int get_script_count (void) const
  2242   { return (this+scriptList).len; }
  2243   inline const Tag& get_script_tag (unsigned int i) const
  2244   { return (this+scriptList).get_tag (i); }
  2245   inline unsigned int get_script_tags (unsigned int start_offset,
  2246 				       unsigned int *script_count /* IN/OUT */,
  2247 				       hb_tag_t     *script_tags /* OUT */) const
  2248   { return (this+scriptList).get_tags (start_offset, script_count, script_tags); }
  2249   inline const Script& get_script (unsigned int i) const
  2250   { return (this+scriptList)[i]; }
  2251   inline bool find_script_index (hb_tag_t tag, unsigned int *index) const
  2252   { return (this+scriptList).find_index (tag, index); }
  2254   inline unsigned int get_feature_count (void) const
  2255   { return (this+featureList).len; }
  2256   inline const Tag& get_feature_tag (unsigned int i) const
  2257   { return (this+featureList).get_tag (i); }
  2258   inline unsigned int get_feature_tags (unsigned int start_offset,
  2259 					unsigned int *feature_count /* IN/OUT */,
  2260 					hb_tag_t     *feature_tags /* OUT */) const
  2261   { return (this+featureList).get_tags (start_offset, feature_count, feature_tags); }
  2262   inline const Feature& get_feature (unsigned int i) const
  2263   { return (this+featureList)[i]; }
  2264   inline bool find_feature_index (hb_tag_t tag, unsigned int *index) const
  2265   { return (this+featureList).find_index (tag, index); }
  2267   inline unsigned int get_lookup_count (void) const
  2268   { return (this+lookupList).len; }
  2269   inline const Lookup& get_lookup (unsigned int i) const
  2270   { return (this+lookupList)[i]; }
  2272   inline bool sanitize (hb_sanitize_context_t *c) {
  2273     TRACE_SANITIZE (this);
  2274     return TRACE_RETURN (version.sanitize (c) && likely (version.major == 1) &&
  2275 			 scriptList.sanitize (c, this) &&
  2276 			 featureList.sanitize (c, this) &&
  2277 			 lookupList.sanitize (c, this));
  2280   protected:
  2281   FixedVersion	version;	/* Version of the GSUB/GPOS table--initially set
  2282 				 * to 0x00010000 */
  2283   OffsetTo<ScriptList>
  2284 		scriptList;  	/* ScriptList table */
  2285   OffsetTo<FeatureList>
  2286 		featureList; 	/* FeatureList table */
  2287   OffsetTo<LookupList>
  2288 		lookupList; 	/* LookupList table */
  2289   public:
  2290   DEFINE_SIZE_STATIC (10);
  2291 };
  2294 } /* namespace OT */
  2297 #endif /* HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH */

mercurial