blob: 2751c8249ace1b0515509ee2f8dd3ee515567b1b [file] [log] [blame]
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001/*
Behdad Esfahbod2409d5f2011-04-21 17:14:28 -04002 * Copyright © 2007,2008,2009,2010 Red Hat, Inc.
Behdad Esfahbod5b93e8d2012-04-23 22:26:13 -04003 * Copyright © 2010,2012 Google, Inc.
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04004 *
Behdad Esfahbodc755cb32010-04-22 00:11:43 -04005 * This is part of HarfBuzz, a text shaping library.
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04006 *
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
Behdad Esfahbod98370e82010-10-27 17:39:01 -040026 * Google Author(s): Behdad Esfahbod
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -040027 */
28
Behdad Esfahbod5f5b24f2009-08-02 20:03:12 -040029#ifndef HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH
30#define HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -040031
Behdad Esfahbod22da7fd2010-05-12 18:23:21 -040032#include "hb-buffer-private.hh"
Behdad Esfahbod7a750ac2011-08-17 14:19:59 +020033#include "hb-ot-layout-gdef-table.hh"
Behdad Esfahbod1336ecd2012-08-01 21:46:36 -040034#include "hb-set-private.hh"
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -040035
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -040036
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -040037namespace OT {
38
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -040039
Behdad Esfahbod902cc8a2012-11-23 15:06:59 -050040
Behdad Esfahbod00f6a8e2014-12-12 20:36:49 -080041#define TRACE_DISPATCH(this, format) \
Behdad Esfahboda1733db2012-11-23 16:40:04 -050042 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, \
Behdad Esfahbod00f6a8e2014-12-12 20:36:49 -080044 "format %d", (int) format);
Behdad Esfahboda1733db2012-11-23 16:40:04 -050045
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -040046#ifndef HB_DEBUG_CLOSURE
47#define HB_DEBUG_CLOSURE (HB_DEBUG+0)
48#endif
49
Behdad Esfahbodbe218c62012-11-23 15:32:14 -050050#define TRACE_CLOSURE(this) \
Behdad Esfahbod130bb3f2012-12-05 16:49:47 -050051 hb_auto_trace_t<HB_DEBUG_CLOSURE, hb_void_t> trace \
Behdad Esfahbod2c53bd32012-11-23 17:29:05 -050052 (&c->debug_depth, c->get_name (), this, HB_FUNC, \
Behdad Esfahbod902cc8a2012-11-23 15:06:59 -050053 "");
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -040054
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -040055struct hb_closure_context_t
56{
Behdad Esfahboda1733db2012-11-23 16:40:04 -050057 inline const char *get_name (void) { return "CLOSURE"; }
58 static const unsigned int max_debug_depth = HB_DEBUG_CLOSURE;
Behdad Esfahbod130bb3f2012-12-05 16:49:47 -050059 typedef hb_void_t return_t;
Behdad Esfahbod44fc2372012-11-21 23:33:13 -050060 typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
Behdad Esfahbod50b8dc72015-02-17 18:14:17 +030061 template <typename T, typename F>
62 inline bool may_dispatch (const T *obj, const F *format) { return true; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -050063 template <typename T>
Behdad Esfahbod9c5a9ee2013-03-09 01:55:04 -050064 inline return_t dispatch (const T &obj) { obj.closure (this); return HB_VOID; }
Behdad Esfahbod130bb3f2012-12-05 16:49:47 -050065 static return_t default_return_value (void) { return HB_VOID; }
Behdad Esfahbod7b912c12013-01-04 01:25:27 -060066 bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -050067 return_t recurse (unsigned int lookup_index)
68 {
Behdad Esfahbod9b346772012-11-23 17:55:40 -050069 if (unlikely (nesting_level_left == 0 || !recurse_func))
Behdad Esfahbod2005fa52012-11-22 14:38:10 -050070 return default_return_value ();
Behdad Esfahbod44fc2372012-11-21 23:33:13 -050071
72 nesting_level_left--;
73 recurse_func (this, lookup_index);
74 nesting_level_left++;
Behdad Esfahbod130bb3f2012-12-05 16:49:47 -050075 return HB_VOID;
Behdad Esfahbod44fc2372012-11-21 23:33:13 -050076 }
77
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -040078 hb_face_t *face;
Behdad Esfahbod6a9be5b2012-04-23 22:23:17 -040079 hb_set_t *glyphs;
Behdad Esfahbod44fc2372012-11-21 23:33:13 -050080 recurse_func_t recurse_func;
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -040081 unsigned int nesting_level_left;
82 unsigned int debug_depth;
83
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -040084 hb_closure_context_t (hb_face_t *face_,
Behdad Esfahbod6a9be5b2012-04-23 22:23:17 -040085 hb_set_t *glyphs_,
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -040086 unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) :
Behdad Esfahbode72b3602012-07-19 14:35:23 -040087 face (face_),
88 glyphs (glyphs_),
Behdad Esfahbod9b346772012-11-23 17:55:40 -050089 recurse_func (NULL),
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -040090 nesting_level_left (nesting_level_left_),
91 debug_depth (0) {}
Behdad Esfahbod9b346772012-11-23 17:55:40 -050092
93 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -040094};
95
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -040096
97
Behdad Esfahbod472f2292012-08-07 22:25:24 -040098#ifndef HB_DEBUG_WOULD_APPLY
99#define HB_DEBUG_WOULD_APPLY (HB_DEBUG+0)
100#endif
101
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500102#define TRACE_WOULD_APPLY(this) \
Behdad Esfahbod902cc8a2012-11-23 15:06:59 -0500103 hb_auto_trace_t<HB_DEBUG_WOULD_APPLY, bool> trace \
Behdad Esfahbod2c53bd32012-11-23 17:29:05 -0500104 (&c->debug_depth, c->get_name (), this, HB_FUNC, \
Behdad Esfahbod902cc8a2012-11-23 15:06:59 -0500105 "%d glyphs", c->len);
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400106
107struct hb_would_apply_context_t
108{
Behdad Esfahboda1733db2012-11-23 16:40:04 -0500109 inline const char *get_name (void) { return "WOULD_APPLY"; }
110 static const unsigned int max_debug_depth = HB_DEBUG_WOULD_APPLY;
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500111 typedef bool return_t;
Behdad Esfahbod50b8dc72015-02-17 18:14:17 +0300112 template <typename T, typename F>
113 inline bool may_dispatch (const T *obj, const F *format) { return true; }
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500114 template <typename T>
Behdad Esfahbod9c5a9ee2013-03-09 01:55:04 -0500115 inline return_t dispatch (const T &obj) { return obj.would_apply (this); }
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500116 static return_t default_return_value (void) { return false; }
Behdad Esfahbod7b912c12013-01-04 01:25:27 -0600117 bool stop_sublookup_iteration (return_t r) const { return r; }
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500118
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400119 hb_face_t *face;
Behdad Esfahbod472f2292012-08-07 22:25:24 -0400120 const hb_codepoint_t *glyphs;
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400121 unsigned int len;
Behdad Esfahbodd9b204d2012-08-23 16:22:28 -0400122 bool zero_context;
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400123 unsigned int debug_depth;
124
125 hb_would_apply_context_t (hb_face_t *face_,
Behdad Esfahbod472f2292012-08-07 22:25:24 -0400126 const hb_codepoint_t *glyphs_,
127 unsigned int len_,
Behdad Esfahbod2bd9fe32012-09-04 15:15:19 -0400128 bool zero_context_) :
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400129 face (face_),
Behdad Esfahbod472f2292012-08-07 22:25:24 -0400130 glyphs (glyphs_),
131 len (len_),
Behdad Esfahbodd9b204d2012-08-23 16:22:28 -0400132 zero_context (zero_context_),
Behdad Esfahboda1733db2012-11-23 16:40:04 -0500133 debug_depth (0) {}
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400134};
135
136
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800137
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800138#ifndef HB_DEBUG_COLLECT_GLYPHS
139#define HB_DEBUG_COLLECT_GLYPHS (HB_DEBUG+0)
140#endif
141
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500142#define TRACE_COLLECT_GLYPHS(this) \
Behdad Esfahbod130bb3f2012-12-05 16:49:47 -0500143 hb_auto_trace_t<HB_DEBUG_COLLECT_GLYPHS, hb_void_t> trace \
Behdad Esfahbod2c53bd32012-11-23 17:29:05 -0500144 (&c->debug_depth, c->get_name (), this, HB_FUNC, \
Behdad Esfahbod902cc8a2012-11-23 15:06:59 -0500145 "");
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800146
147struct hb_collect_glyphs_context_t
148{
Behdad Esfahboda1733db2012-11-23 16:40:04 -0500149 inline const char *get_name (void) { return "COLLECT_GLYPHS"; }
150 static const unsigned int max_debug_depth = HB_DEBUG_COLLECT_GLYPHS;
Behdad Esfahbod130bb3f2012-12-05 16:49:47 -0500151 typedef hb_void_t return_t;
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500152 typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index);
Behdad Esfahbod50b8dc72015-02-17 18:14:17 +0300153 template <typename T, typename F>
154 inline bool may_dispatch (const T *obj, const F *format) { return true; }
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500155 template <typename T>
Behdad Esfahbod9c5a9ee2013-03-09 01:55:04 -0500156 inline return_t dispatch (const T &obj) { obj.collect_glyphs (this); return HB_VOID; }
Behdad Esfahbod130bb3f2012-12-05 16:49:47 -0500157 static return_t default_return_value (void) { return HB_VOID; }
Behdad Esfahbod7b912c12013-01-04 01:25:27 -0600158 bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500159 return_t recurse (unsigned int lookup_index)
160 {
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500161 if (unlikely (nesting_level_left == 0 || !recurse_func))
162 return default_return_value ();
163
Behdad Esfahbod1bcfa062012-12-04 16:58:09 -0500164 /* Note that GPOS sets recurse_func to NULL already, so it doesn't get
165 * past the previous check. For GSUB, we only want to collect the output
Behdad Esfahbod76ea5632013-05-04 16:01:20 -0400166 * glyphs in the recursion. If output is not requested, we can go home now.
167 *
168 * Note further, that the above is not exactly correct. A recursed lookup
169 * is allowed to match input that is not matched in the context, but that's
170 * not how most fonts are built. It's possible to relax that and recurse
171 * with all sets here if it proves to be an issue.
172 */
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500173
174 if (output == hb_set_get_empty ())
Behdad Esfahbod130bb3f2012-12-05 16:49:47 -0500175 return HB_VOID;
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500176
Behdad Esfahbodfde3e4a2014-10-29 11:23:08 -0700177 /* Return if new lookup was recursed to before. */
178 if (recursed_lookups.has (lookup_index))
179 return HB_VOID;
180
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500181 hb_set_t *old_before = before;
182 hb_set_t *old_input = input;
183 hb_set_t *old_after = after;
184 before = input = after = hb_set_get_empty ();
Behdad Esfahbod1bcfa062012-12-04 16:58:09 -0500185
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500186 nesting_level_left--;
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500187 recurse_func (this, lookup_index);
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500188 nesting_level_left++;
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500189
190 before = old_before;
191 input = old_input;
192 after = old_after;
193
Behdad Esfahbodfde3e4a2014-10-29 11:23:08 -0700194 recursed_lookups.add (lookup_index);
195
Behdad Esfahbod130bb3f2012-12-05 16:49:47 -0500196 return HB_VOID;
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500197 }
198
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800199 hb_face_t *face;
Behdad Esfahbod83035932012-12-04 17:08:41 -0500200 hb_set_t *before;
201 hb_set_t *input;
202 hb_set_t *after;
203 hb_set_t *output;
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500204 recurse_func_t recurse_func;
Behdad Esfahbodfde3e4a2014-10-29 11:23:08 -0700205 hb_set_t recursed_lookups;
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500206 unsigned int nesting_level_left;
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800207 unsigned int debug_depth;
208
209 hb_collect_glyphs_context_t (hb_face_t *face_,
210 hb_set_t *glyphs_before, /* OUT. May be NULL */
211 hb_set_t *glyphs_input, /* OUT. May be NULL */
212 hb_set_t *glyphs_after, /* OUT. May be NULL */
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500213 hb_set_t *glyphs_output, /* OUT. May be NULL */
214 unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) :
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800215 face (face_),
Behdad Esfahbod83035932012-12-04 17:08:41 -0500216 before (glyphs_before ? glyphs_before : hb_set_get_empty ()),
217 input (glyphs_input ? glyphs_input : hb_set_get_empty ()),
218 after (glyphs_after ? glyphs_after : hb_set_get_empty ()),
219 output (glyphs_output ? glyphs_output : hb_set_get_empty ()),
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500220 recurse_func (NULL),
Behdad Esfahbodfde3e4a2014-10-29 11:23:08 -0700221 recursed_lookups (),
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500222 nesting_level_left (nesting_level_left_),
Behdad Esfahbodfde3e4a2014-10-29 11:23:08 -0700223 debug_depth (0)
224 {
225 recursed_lookups.init ();
226 }
227 ~hb_collect_glyphs_context_t (void)
228 {
229 recursed_lookups.fini ();
230 }
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500231
232 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800233};
234
235
236
Behdad Esfahbod295ef1d2014-12-12 20:43:18 -0800237#ifndef HB_DEBUG_GET_COVERAGE
238#define HB_DEBUG_GET_COVERAGE (HB_DEBUG+0)
239#endif
240
Behdad Esfahbod2005fa52012-11-22 14:38:10 -0500241struct hb_get_coverage_context_t
242{
Behdad Esfahboda1733db2012-11-23 16:40:04 -0500243 inline const char *get_name (void) { return "GET_COVERAGE"; }
Behdad Esfahbod295ef1d2014-12-12 20:43:18 -0800244 static const unsigned int max_debug_depth = HB_DEBUG_GET_COVERAGE;
Behdad Esfahbod2005fa52012-11-22 14:38:10 -0500245 typedef const Coverage &return_t;
Behdad Esfahbod50b8dc72015-02-17 18:14:17 +0300246 template <typename T, typename F>
247 inline bool may_dispatch (const T *obj, const F *format) { return true; }
Behdad Esfahbod2005fa52012-11-22 14:38:10 -0500248 template <typename T>
Behdad Esfahbod9c5a9ee2013-03-09 01:55:04 -0500249 inline return_t dispatch (const T &obj) { return obj.get_coverage (); }
Behdad Esfahboda1733db2012-11-23 16:40:04 -0500250 static return_t default_return_value (void) { return Null(Coverage); }
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500251
Behdad Esfahboda1733db2012-11-23 16:40:04 -0500252 hb_get_coverage_context_t (void) :
253 debug_depth (0) {}
254
255 unsigned int debug_depth;
Behdad Esfahbod2005fa52012-11-22 14:38:10 -0500256};
257
258
259
Behdad Esfahbod0535b502009-08-28 17:14:33 -0400260#ifndef HB_DEBUG_APPLY
Behdad Esfahbod11e3ec42010-11-03 15:11:04 -0400261#define HB_DEBUG_APPLY (HB_DEBUG+0)
Behdad Esfahbod0535b502009-08-28 17:14:33 -0400262#endif
263
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500264#define TRACE_APPLY(this) \
Behdad Esfahbod902cc8a2012-11-23 15:06:59 -0500265 hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace \
Behdad Esfahbod2c53bd32012-11-23 17:29:05 -0500266 (&c->debug_depth, c->get_name (), this, HB_FUNC, \
Behdad Esfahbod902cc8a2012-11-23 15:06:59 -0500267 "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);
Behdad Esfahbod0535b502009-08-28 17:14:33 -0400268
Behdad Esfahbod1376fb72010-04-29 02:19:21 -0400269struct hb_apply_context_t
270{
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500271 struct matcher_t
272 {
273 inline matcher_t (void) :
274 lookup_props (0),
Behdad Esfahbodcfc507c2013-02-14 10:40:12 -0500275 ignore_zwnj (false),
276 ignore_zwj (false),
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500277 mask (-1),
278#define arg1(arg) (arg) /* Remove the macro to see why it's needed! */
279 syllable arg1(0),
280#undef arg1
281 match_func (NULL),
282 match_data (NULL) {};
283
284 typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data);
285
286 inline void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; }
Behdad Esfahbod0b454792013-02-14 10:46:52 -0500287 inline void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500288 inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
289 inline void set_mask (hb_mask_t mask_) { mask = mask_; }
290 inline void set_syllable (uint8_t syllable_) { syllable = syllable_; }
291 inline void set_match_func (match_func_t match_func_,
292 const void *match_data_)
293 { match_func = match_func_; match_data = match_data_; }
294
Behdad Esfahbod2b2a6e82013-02-21 15:07:03 -0500295 enum may_match_t {
296 MATCH_NO,
297 MATCH_YES,
298 MATCH_MAYBE
299 };
300
301 inline may_match_t may_match (const hb_glyph_info_t &info,
302 const USHORT *glyph_data) const
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500303 {
Behdad Esfahbod2b2a6e82013-02-21 15:07:03 -0500304 if (!(info.mask & mask) ||
305 (syllable && syllable != info.syllable ()))
306 return MATCH_NO;
307
308 if (match_func)
309 return match_func (info.codepoint, *glyph_data, match_data) ? MATCH_YES : MATCH_NO;
310
311 return MATCH_MAYBE;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500312 }
313
314 enum may_skip_t {
315 SKIP_NO,
316 SKIP_YES,
317 SKIP_MAYBE
318 };
319
320 inline may_skip_t
321 may_skip (const hb_apply_context_t *c,
322 const hb_glyph_info_t &info) const
323 {
Behdad Esfahbodb98c5db2014-07-16 13:44:01 -0400324 if (!c->check_glyph_property (&info, lookup_props))
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500325 return SKIP_YES;
326
Behdad Esfahbod0b454792013-02-14 10:46:52 -0500327 if (unlikely (_hb_glyph_info_is_default_ignorable (&info) &&
328 (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) &&
329 (ignore_zwj || !_hb_glyph_info_is_zwj (&info)) &&
Behdad Esfahboda1f7b282013-10-18 01:09:08 +0200330 !_hb_glyph_info_ligated (&info)))
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500331 return SKIP_MAYBE;
332
333 return SKIP_NO;
334 }
335
336 protected:
337 unsigned int lookup_props;
338 bool ignore_zwnj;
Behdad Esfahbod0b454792013-02-14 10:46:52 -0500339 bool ignore_zwj;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500340 hb_mask_t mask;
341 uint8_t syllable;
342 match_func_t match_func;
343 const void *match_data;
344 };
345
Behdad Esfahbod69626692015-01-29 13:08:41 +0100346 struct skipping_iterator_t
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500347 {
Behdad Esfahbod514564f2015-01-29 13:48:48 +0100348 inline void init (hb_apply_context_t *c_, bool context_match = false)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500349 {
Behdad Esfahbod514564f2015-01-29 13:48:48 +0100350 c = c_;
351 match_glyph_data = NULL,
352 matcher.set_match_func (NULL, NULL);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500353 matcher.set_lookup_props (c->lookup_props);
Behdad Esfahboda8cf7b42013-03-19 05:53:26 -0400354 /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
355 matcher.set_ignore_zwnj (context_match || c->table_index == 1);
356 /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */
357 matcher.set_ignore_zwj (context_match || c->table_index == 1 || c->auto_zwj);
Behdad Esfahbod514564f2015-01-29 13:48:48 +0100358 matcher.set_mask (context_match ? -1 : c->lookup_mask);
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500359 }
Behdad Esfahbod514564f2015-01-29 13:48:48 +0100360 inline void set_lookup_props (unsigned int lookup_props)
361 {
362 matcher.set_lookup_props (lookup_props);
363 }
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500364 inline void set_match_func (matcher_t::match_func_t match_func,
365 const void *match_data,
366 const USHORT glyph_data[])
Behdad Esfahbodc074ebc2013-02-13 11:22:42 -0500367 {
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500368 matcher.set_match_func (match_func, match_data);
369 match_glyph_data = glyph_data;
Behdad Esfahbodc074ebc2013-02-13 11:22:42 -0500370 }
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500371
Behdad Esfahbodb051be52015-01-29 13:40:39 +0100372 inline void reset (unsigned int start_index_,
373 unsigned int num_items_)
374 {
375 idx = start_index_;
376 num_items = num_items_;
377 end = c->buffer->len;
378 matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
379 }
380
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500381 inline void reject (void) { num_items++; match_glyph_data--; }
Behdad Esfahbod69626692015-01-29 13:08:41 +0100382
Behdad Esfahbodc074ebc2013-02-13 11:22:42 -0500383 inline bool next (void)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500384 {
Behdad Esfahbod506ffeb2012-01-18 16:07:53 -0500385 assert (num_items > 0);
Behdad Esfahbod37d13ac2015-01-29 11:38:01 +0100386 while (idx + num_items < end)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500387 {
Behdad Esfahboda4a48fe2012-01-17 18:08:41 -0500388 idx++;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500389 const hb_glyph_info_t &info = c->buffer->info[idx];
390
Behdad Esfahbodff93ac82013-02-21 14:51:40 -0500391 matcher_t::may_skip_t skip = matcher.may_skip (c, info);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500392 if (unlikely (skip == matcher_t::SKIP_YES))
393 continue;
394
Behdad Esfahbod2b2a6e82013-02-21 15:07:03 -0500395 matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
Behdad Esfahbod722e8b82013-02-21 15:37:51 -0500396 if (match == matcher_t::MATCH_YES ||
397 (match == matcher_t::MATCH_MAYBE &&
398 skip == matcher_t::SKIP_NO))
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500399 {
400 num_items--;
401 match_glyph_data++;
402 return true;
403 }
404
405 if (skip == matcher_t::SKIP_NO)
Behdad Esfahbod722e8b82013-02-21 15:37:51 -0500406 return false;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500407 }
408 return false;
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500409 }
Behdad Esfahbodc074ebc2013-02-13 11:22:42 -0500410 inline bool prev (void)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500411 {
Behdad Esfahbod506ffeb2012-01-18 16:07:53 -0500412 assert (num_items > 0);
Behdad Esfahbod37d13ac2015-01-29 11:38:01 +0100413 while (idx >= num_items)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500414 {
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500415 idx--;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500416 const hb_glyph_info_t &info = c->buffer->out_info[idx];
417
Behdad Esfahbodff93ac82013-02-21 14:51:40 -0500418 matcher_t::may_skip_t skip = matcher.may_skip (c, info);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500419 if (unlikely (skip == matcher_t::SKIP_YES))
420 continue;
421
Behdad Esfahbod2b2a6e82013-02-21 15:07:03 -0500422 matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
Behdad Esfahbod722e8b82013-02-21 15:37:51 -0500423 if (match == matcher_t::MATCH_YES ||
424 (match == matcher_t::MATCH_MAYBE &&
425 skip == matcher_t::SKIP_NO))
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500426 {
427 num_items--;
428 match_glyph_data++;
429 return true;
430 }
431
432 if (skip == matcher_t::SKIP_NO)
Behdad Esfahbod722e8b82013-02-21 15:37:51 -0500433 return false;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500434 }
435 return false;
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500436 }
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500437
438 unsigned int idx;
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400439 protected:
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500440 hb_apply_context_t *c;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500441 matcher_t matcher;
442 const USHORT *match_glyph_data;
443
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500444 unsigned int num_items;
Behdad Esfahbod69626692015-01-29 13:08:41 +0100445 unsigned int end;
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500446 };
447
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100448
449 inline const char *get_name (void) { return "APPLY"; }
450 static const unsigned int max_debug_depth = HB_DEBUG_APPLY;
451 typedef bool return_t;
452 typedef return_t (*recurse_func_t) (hb_apply_context_t *c, unsigned int lookup_index);
Behdad Esfahbod50b8dc72015-02-17 18:14:17 +0300453 template <typename T, typename F>
454 inline bool may_dispatch (const T *obj, const F *format) { return true; }
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100455 template <typename T>
456 inline return_t dispatch (const T &obj) { return obj.apply (this); }
457 static return_t default_return_value (void) { return false; }
458 bool stop_sublookup_iteration (return_t r) const { return r; }
459 return_t recurse (unsigned int lookup_index)
460 {
461 if (unlikely (nesting_level_left == 0 || !recurse_func))
462 return default_return_value ();
463
464 nesting_level_left--;
465 bool ret = recurse_func (this, lookup_index);
466 nesting_level_left++;
467 return ret;
468 }
469
470 unsigned int table_index; /* GSUB/GPOS */
471 hb_font_t *font;
472 hb_face_t *face;
473 hb_buffer_t *buffer;
474 hb_direction_t direction;
475 hb_mask_t lookup_mask;
476 bool auto_zwj;
477 recurse_func_t recurse_func;
478 unsigned int nesting_level_left;
479 unsigned int lookup_props;
480 const GDEF &gdef;
481 bool has_glyph_classes;
Behdad Esfahbod365576d2015-01-29 13:59:42 +0100482 skipping_iterator_t iter_input, iter_context;
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100483 unsigned int debug_depth;
484
485
486 hb_apply_context_t (unsigned int table_index_,
487 hb_font_t *font_,
488 hb_buffer_t *buffer_) :
489 table_index (table_index_),
490 font (font_), face (font->face), buffer (buffer_),
491 direction (buffer_->props.direction),
492 lookup_mask (1),
493 auto_zwj (true),
494 recurse_func (NULL),
495 nesting_level_left (MAX_NESTING_LEVEL),
496 lookup_props (0),
497 gdef (*hb_ot_layout_from_face (face)->gdef),
498 has_glyph_classes (gdef.has_glyph_classes ()),
Behdad Esfahbod365576d2015-01-29 13:59:42 +0100499 iter_input (),
500 iter_context (),
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100501 debug_depth (0) {}
502
503 inline void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; }
504 inline void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; }
505 inline void set_recurse_func (recurse_func_t func) { recurse_func = func; }
Behdad Esfahbod365576d2015-01-29 13:59:42 +0100506 inline void set_lookup (const Lookup &l) { set_lookup_props (l.get_props ()); }
507 inline void set_lookup_props (unsigned int lookup_props_)
508 {
509 lookup_props = lookup_props_;
510 iter_input.init (this, false);
511 iter_context.init (this, true);
512 }
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100513
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400514 inline bool
515 match_properties_mark (hb_codepoint_t glyph,
516 unsigned int glyph_props,
517 unsigned int lookup_props) const
518 {
519 /* If using mark filtering sets, the high short of
520 * lookup_props has the set index.
521 */
522 if (lookup_props & LookupFlag::UseMarkFilteringSet)
523 return gdef.mark_set_covers (lookup_props >> 16, glyph);
524
525 /* The second byte of lookup_props has the meaning
526 * "ignore marks of attachment type different than
527 * the attachment type specified."
528 */
529 if (lookup_props & LookupFlag::MarkAttachmentType)
530 return (lookup_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);
531
532 return true;
533 }
534
535 inline bool
Behdad Esfahbodb98c5db2014-07-16 13:44:01 -0400536 check_glyph_property (const hb_glyph_info_t *info,
537 unsigned int lookup_props) const
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400538 {
Behdad Esfahbodb98c5db2014-07-16 13:44:01 -0400539 hb_codepoint_t glyph = info->codepoint;
540 unsigned int glyph_props = _hb_glyph_info_get_glyph_props (info);
541
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400542 /* Not covered, if, for example, glyph class is ligature and
543 * lookup_props includes LookupFlags::IgnoreLigatures
544 */
545 if (glyph_props & lookup_props & LookupFlag::IgnoreFlags)
546 return false;
547
Behdad Esfahbod5a08ecf2012-11-16 13:34:29 -0800548 if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK))
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400549 return match_properties_mark (glyph, glyph_props, lookup_props);
550
551 return true;
552 }
553
Behdad Esfahboda0161742013-10-18 00:06:30 +0200554 inline void _set_glyph_props (hb_codepoint_t glyph_index,
Behdad Esfahbod71b4c992013-10-28 00:20:59 +0100555 unsigned int class_guess = 0,
Behdad Esfahbod832a6f92014-06-04 16:57:42 -0400556 bool ligature = false,
557 bool component = false) const
Behdad Esfahbod60da7632012-07-16 16:13:32 -0400558 {
Behdad Esfahbod09675a82013-10-18 01:05:58 +0200559 unsigned int add_in = _hb_glyph_info_get_glyph_props (&buffer->cur()) &
560 HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE;
561 add_in |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED;
562 if (ligature)
Behdad Esfahbod832a6f92014-06-04 16:57:42 -0400563 {
Behdad Esfahbod09675a82013-10-18 01:05:58 +0200564 add_in |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED;
Behdad Esfahbod832a6f92014-06-04 16:57:42 -0400565 /* In the only place that the MULTIPLIED bit is used, Uniscribe
566 * seems to only care about the "last" transformation between
567 * Ligature and Multiple substitions. Ie. if you ligate, expand,
568 * and ligate again, it forgives the multiplication and acts as
569 * if only ligation happened. As such, clear MULTIPLIED bit.
570 */
571 add_in &= ~HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
572 }
573 if (component)
574 add_in |= HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
Behdad Esfahbod2fca1422012-07-30 18:46:41 -0400575 if (likely (has_glyph_classes))
Behdad Esfahbod05ad6b52013-10-18 00:45:59 +0200576 _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | gdef.get_glyph_props (glyph_index));
Behdad Esfahbod05bd1b62012-07-30 19:30:01 -0400577 else if (class_guess)
Behdad Esfahbod09675a82013-10-18 01:05:58 +0200578 _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | class_guess);
Behdad Esfahbod60da7632012-07-16 16:13:32 -0400579 }
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500580
Behdad Esfahboda0161742013-10-18 00:06:30 +0200581 inline void replace_glyph (hb_codepoint_t glyph_index) const
Behdad Esfahbod3ec77d62012-06-08 21:44:06 -0400582 {
Behdad Esfahboda0161742013-10-18 00:06:30 +0200583 _set_glyph_props (glyph_index);
Behdad Esfahbod98370e82010-10-27 17:39:01 -0400584 buffer->replace_glyph (glyph_index);
585 }
Behdad Esfahboda0161742013-10-18 00:06:30 +0200586 inline void replace_glyph_inplace (hb_codepoint_t glyph_index) const
Behdad Esfahbod7fbbf862012-07-30 18:36:42 -0400587 {
Behdad Esfahboda0161742013-10-18 00:06:30 +0200588 _set_glyph_props (glyph_index);
Behdad Esfahbod7fbbf862012-07-30 18:36:42 -0400589 buffer->cur().codepoint = glyph_index;
590 }
Behdad Esfahboda0161742013-10-18 00:06:30 +0200591 inline void replace_glyph_with_ligature (hb_codepoint_t glyph_index,
592 unsigned int class_guess) const
593 {
Behdad Esfahbod09675a82013-10-18 01:05:58 +0200594 _set_glyph_props (glyph_index, class_guess, true);
Behdad Esfahboda0161742013-10-18 00:06:30 +0200595 buffer->replace_glyph (glyph_index);
596 }
Behdad Esfahbod832a6f92014-06-04 16:57:42 -0400597 inline void output_glyph_for_component (hb_codepoint_t glyph_index,
598 unsigned int class_guess) const
Behdad Esfahboda0161742013-10-18 00:06:30 +0200599 {
Behdad Esfahbod832a6f92014-06-04 16:57:42 -0400600 _set_glyph_props (glyph_index, class_guess, false, true);
Behdad Esfahboda0161742013-10-18 00:06:30 +0200601 buffer->output_glyph (glyph_index);
602 }
Behdad Esfahbod1376fb72010-04-29 02:19:21 -0400603};
604
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -0400605
Behdad Esfahbod94a23aa2010-05-05 01:13:09 -0400606
Behdad Esfahbod6a9be5b2012-04-23 22:23:17 -0400607typedef bool (*intersects_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500608typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data);
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -0400609typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -0400610
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400611struct ContextClosureFuncs
612{
613 intersects_func_t intersects;
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400614};
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500615struct ContextCollectGlyphsFuncs
616{
617 collect_glyphs_func_t collect;
618};
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400619struct ContextApplyFuncs
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400620{
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -0400621 match_func_t match;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -0400622};
623
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500624
Behdad Esfahbod6a9be5b2012-04-23 22:23:17 -0400625static inline bool intersects_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED)
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400626{
627 return glyphs->has (value);
628}
Behdad Esfahbod6a9be5b2012-04-23 22:23:17 -0400629static inline bool intersects_class (hb_set_t *glyphs, const USHORT &value, const void *data)
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400630{
631 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
632 return class_def.intersects_class (glyphs, value);
633}
Behdad Esfahbod6a9be5b2012-04-23 22:23:17 -0400634static inline bool intersects_coverage (hb_set_t *glyphs, const USHORT &value, const void *data)
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400635{
636 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
637 return (data+coverage).intersects (glyphs);
638}
639
640static inline bool intersects_array (hb_closure_context_t *c,
641 unsigned int count,
642 const USHORT values[],
643 intersects_func_t intersects_func,
644 const void *intersects_data)
645{
646 for (unsigned int i = 0; i < count; i++)
647 if (likely (!intersects_func (c->glyphs, values[i], intersects_data)))
648 return false;
649 return true;
650}
651
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -0400652
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500653static inline void collect_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED)
654{
655 glyphs->add (value);
656}
657static inline void collect_class (hb_set_t *glyphs, const USHORT &value, const void *data)
658{
659 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
660 class_def.add_class (glyphs, value);
661}
662static inline void collect_coverage (hb_set_t *glyphs, const USHORT &value, const void *data)
663{
664 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
665 (data+coverage).add_coverage (glyphs);
666}
Behdad Esfahbod0beb66e2012-12-05 18:46:04 -0500667static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -0500668 hb_set_t *glyphs,
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500669 unsigned int count,
670 const USHORT values[],
671 collect_glyphs_func_t collect_func,
672 const void *collect_data)
673{
674 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbodf1b12782012-11-24 01:55:34 -0500675 collect_func (glyphs, values[i], collect_data);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500676}
677
678
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -0400679static inline bool match_glyph (hb_codepoint_t glyph_id, const USHORT &value, const void *data HB_UNUSED)
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400680{
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -0400681 return glyph_id == value;
682}
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -0400683static inline bool match_class (hb_codepoint_t glyph_id, const USHORT &value, const void *data)
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400684{
Behdad Esfahbod2b5a59c2009-08-04 11:38:50 -0400685 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -0400686 return class_def.get_class (glyph_id) == value;
687}
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -0400688static inline bool match_coverage (hb_codepoint_t glyph_id, const USHORT &value, const void *data)
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400689{
Behdad Esfahbod6b54c5d2009-05-18 18:30:25 -0400690 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400691 return (data+coverage).get_coverage (glyph_id) != NOT_COVERED;
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -0400692}
693
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400694static inline bool would_match_input (hb_would_apply_context_t *c,
695 unsigned int count, /* Including the first glyph (not matched) */
696 const USHORT input[], /* Array of input values--start with second glyph */
697 match_func_t match_func,
698 const void *match_data)
699{
700 if (count != c->len)
701 return false;
702
703 for (unsigned int i = 1; i < count; i++)
Behdad Esfahbod472f2292012-08-07 22:25:24 -0400704 if (likely (!match_func (c->glyphs[i], input[i - 1], match_data)))
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400705 return false;
706
707 return true;
708}
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400709static inline bool match_input (hb_apply_context_t *c,
Behdad Esfahbode072c242009-05-18 03:47:31 -0400710 unsigned int count, /* Including the first glyph (not matched) */
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -0400711 const USHORT input[], /* Array of input values--start with second glyph */
712 match_func_t match_func,
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -0400713 const void *match_data,
Behdad Esfahbod6cc136f2013-10-17 13:55:48 +0200714 unsigned int *end_offset,
715 unsigned int match_positions[MAX_CONTEXT_LENGTH],
Behdad Esfahbod191fa882012-08-28 22:58:55 -0400716 bool *p_is_mark_ligature = NULL,
717 unsigned int *p_total_component_count = NULL)
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -0400718{
Behdad Esfahbod73c18ae2012-11-23 15:34:11 -0500719 TRACE_APPLY (NULL);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400720
Behdad Esfahbod6b65a762013-10-14 18:51:39 +0200721 if (unlikely (count > MAX_CONTEXT_LENGTH)) TRACE_RETURN (false);
722
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200723 hb_buffer_t *buffer = c->buffer;
724
Behdad Esfahbod365576d2015-01-29 13:59:42 +0100725 hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
Behdad Esfahbodb051be52015-01-29 13:40:39 +0100726 skippy_iter.reset (buffer->idx, count - 1);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500727 skippy_iter.set_match_func (match_func, match_data, input);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400728
Behdad Esfahbod191fa882012-08-28 22:58:55 -0400729 /*
730 * This is perhaps the trickiest part of OpenType... Remarks:
731 *
732 * - If all components of the ligature were marks, we call this a mark ligature.
733 *
734 * - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize
735 * it as a ligature glyph.
736 *
737 * - Ligatures cannot be formed across glyphs attached to different components
738 * of previous ligatures. Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and
739 * LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother.
740 * However, it would be wrong to ligate that SHADDA,FATHA sequence.o
741 * There is an exception to this: If a ligature tries ligating with marks that
742 * belong to it itself, go ahead, assuming that the font designer knows what
743 * they are doing (otherwise it can break Indic stuff when a matra wants to
744 * ligate with a conjunct...)
745 */
746
Behdad Esfahbod101303d2013-10-18 00:42:39 +0200747 bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->cur());
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400748
749 unsigned int total_component_count = 0;
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200750 total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur());
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400751
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200752 unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
753 unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -0400754
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200755 match_positions[0] = buffer->idx;
Behdad Esfahbod370f03e2012-01-16 17:03:55 -0500756 for (unsigned int i = 1; i < count; i++)
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400757 {
Behdad Esfahbod407fc122013-02-13 11:13:06 -0500758 if (!skippy_iter.next ()) return TRACE_RETURN (false);
Behdad Esfahbod6cc136f2013-10-17 13:55:48 +0200759
760 match_positions[i] = skippy_iter.idx;
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400761
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200762 unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]);
763 unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400764
765 if (first_lig_id && first_lig_comp) {
766 /* If first component was attached to a previous ligature component,
767 * all subsequent components should be attached to the same ligature
768 * component, otherwise we shouldn't ligate them. */
769 if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
770 return TRACE_RETURN (false);
771 } else {
772 /* If first component was NOT attached to a previous ligature component,
773 * all subsequent components should also NOT be attached to any ligature
774 * component, unless they are attached to the first component itself! */
775 if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id))
776 return TRACE_RETURN (false);
777 }
778
Behdad Esfahbod101303d2013-10-18 00:42:39 +0200779 is_mark_ligature = is_mark_ligature && _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx]);
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200780 total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -0400781 }
782
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200783 *end_offset = skippy_iter.idx - buffer->idx + 1;
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400784
Behdad Esfahbod191fa882012-08-28 22:58:55 -0400785 if (p_is_mark_ligature)
786 *p_is_mark_ligature = is_mark_ligature;
787
788 if (p_total_component_count)
789 *p_total_component_count = total_component_count;
790
Behdad Esfahbodbc513ad2012-10-29 19:03:55 -0700791 return TRACE_RETURN (true);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400792}
Behdad Esfahboda177d022012-08-28 23:18:22 -0400793static inline void ligate_input (hb_apply_context_t *c,
Behdad Esfahbode714fe62013-10-17 13:49:51 +0200794 unsigned int count, /* Including the first glyph */
795 unsigned int match_positions[MAX_CONTEXT_LENGTH], /* Including the first glyph */
796 unsigned int match_length,
Behdad Esfahboda177d022012-08-28 23:18:22 -0400797 hb_codepoint_t lig_glyph,
Behdad Esfahboda177d022012-08-28 23:18:22 -0400798 bool is_mark_ligature,
799 unsigned int total_component_count)
800{
Behdad Esfahbode714fe62013-10-17 13:49:51 +0200801 TRACE_APPLY (NULL);
802
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200803 hb_buffer_t *buffer = c->buffer;
804
805 buffer->merge_clusters (buffer->idx, buffer->idx + match_length);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500806
Behdad Esfahboda177d022012-08-28 23:18:22 -0400807 /*
808 * - If it *is* a mark ligature, we don't allocate a new ligature id, and leave
809 * the ligature to keep its old ligature id. This will allow it to attach to
810 * a base ligature in GPOS. Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH,
811 * and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA wit a
812 * ligature id and component value of 2. Then if SHADDA,FATHA form a ligature
813 * later, we don't want them to lose their ligature id/component, otherwise
814 * GPOS will fail to correctly position the mark ligature on top of the
815 * LAM,LAM,HEH ligature. See:
816 * https://bugzilla.gnome.org/show_bug.cgi?id=676343
817 *
818 * - If a ligature is formed of components that some of which are also ligatures
819 * themselves, and those ligature components had marks attached to *their*
820 * components, we have to attach the marks to the new ligature component
821 * positions! Now *that*'s tricky! And these marks may be following the
822 * last component of the whole sequence, so we should loop forward looking
823 * for them and update them.
824 *
825 * Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a
826 * 'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature
827 * id and component == 1. Now, during 'liga', the LAM and the LAM-HEH ligature
828 * form a LAM-LAM-HEH ligature. We need to reassign the SHADDA and FATHA to
829 * the new ligature with a component value of 2.
830 *
831 * This in fact happened to a font... See:
832 * https://bugzilla.gnome.org/show_bug.cgi?id=437633
833 */
834
Behdad Esfahbod5a08ecf2012-11-16 13:34:29 -0800835 unsigned int klass = is_mark_ligature ? 0 : HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200836 unsigned int lig_id = is_mark_ligature ? 0 : _hb_allocate_lig_id (buffer);
837 unsigned int last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
838 unsigned int last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
Behdad Esfahboda177d022012-08-28 23:18:22 -0400839 unsigned int components_so_far = last_num_components;
840
841 if (!is_mark_ligature)
Behdad Esfahbod7e08f122013-05-27 14:48:34 -0400842 {
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200843 _hb_glyph_info_set_lig_props_for_ligature (&buffer->cur(), lig_id, total_component_count);
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200844 if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
Behdad Esfahbod3d436d32013-10-28 21:00:37 +0100845 {
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200846 _hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER);
Behdad Esfahbod3d436d32013-10-28 21:00:37 +0100847 _hb_glyph_info_set_modified_combining_class (&buffer->cur(), 0);
848 }
Behdad Esfahbod7e08f122013-05-27 14:48:34 -0400849 }
Behdad Esfahboda0161742013-10-18 00:06:30 +0200850 c->replace_glyph_with_ligature (lig_glyph, klass);
Behdad Esfahboda177d022012-08-28 23:18:22 -0400851
852 for (unsigned int i = 1; i < count; i++)
853 {
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200854 while (buffer->idx < match_positions[i])
Behdad Esfahboda177d022012-08-28 23:18:22 -0400855 {
856 if (!is_mark_ligature) {
857 unsigned int new_lig_comp = components_so_far - last_num_components +
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200858 MIN (MAX (_hb_glyph_info_get_lig_comp (&buffer->cur()), 1u), last_num_components);
859 _hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
Behdad Esfahboda177d022012-08-28 23:18:22 -0400860 }
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200861 buffer->next_glyph ();
Behdad Esfahboda177d022012-08-28 23:18:22 -0400862 }
863
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200864 last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
865 last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
Behdad Esfahboda177d022012-08-28 23:18:22 -0400866 components_so_far += last_num_components;
867
868 /* Skip the base glyph */
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200869 buffer->idx++;
Behdad Esfahboda177d022012-08-28 23:18:22 -0400870 }
871
872 if (!is_mark_ligature && last_lig_id) {
873 /* Re-adjust components for any marks following. */
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200874 for (unsigned int i = buffer->idx; i < buffer->len; i++) {
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200875 if (last_lig_id == _hb_glyph_info_get_lig_id (&buffer->info[i])) {
Behdad Esfahboda177d022012-08-28 23:18:22 -0400876 unsigned int new_lig_comp = components_so_far - last_num_components +
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200877 MIN (MAX (_hb_glyph_info_get_lig_comp (&buffer->info[i]), 1u), last_num_components);
878 _hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
Behdad Esfahboda177d022012-08-28 23:18:22 -0400879 } else
880 break;
881 }
882 }
Behdad Esfahbod04d894e2014-03-25 12:11:32 -0700883 TRACE_RETURN (true);
Behdad Esfahboda177d022012-08-28 23:18:22 -0400884}
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400885
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400886static inline bool match_backtrack (hb_apply_context_t *c,
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400887 unsigned int count,
888 const USHORT backtrack[],
889 match_func_t match_func,
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -0400890 const void *match_data)
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400891{
Behdad Esfahbod73c18ae2012-11-23 15:34:11 -0500892 TRACE_APPLY (NULL);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400893
Behdad Esfahbod365576d2015-01-29 13:59:42 +0100894 hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
Behdad Esfahbodb051be52015-01-29 13:40:39 +0100895 skippy_iter.reset (c->buffer->backtrack_len (), count);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500896 skippy_iter.set_match_func (match_func, match_data, backtrack);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400897
Behdad Esfahbod4d3aeb82012-01-16 16:43:26 -0500898 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500899 if (!skippy_iter.prev ())
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400900 return TRACE_RETURN (false);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400901
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400902 return TRACE_RETURN (true);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400903}
904
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400905static inline bool match_lookahead (hb_apply_context_t *c,
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400906 unsigned int count,
907 const USHORT lookahead[],
908 match_func_t match_func,
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -0400909 const void *match_data,
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400910 unsigned int offset)
911{
Behdad Esfahbod73c18ae2012-11-23 15:34:11 -0500912 TRACE_APPLY (NULL);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400913
Behdad Esfahbod365576d2015-01-29 13:59:42 +0100914 hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
Behdad Esfahbodb051be52015-01-29 13:40:39 +0100915 skippy_iter.reset (c->buffer->idx + offset - 1, count);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500916 skippy_iter.set_match_func (match_func, match_data, lookahead);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400917
Behdad Esfahbod370f03e2012-01-16 17:03:55 -0500918 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500919 if (!skippy_iter.next ())
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400920 return TRACE_RETURN (false);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400921
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400922 return TRACE_RETURN (true);
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -0400923}
924
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -0400925
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -0400926
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400927struct LookupRecord
928{
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300929 inline bool sanitize (hb_sanitize_context_t *c) const
930 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500931 TRACE_SANITIZE (this);
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200932 return TRACE_RETURN (c->check_struct (this));
Behdad Esfahbodcd3827e2009-08-04 02:09:34 -0400933 }
934
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -0400935 USHORT sequenceIndex; /* Index into current glyph
936 * sequence--first glyph = 0 */
937 USHORT lookupListIndex; /* Lookup to apply to that
938 * position--zero--based */
Behdad Esfahbod569da922010-05-10 16:38:32 -0400939 public:
940 DEFINE_SIZE_STATIC (4);
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -0400941};
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -0400942
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -0400943
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500944template <typename context_t>
945static inline void recurse_lookups (context_t *c,
946 unsigned int lookupCount,
947 const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400948{
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400949 for (unsigned int i = 0; i < lookupCount; i++)
Behdad Esfahbod86522e42013-07-22 19:07:53 -0400950 c->recurse (lookupRecord[i].lookupListIndex);
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400951}
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -0400952
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400953static inline bool apply_lookup (hb_apply_context_t *c,
Behdad Esfahbode072c242009-05-18 03:47:31 -0400954 unsigned int count, /* Including the first glyph */
Behdad Esfahbod6b65a762013-10-14 18:51:39 +0200955 unsigned int match_positions[MAX_CONTEXT_LENGTH], /* Including the first glyph */
Behdad Esfahbode072c242009-05-18 03:47:31 -0400956 unsigned int lookupCount,
Behdad Esfahbod6b65a762013-10-14 18:51:39 +0200957 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
958 unsigned int match_length)
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -0400959{
Behdad Esfahbod73c18ae2012-11-23 15:34:11 -0500960 TRACE_APPLY (NULL);
Behdad Esfahbod902cc8a2012-11-23 15:06:59 -0500961
Behdad Esfahbod6b65a762013-10-14 18:51:39 +0200962 hb_buffer_t *buffer = c->buffer;
963 unsigned int end;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -0400964
Behdad Esfahbod6b65a762013-10-14 18:51:39 +0200965 /* All positions are distance from beginning of *output* buffer.
966 * Adjust. */
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400967 {
Behdad Esfahbod6b65a762013-10-14 18:51:39 +0200968 unsigned int bl = buffer->backtrack_len ();
969 end = bl + match_length;
Behdad Esfahbod8751de52013-07-18 16:29:50 -0400970
Behdad Esfahbod6b65a762013-10-14 18:51:39 +0200971 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;
Behdad Esfahbod8820bb22013-02-14 07:41:03 -0500975 }
Behdad Esfahbode73a0c22009-05-18 04:15:25 -0400976
Behdad Esfahbod6b65a762013-10-14 18:51:39 +0200977 for (unsigned int i = 0; i < lookupCount; i++)
978 {
979 unsigned int idx = lookupRecord[i].sequenceIndex;
980 if (idx >= count)
981 continue;
982
983 buffer->move_to (match_positions[idx]);
984
985 unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
986 if (!c->recurse (lookupRecord[i].lookupListIndex))
987 continue;
988
989 unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len ();
990 int delta = new_len - orig_len;
991
992 if (!delta)
993 continue;
994
995 /* Recursed lookup changed buffer len. Adjust. */
996
Behdad Esfahbodb6b304f2014-06-05 17:12:54 -0400997 /* end can't go back past the current match position.
998 * Note: this is only true because we do NOT allow MultipleSubst
999 * with zero sequence len. */
Behdad Esfahbodda720422013-10-17 12:01:50 +02001000 end = MAX ((int) match_positions[idx] + 1, int (end) + delta);
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001001
1002 unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */
1003
1004 if (delta > 0)
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001005 {
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001006 if (unlikely (delta + count > MAX_CONTEXT_LENGTH))
1007 break;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001008 }
1009 else
1010 {
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001011 /* NOTE: delta is negative. */
1012 delta = MAX (delta, (int) next - (int) count);
1013 next -= delta;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001014 }
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001015
1016 /* Shift! */
1017 memmove (match_positions + next + delta, match_positions + next,
1018 (count - next) * sizeof (match_positions[0]));
1019 next += delta;
1020 count += delta;
1021
1022 /* Fill in new entries. */
1023 for (unsigned int j = idx + 1; j < next; j++)
1024 match_positions[j] = match_positions[j - 1] + 1;
1025
1026 /* And fixup the rest. */
1027 for (; next < count; next++)
1028 match_positions[next] += delta;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001029 }
1030
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001031 buffer->move_to (end);
1032
Behdad Esfahbod26166892012-10-29 21:51:56 -07001033 return TRACE_RETURN (true);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001034}
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001035
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04001036
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001037
1038/* Contextual lookups */
1039
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001040struct ContextClosureLookupContext
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001041{
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001042 ContextClosureFuncs funcs;
1043 const void *intersects_data;
1044};
1045
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001046struct ContextCollectGlyphsLookupContext
1047{
1048 ContextCollectGlyphsFuncs funcs;
1049 const void *collect_data;
1050};
1051
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001052struct ContextApplyLookupContext
1053{
1054 ContextApplyFuncs funcs;
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04001055 const void *match_data;
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001056};
1057
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001058static inline void context_closure_lookup (hb_closure_context_t *c,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001059 unsigned int inputCount, /* Including the first glyph (not matched) */
1060 const USHORT input[], /* Array of input values--start with second glyph */
1061 unsigned int lookupCount,
1062 const LookupRecord lookupRecord[],
1063 ContextClosureLookupContext &lookup_context)
1064{
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001065 if (intersects_array (c,
1066 inputCount ? inputCount - 1 : 0, input,
1067 lookup_context.funcs.intersects, lookup_context.intersects_data))
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001068 recurse_lookups (c,
1069 lookupCount, lookupRecord);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001070}
1071
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001072static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
1073 unsigned int inputCount, /* Including the first glyph (not matched) */
1074 const USHORT input[], /* Array of input values--start with second glyph */
1075 unsigned int lookupCount,
1076 const LookupRecord lookupRecord[],
1077 ContextCollectGlyphsLookupContext &lookup_context)
1078{
Behdad Esfahbod83035932012-12-04 17:08:41 -05001079 collect_array (c, c->input,
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001080 inputCount ? inputCount - 1 : 0, input,
1081 lookup_context.funcs.collect, lookup_context.collect_data);
1082 recurse_lookups (c,
1083 lookupCount, lookupRecord);
1084}
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001085
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001086static inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
1087 unsigned int inputCount, /* Including the first glyph (not matched) */
1088 const USHORT input[], /* Array of input values--start with second glyph */
Behdad Esfahbod0beb66e2012-12-05 18:46:04 -05001089 unsigned int lookupCount HB_UNUSED,
1090 const LookupRecord lookupRecord[] HB_UNUSED,
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001091 ContextApplyLookupContext &lookup_context)
1092{
1093 return would_match_input (c,
1094 inputCount, input,
1095 lookup_context.funcs.match, lookup_context.match_data);
1096}
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001097static inline bool context_apply_lookup (hb_apply_context_t *c,
1098 unsigned int inputCount, /* Including the first glyph (not matched) */
1099 const USHORT input[], /* Array of input values--start with second glyph */
1100 unsigned int lookupCount,
1101 const LookupRecord lookupRecord[],
1102 ContextApplyLookupContext &lookup_context)
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001103{
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001104 unsigned int match_length = 0;
1105 unsigned int match_positions[MAX_CONTEXT_LENGTH];
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001106 return match_input (c,
Behdad Esfahbod41697102010-05-05 01:37:58 -04001107 inputCount, input,
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001108 lookup_context.funcs.match, lookup_context.match_data,
1109 &match_length, match_positions)
Behdad Esfahbod5df809b2012-05-13 15:17:51 +02001110 && apply_lookup (c,
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001111 inputCount, match_positions,
1112 lookupCount, lookupRecord,
1113 match_length);
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001114}
1115
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001116struct Rule
1117{
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001118 inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001119 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001120 TRACE_CLOSURE (this);
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001121 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001122 context_closure_lookup (c,
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001123 inputCount, inputZ,
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001124 lookupCount, lookupRecord,
1125 lookup_context);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001126 }
1127
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001128 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const
1129 {
1130 TRACE_COLLECT_GLYPHS (this);
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001131 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001132 context_collect_glyphs_lookup (c,
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001133 inputCount, inputZ,
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001134 lookupCount, lookupRecord,
1135 lookup_context);
1136 }
1137
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001138 inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
1139 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001140 TRACE_WOULD_APPLY (this);
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001141 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
1142 return TRACE_RETURN (context_would_apply_lookup (c, inputCount, inputZ, lookupCount, lookupRecord, lookup_context));
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001143 }
1144
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001145 inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001146 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001147 TRACE_APPLY (this);
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001148 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
1149 return TRACE_RETURN (context_apply_lookup (c, inputCount, inputZ, lookupCount, lookupRecord, lookup_context));
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001150 }
1151
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001152 public:
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001153 inline bool sanitize (hb_sanitize_context_t *c) const
1154 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001155 TRACE_SANITIZE (this);
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001156 return inputCount.sanitize (c)
1157 && lookupCount.sanitize (c)
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001158 && c->check_range (inputZ,
1159 inputZ[0].static_size * inputCount
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001160 + lookupRecordX[0].static_size * lookupCount);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001161 }
1162
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001163 protected:
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001164 USHORT inputCount; /* Total number of glyphs in input
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001165 * glyph sequence--includes the first
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001166 * glyph */
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001167 USHORT lookupCount; /* Number of LookupRecords */
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001168 USHORT inputZ[VAR]; /* Array of match inputs--start with
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001169 * second glyph */
Behdad Esfahbodd3480ba2009-11-03 10:47:29 -05001170 LookupRecord lookupRecordX[VAR]; /* Array of LookupRecords--in
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001171 * design order */
Behdad Esfahbod569da922010-05-10 16:38:32 -04001172 public:
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001173 DEFINE_SIZE_ARRAY2 (4, inputZ, lookupRecordX);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001174};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001175
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001176struct RuleSet
1177{
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001178 inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001179 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001180 TRACE_CLOSURE (this);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001181 unsigned int num_rules = rule.len;
1182 for (unsigned int i = 0; i < num_rules; i++)
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001183 (this+rule[i]).closure (c, lookup_context);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001184 }
1185
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001186 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const
1187 {
1188 TRACE_COLLECT_GLYPHS (this);
1189 unsigned int num_rules = rule.len;
1190 for (unsigned int i = 0; i < num_rules; i++)
1191 (this+rule[i]).collect_glyphs (c, lookup_context);
1192 }
1193
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001194 inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
1195 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001196 TRACE_WOULD_APPLY (this);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001197 unsigned int num_rules = rule.len;
1198 for (unsigned int i = 0; i < num_rules; i++)
1199 {
1200 if ((this+rule[i]).would_apply (c, lookup_context))
1201 return TRACE_RETURN (true);
1202 }
1203 return TRACE_RETURN (false);
1204 }
1205
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001206 inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001207 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001208 TRACE_APPLY (this);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001209 unsigned int num_rules = rule.len;
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001210 for (unsigned int i = 0; i < num_rules; i++)
1211 {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001212 if ((this+rule[i]).apply (c, lookup_context))
Behdad Esfahbodacea1832012-05-11 02:33:11 +02001213 return TRACE_RETURN (true);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001214 }
Behdad Esfahbodacea1832012-05-11 02:33:11 +02001215 return TRACE_RETURN (false);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001216 }
1217
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001218 inline bool sanitize (hb_sanitize_context_t *c) const
1219 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001220 TRACE_SANITIZE (this);
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02001221 return TRACE_RETURN (rule.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001222 }
1223
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001224 protected:
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001225 OffsetArrayOf<Rule>
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001226 rule; /* Array of Rule tables
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001227 * ordered by preference */
Behdad Esfahboded074222010-05-10 18:08:46 -04001228 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04001229 DEFINE_SIZE_ARRAY (2, rule);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001230};
1231
1232
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001233struct ContextFormat1
1234{
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001235 inline void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001236 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001237 TRACE_CLOSURE (this);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001238
1239 const Coverage &cov = (this+coverage);
1240
1241 struct ContextClosureLookupContext lookup_context = {
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001242 {intersects_glyph},
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001243 NULL
1244 };
1245
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001246 unsigned int count = ruleSet.len;
1247 for (unsigned int i = 0; i < count; i++)
1248 if (cov.intersects_coverage (c->glyphs, i)) {
1249 const RuleSet &rule_set = this+ruleSet[i];
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001250 rule_set.closure (c, lookup_context);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001251 }
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001252 }
1253
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001254 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1255 {
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001256 TRACE_COLLECT_GLYPHS (this);
Behdad Esfahbod83035932012-12-04 17:08:41 -05001257 (this+coverage).add_coverage (c->input);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001258
1259 struct ContextCollectGlyphsLookupContext lookup_context = {
1260 {collect_glyph},
1261 NULL
1262 };
1263
1264 unsigned int count = ruleSet.len;
1265 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001266 (this+ruleSet[i]).collect_glyphs (c, lookup_context);
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001267 }
1268
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001269 inline bool would_apply (hb_would_apply_context_t *c) const
1270 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001271 TRACE_WOULD_APPLY (this);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001272
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05001273 const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001274 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001275 {match_glyph},
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001276 NULL
1277 };
1278 return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
1279 }
1280
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001281 inline const Coverage &get_coverage (void) const
1282 {
1283 return this+coverage;
1284 }
1285
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001286 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001287 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001288 TRACE_APPLY (this);
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05001289 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -04001290 if (likely (index == NOT_COVERED))
Behdad Esfahbodacea1832012-05-11 02:33:11 +02001291 return TRACE_RETURN (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04001292
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001293 const RuleSet &rule_set = this+ruleSet[index];
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001294 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001295 {match_glyph},
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001296 NULL
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001297 };
Behdad Esfahbodacea1832012-05-11 02:33:11 +02001298 return TRACE_RETURN (rule_set.apply (c, lookup_context));
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001299 }
1300
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001301 inline bool sanitize (hb_sanitize_context_t *c) const
1302 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001303 TRACE_SANITIZE (this);
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02001304 return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001305 }
1306
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001307 protected:
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001308 USHORT format; /* Format identifier--format = 1 */
1309 OffsetTo<Coverage>
1310 coverage; /* Offset to Coverage table--from
1311 * beginning of table */
1312 OffsetArrayOf<RuleSet>
1313 ruleSet; /* Array of RuleSet tables
1314 * ordered by Coverage Index */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04001315 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04001316 DEFINE_SIZE_ARRAY (6, ruleSet);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001317};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001318
1319
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001320struct ContextFormat2
1321{
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001322 inline void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001323 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001324 TRACE_CLOSURE (this);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001325 if (!(this+coverage).intersects (c->glyphs))
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001326 return;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001327
1328 const ClassDef &class_def = this+classDef;
1329
1330 struct ContextClosureLookupContext lookup_context = {
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001331 {intersects_class},
Behdad Esfahbod11fba792013-01-02 23:36:37 -06001332 &class_def
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001333 };
1334
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001335 unsigned int count = ruleSet.len;
1336 for (unsigned int i = 0; i < count; i++)
1337 if (class_def.intersects_class (c->glyphs, i)) {
1338 const RuleSet &rule_set = this+ruleSet[i];
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001339 rule_set.closure (c, lookup_context);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001340 }
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001341 }
1342
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001343 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1344 {
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001345 TRACE_COLLECT_GLYPHS (this);
Behdad Esfahbod83035932012-12-04 17:08:41 -05001346 (this+coverage).add_coverage (c->input);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001347
Behdad Esfahbod11fba792013-01-02 23:36:37 -06001348 const ClassDef &class_def = this+classDef;
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001349 struct ContextCollectGlyphsLookupContext lookup_context = {
1350 {collect_class},
Behdad Esfahbod11fba792013-01-02 23:36:37 -06001351 &class_def
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001352 };
1353
1354 unsigned int count = ruleSet.len;
1355 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001356 (this+ruleSet[i]).collect_glyphs (c, lookup_context);
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001357 }
1358
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001359 inline bool would_apply (hb_would_apply_context_t *c) const
1360 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001361 TRACE_WOULD_APPLY (this);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001362
1363 const ClassDef &class_def = this+classDef;
Behdad Esfahbod2dc11412012-11-24 19:16:34 -05001364 unsigned int index = class_def.get_class (c->glyphs[0]);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001365 const RuleSet &rule_set = this+ruleSet[index];
1366 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001367 {match_class},
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001368 &class_def
1369 };
1370 return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
1371 }
1372
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001373 inline const Coverage &get_coverage (void) const
1374 {
1375 return this+coverage;
1376 }
1377
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001378 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001379 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001380 TRACE_APPLY (this);
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05001381 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodacea1832012-05-11 02:33:11 +02001382 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04001383
1384 const ClassDef &class_def = this+classDef;
Behdad Esfahbod2dc11412012-11-24 19:16:34 -05001385 index = class_def.get_class (c->buffer->cur().codepoint);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001386 const RuleSet &rule_set = this+ruleSet[index];
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001387 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001388 {match_class},
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04001389 &class_def
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001390 };
Behdad Esfahbodacea1832012-05-11 02:33:11 +02001391 return TRACE_RETURN (rule_set.apply (c, lookup_context));
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001392 }
1393
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001394 inline bool sanitize (hb_sanitize_context_t *c) const
1395 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001396 TRACE_SANITIZE (this);
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02001397 return TRACE_RETURN (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001398 }
1399
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001400 protected:
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001401 USHORT format; /* Format identifier--format = 2 */
1402 OffsetTo<Coverage>
1403 coverage; /* Offset to Coverage table--from
1404 * beginning of table */
1405 OffsetTo<ClassDef>
1406 classDef; /* Offset to glyph ClassDef table--from
1407 * beginning of table */
1408 OffsetArrayOf<RuleSet>
1409 ruleSet; /* Array of RuleSet tables
1410 * ordered by class */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04001411 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04001412 DEFINE_SIZE_ARRAY (8, ruleSet);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001413};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001414
1415
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001416struct ContextFormat3
1417{
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001418 inline void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001419 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001420 TRACE_CLOSURE (this);
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001421 if (!(this+coverageZ[0]).intersects (c->glyphs))
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001422 return;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001423
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001424 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001425 struct ContextClosureLookupContext lookup_context = {
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001426 {intersects_coverage},
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001427 this
1428 };
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001429 context_closure_lookup (c,
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001430 glyphCount, (const USHORT *) (coverageZ + 1),
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001431 lookupCount, lookupRecord,
1432 lookup_context);
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001433 }
1434
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001435 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1436 {
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001437 TRACE_COLLECT_GLYPHS (this);
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001438 (this+coverageZ[0]).add_coverage (c->input);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001439
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001440 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001441 struct ContextCollectGlyphsLookupContext lookup_context = {
1442 {collect_coverage},
Behdad Esfahbode75943d2012-11-30 08:38:24 +02001443 this
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001444 };
1445
1446 context_collect_glyphs_lookup (c,
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001447 glyphCount, (const USHORT *) (coverageZ + 1),
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001448 lookupCount, lookupRecord,
1449 lookup_context);
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001450 }
1451
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001452 inline bool would_apply (hb_would_apply_context_t *c) const
1453 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001454 TRACE_WOULD_APPLY (this);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001455
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001456 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001457 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001458 {match_coverage},
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001459 this
1460 };
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001461 return TRACE_RETURN (context_would_apply_lookup (c, glyphCount, (const USHORT *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001462 }
1463
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001464 inline const Coverage &get_coverage (void) const
1465 {
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001466 return this+coverageZ[0];
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001467 }
1468
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001469 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001470 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001471 TRACE_APPLY (this);
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001472 unsigned int index = (this+coverageZ[0]).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodacea1832012-05-11 02:33:11 +02001473 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04001474
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001475 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001476 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001477 {match_coverage},
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04001478 this
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001479 };
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001480 return TRACE_RETURN (context_apply_lookup (c, glyphCount, (const USHORT *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001481 }
1482
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001483 inline bool sanitize (hb_sanitize_context_t *c) const
1484 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001485 TRACE_SANITIZE (this);
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02001486 if (!c->check_struct (this)) return TRACE_RETURN (false);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001487 unsigned int count = glyphCount;
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001488 if (!count) return TRACE_RETURN (false); /* We want to access coverageZ[0] freely. */
1489 if (!c->check_array (coverageZ, coverageZ[0].static_size, count)) return TRACE_RETURN (false);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001490 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001491 if (!coverageZ[i].sanitize (c, this)) return TRACE_RETURN (false);
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001492 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * count);
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02001493 return TRACE_RETURN (c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001494 }
1495
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001496 protected:
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001497 USHORT format; /* Format identifier--format = 3 */
1498 USHORT glyphCount; /* Number of glyphs in the input glyph
1499 * sequence */
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001500 USHORT lookupCount; /* Number of LookupRecords */
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04001501 OffsetTo<Coverage>
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001502 coverageZ[VAR]; /* Array of offsets to Coverage
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04001503 * table in glyph sequence order */
Behdad Esfahbodd3480ba2009-11-03 10:47:29 -05001504 LookupRecord lookupRecordX[VAR]; /* Array of LookupRecords--in
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001505 * design order */
Behdad Esfahbod569da922010-05-10 16:38:32 -04001506 public:
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001507 DEFINE_SIZE_ARRAY2 (6, coverageZ, lookupRecordX);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001508};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001509
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001510struct Context
1511{
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001512 template <typename context_t>
Behdad Esfahbod9c5a9ee2013-03-09 01:55:04 -05001513 inline typename context_t::return_t dispatch (context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001514 {
Behdad Esfahbod00f6a8e2014-12-12 20:36:49 -08001515 TRACE_DISPATCH (this, u.format);
Behdad Esfahbod50b8dc72015-02-17 18:14:17 +03001516 if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001517 switch (u.format) {
Behdad Esfahbod9c5a9ee2013-03-09 01:55:04 -05001518 case 1: return TRACE_RETURN (c->dispatch (u.format1));
1519 case 2: return TRACE_RETURN (c->dispatch (u.format2));
1520 case 3: return TRACE_RETURN (c->dispatch (u.format3));
Behdad Esfahbodf48ec0e2012-11-23 17:23:41 -05001521 default:return TRACE_RETURN (c->default_return_value ());
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001522 }
1523 }
1524
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001525 inline bool sanitize (hb_sanitize_context_t *c) const
1526 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001527 TRACE_SANITIZE (this);
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02001528 if (!u.format.sanitize (c)) return TRACE_RETURN (false);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001529 switch (u.format) {
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02001530 case 1: return TRACE_RETURN (u.format1.sanitize (c));
1531 case 2: return TRACE_RETURN (u.format2.sanitize (c));
1532 case 3: return TRACE_RETURN (u.format3.sanitize (c));
1533 default:return TRACE_RETURN (true);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001534 }
1535 }
1536
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001537 protected:
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001538 union {
Behdad Esfahbodf8dc67b2009-05-17 19:47:54 -04001539 USHORT format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -04001540 ContextFormat1 format1;
1541 ContextFormat2 format2;
1542 ContextFormat3 format3;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001543 } u;
1544};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001545
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001546
1547/* Chaining Contextual lookups */
1548
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001549struct ChainContextClosureLookupContext
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001550{
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001551 ContextClosureFuncs funcs;
1552 const void *intersects_data[3];
1553};
1554
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001555struct ChainContextCollectGlyphsLookupContext
1556{
1557 ContextCollectGlyphsFuncs funcs;
1558 const void *collect_data[3];
1559};
1560
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001561struct ChainContextApplyLookupContext
1562{
1563 ContextApplyFuncs funcs;
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04001564 const void *match_data[3];
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001565};
1566
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001567static inline void chain_context_closure_lookup (hb_closure_context_t *c,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001568 unsigned int backtrackCount,
1569 const USHORT backtrack[],
1570 unsigned int inputCount, /* Including the first glyph (not matched) */
1571 const USHORT input[], /* Array of input values--start with second glyph */
1572 unsigned int lookaheadCount,
1573 const USHORT lookahead[],
1574 unsigned int lookupCount,
1575 const LookupRecord lookupRecord[],
1576 ChainContextClosureLookupContext &lookup_context)
1577{
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001578 if (intersects_array (c,
1579 backtrackCount, backtrack,
1580 lookup_context.funcs.intersects, lookup_context.intersects_data[0])
1581 && intersects_array (c,
1582 inputCount ? inputCount - 1 : 0, input,
1583 lookup_context.funcs.intersects, lookup_context.intersects_data[1])
Behdad Esfahbod74439d02013-07-22 19:02:29 -04001584 && intersects_array (c,
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001585 lookaheadCount, lookahead,
1586 lookup_context.funcs.intersects, lookup_context.intersects_data[2]))
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001587 recurse_lookups (c,
1588 lookupCount, lookupRecord);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001589}
1590
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001591static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
1592 unsigned int backtrackCount,
1593 const USHORT backtrack[],
1594 unsigned int inputCount, /* Including the first glyph (not matched) */
1595 const USHORT input[], /* Array of input values--start with second glyph */
1596 unsigned int lookaheadCount,
1597 const USHORT lookahead[],
1598 unsigned int lookupCount,
1599 const LookupRecord lookupRecord[],
1600 ChainContextCollectGlyphsLookupContext &lookup_context)
1601{
Behdad Esfahbod83035932012-12-04 17:08:41 -05001602 collect_array (c, c->before,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001603 backtrackCount, backtrack,
1604 lookup_context.funcs.collect, lookup_context.collect_data[0]);
Behdad Esfahbod83035932012-12-04 17:08:41 -05001605 collect_array (c, c->input,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001606 inputCount ? inputCount - 1 : 0, input,
1607 lookup_context.funcs.collect, lookup_context.collect_data[1]);
Behdad Esfahbod83035932012-12-04 17:08:41 -05001608 collect_array (c, c->after,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001609 lookaheadCount, lookahead,
1610 lookup_context.funcs.collect, lookup_context.collect_data[2]);
1611 recurse_lookups (c,
1612 lookupCount, lookupRecord);
1613}
1614
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001615static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c,
1616 unsigned int backtrackCount,
Behdad Esfahbod0beb66e2012-12-05 18:46:04 -05001617 const USHORT backtrack[] HB_UNUSED,
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001618 unsigned int inputCount, /* Including the first glyph (not matched) */
1619 const USHORT input[], /* Array of input values--start with second glyph */
1620 unsigned int lookaheadCount,
Behdad Esfahbod0beb66e2012-12-05 18:46:04 -05001621 const USHORT lookahead[] HB_UNUSED,
1622 unsigned int lookupCount HB_UNUSED,
1623 const LookupRecord lookupRecord[] HB_UNUSED,
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001624 ChainContextApplyLookupContext &lookup_context)
1625{
Behdad Esfahbodd9b204d2012-08-23 16:22:28 -04001626 return (c->zero_context ? !backtrackCount && !lookaheadCount : true)
Behdad Esfahbod1f2bb172012-08-23 16:10:37 -04001627 && would_match_input (c,
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001628 inputCount, input,
1629 lookup_context.funcs.match, lookup_context.match_data[1]);
1630}
1631
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001632static inline bool chain_context_apply_lookup (hb_apply_context_t *c,
1633 unsigned int backtrackCount,
1634 const USHORT backtrack[],
1635 unsigned int inputCount, /* Including the first glyph (not matched) */
1636 const USHORT input[], /* Array of input values--start with second glyph */
1637 unsigned int lookaheadCount,
1638 const USHORT lookahead[],
1639 unsigned int lookupCount,
1640 const LookupRecord lookupRecord[],
1641 ChainContextApplyLookupContext &lookup_context)
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04001642{
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001643 unsigned int match_length = 0;
1644 unsigned int match_positions[MAX_CONTEXT_LENGTH];
Behdad Esfahbodf19e0b02012-06-09 02:26:57 -04001645 return match_input (c,
Behdad Esfahbod41697102010-05-05 01:37:58 -04001646 inputCount, input,
1647 lookup_context.funcs.match, lookup_context.match_data[1],
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001648 &match_length, match_positions)
Behdad Esfahbodf19e0b02012-06-09 02:26:57 -04001649 && match_backtrack (c,
1650 backtrackCount, backtrack,
1651 lookup_context.funcs.match, lookup_context.match_data[0])
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001652 && match_lookahead (c,
Behdad Esfahbod41697102010-05-05 01:37:58 -04001653 lookaheadCount, lookahead,
1654 lookup_context.funcs.match, lookup_context.match_data[2],
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001655 match_length)
Behdad Esfahbod5df809b2012-05-13 15:17:51 +02001656 && apply_lookup (c,
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001657 inputCount, match_positions,
1658 lookupCount, lookupRecord,
1659 match_length);
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04001660}
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001661
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001662struct ChainRule
1663{
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001664 inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001665 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001666 TRACE_CLOSURE (this);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001667 const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
1668 const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
1669 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001670 chain_context_closure_lookup (c,
1671 backtrack.len, backtrack.array,
1672 input.len, input.array,
1673 lookahead.len, lookahead.array,
1674 lookup.len, lookup.array,
1675 lookup_context);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001676 }
1677
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001678 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
1679 {
1680 TRACE_COLLECT_GLYPHS (this);
1681 const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
1682 const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
1683 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1684 chain_context_collect_glyphs_lookup (c,
1685 backtrack.len, backtrack.array,
1686 input.len, input.array,
1687 lookahead.len, lookahead.array,
1688 lookup.len, lookup.array,
1689 lookup_context);
1690 }
1691
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001692 inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
1693 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001694 TRACE_WOULD_APPLY (this);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001695 const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
1696 const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
1697 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1698 return TRACE_RETURN (chain_context_would_apply_lookup (c,
1699 backtrack.len, backtrack.array,
1700 input.len, input.array,
1701 lookahead.len, lookahead.array, lookup.len,
1702 lookup.array, lookup_context));
1703 }
1704
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001705 inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001706 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001707 TRACE_APPLY (this);
Behdad Esfahbode961c862010-04-21 15:56:11 -04001708 const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
1709 const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
1710 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
Behdad Esfahbodacea1832012-05-11 02:33:11 +02001711 return TRACE_RETURN (chain_context_apply_lookup (c,
1712 backtrack.len, backtrack.array,
1713 input.len, input.array,
1714 lookahead.len, lookahead.array, lookup.len,
1715 lookup.array, lookup_context));
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04001716 }
1717
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001718 inline bool sanitize (hb_sanitize_context_t *c) const
1719 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001720 TRACE_SANITIZE (this);
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02001721 if (!backtrack.sanitize (c)) return TRACE_RETURN (false);
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001722 const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02001723 if (!input.sanitize (c)) return TRACE_RETURN (false);
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001724 const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02001725 if (!lookahead.sanitize (c)) return TRACE_RETURN (false);
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001726 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02001727 return TRACE_RETURN (lookup.sanitize (c));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001728 }
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001729
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001730 protected:
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04001731 ArrayOf<USHORT>
1732 backtrack; /* Array of backtracking values
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001733 * (to be matched before the input
1734 * sequence) */
Behdad Esfahbode8cbaaf2009-05-18 02:03:58 -04001735 HeadlessArrayOf<USHORT>
1736 inputX; /* Array of input values (start with
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001737 * second glyph) */
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04001738 ArrayOf<USHORT>
1739 lookaheadX; /* Array of lookahead values's (to be
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001740 * matched after the input sequence) */
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04001741 ArrayOf<LookupRecord>
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04001742 lookupX; /* Array of LookupRecords--in
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001743 * design order) */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04001744 public:
Behdad Esfahbodbea34c72010-05-10 17:28:16 -04001745 DEFINE_SIZE_MIN (8);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001746};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001747
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001748struct ChainRuleSet
1749{
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001750 inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001751 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001752 TRACE_CLOSURE (this);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001753 unsigned int num_rules = rule.len;
1754 for (unsigned int i = 0; i < num_rules; i++)
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001755 (this+rule[i]).closure (c, lookup_context);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001756 }
1757
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001758 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
1759 {
1760 TRACE_COLLECT_GLYPHS (this);
1761 unsigned int num_rules = rule.len;
1762 for (unsigned int i = 0; i < num_rules; i++)
1763 (this+rule[i]).collect_glyphs (c, lookup_context);
1764 }
1765
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001766 inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
1767 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001768 TRACE_WOULD_APPLY (this);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001769 unsigned int num_rules = rule.len;
1770 for (unsigned int i = 0; i < num_rules; i++)
1771 if ((this+rule[i]).would_apply (c, lookup_context))
1772 return TRACE_RETURN (true);
1773
1774 return TRACE_RETURN (false);
1775 }
1776
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001777 inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001778 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001779 TRACE_APPLY (this);
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001780 unsigned int num_rules = rule.len;
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001781 for (unsigned int i = 0; i < num_rules; i++)
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001782 if ((this+rule[i]).apply (c, lookup_context))
Behdad Esfahbodacea1832012-05-11 02:33:11 +02001783 return TRACE_RETURN (true);
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001784
Behdad Esfahbodacea1832012-05-11 02:33:11 +02001785 return TRACE_RETURN (false);
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001786 }
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001787
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001788 inline bool sanitize (hb_sanitize_context_t *c) const
1789 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001790 TRACE_SANITIZE (this);
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02001791 return TRACE_RETURN (rule.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001792 }
1793
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001794 protected:
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001795 OffsetArrayOf<ChainRule>
1796 rule; /* Array of ChainRule tables
1797 * ordered by preference */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04001798 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04001799 DEFINE_SIZE_ARRAY (2, rule);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001800};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001801
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001802struct ChainContextFormat1
1803{
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001804 inline void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001805 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001806 TRACE_CLOSURE (this);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001807 const Coverage &cov = (this+coverage);
1808
1809 struct ChainContextClosureLookupContext lookup_context = {
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001810 {intersects_glyph},
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001811 {NULL, NULL, NULL}
1812 };
1813
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001814 unsigned int count = ruleSet.len;
1815 for (unsigned int i = 0; i < count; i++)
1816 if (cov.intersects_coverage (c->glyphs, i)) {
1817 const ChainRuleSet &rule_set = this+ruleSet[i];
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001818 rule_set.closure (c, lookup_context);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001819 }
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001820 }
1821
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001822 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1823 {
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001824 TRACE_COLLECT_GLYPHS (this);
Behdad Esfahbod83035932012-12-04 17:08:41 -05001825 (this+coverage).add_coverage (c->input);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001826
1827 struct ChainContextCollectGlyphsLookupContext lookup_context = {
1828 {collect_glyph},
1829 {NULL, NULL, NULL}
1830 };
1831
1832 unsigned int count = ruleSet.len;
1833 for (unsigned int i = 0; i < count; i++)
1834 (this+ruleSet[i]).collect_glyphs (c, lookup_context);
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001835 }
1836
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001837 inline bool would_apply (hb_would_apply_context_t *c) const
1838 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001839 TRACE_WOULD_APPLY (this);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001840
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05001841 const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001842 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001843 {match_glyph},
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001844 {NULL, NULL, NULL}
1845 };
1846 return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
1847 }
1848
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001849 inline const Coverage &get_coverage (void) const
1850 {
1851 return this+coverage;
1852 }
1853
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001854 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001855 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001856 TRACE_APPLY (this);
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05001857 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodacea1832012-05-11 02:33:11 +02001858 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04001859
1860 const ChainRuleSet &rule_set = this+ruleSet[index];
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001861 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001862 {match_glyph},
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04001863 {NULL, NULL, NULL}
1864 };
Behdad Esfahbodacea1832012-05-11 02:33:11 +02001865 return TRACE_RETURN (rule_set.apply (c, lookup_context));
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001866 }
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001867
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001868 inline bool sanitize (hb_sanitize_context_t *c) const
1869 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001870 TRACE_SANITIZE (this);
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02001871 return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001872 }
1873
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001874 protected:
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001875 USHORT format; /* Format identifier--format = 1 */
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001876 OffsetTo<Coverage>
1877 coverage; /* Offset to Coverage table--from
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001878 * beginning of table */
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04001879 OffsetArrayOf<ChainRuleSet>
1880 ruleSet; /* Array of ChainRuleSet tables
1881 * ordered by Coverage Index */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04001882 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04001883 DEFINE_SIZE_ARRAY (6, ruleSet);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001884};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001885
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001886struct ChainContextFormat2
1887{
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001888 inline void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001889 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001890 TRACE_CLOSURE (this);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001891 if (!(this+coverage).intersects (c->glyphs))
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001892 return;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001893
1894 const ClassDef &backtrack_class_def = this+backtrackClassDef;
1895 const ClassDef &input_class_def = this+inputClassDef;
1896 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
1897
1898 struct ChainContextClosureLookupContext lookup_context = {
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001899 {intersects_class},
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001900 {&backtrack_class_def,
1901 &input_class_def,
1902 &lookahead_class_def}
1903 };
1904
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001905 unsigned int count = ruleSet.len;
1906 for (unsigned int i = 0; i < count; i++)
1907 if (input_class_def.intersects_class (c->glyphs, i)) {
1908 const ChainRuleSet &rule_set = this+ruleSet[i];
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001909 rule_set.closure (c, lookup_context);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001910 }
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001911 }
1912
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001913 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1914 {
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001915 TRACE_COLLECT_GLYPHS (this);
Behdad Esfahbod83035932012-12-04 17:08:41 -05001916 (this+coverage).add_coverage (c->input);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001917
Behdad Esfahbod11fba792013-01-02 23:36:37 -06001918 const ClassDef &backtrack_class_def = this+backtrackClassDef;
1919 const ClassDef &input_class_def = this+inputClassDef;
1920 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
1921
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001922 struct ChainContextCollectGlyphsLookupContext lookup_context = {
1923 {collect_class},
Behdad Esfahbod11fba792013-01-02 23:36:37 -06001924 {&backtrack_class_def,
1925 &input_class_def,
1926 &lookahead_class_def}
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001927 };
1928
1929 unsigned int count = ruleSet.len;
1930 for (unsigned int i = 0; i < count; i++)
1931 (this+ruleSet[i]).collect_glyphs (c, lookup_context);
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001932 }
1933
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001934 inline bool would_apply (hb_would_apply_context_t *c) const
1935 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001936 TRACE_WOULD_APPLY (this);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001937
Behdad Esfahbod11fba792013-01-02 23:36:37 -06001938 const ClassDef &backtrack_class_def = this+backtrackClassDef;
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001939 const ClassDef &input_class_def = this+inputClassDef;
Behdad Esfahbod11fba792013-01-02 23:36:37 -06001940 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001941
Behdad Esfahbod2dc11412012-11-24 19:16:34 -05001942 unsigned int index = input_class_def.get_class (c->glyphs[0]);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001943 const ChainRuleSet &rule_set = this+ruleSet[index];
1944 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001945 {match_class},
Behdad Esfahbod11fba792013-01-02 23:36:37 -06001946 {&backtrack_class_def,
1947 &input_class_def,
1948 &lookahead_class_def}
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001949 };
1950 return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
1951 }
1952
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001953 inline const Coverage &get_coverage (void) const
1954 {
1955 return this+coverage;
1956 }
1957
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001958 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001959 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001960 TRACE_APPLY (this);
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05001961 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodacea1832012-05-11 02:33:11 +02001962 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04001963
1964 const ClassDef &backtrack_class_def = this+backtrackClassDef;
1965 const ClassDef &input_class_def = this+inputClassDef;
1966 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
1967
Behdad Esfahbod2dc11412012-11-24 19:16:34 -05001968 index = input_class_def.get_class (c->buffer->cur().codepoint);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04001969 const ChainRuleSet &rule_set = this+ruleSet[index];
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001970 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001971 {match_class},
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04001972 {&backtrack_class_def,
1973 &input_class_def,
1974 &lookahead_class_def}
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04001975 };
Behdad Esfahbodacea1832012-05-11 02:33:11 +02001976 return TRACE_RETURN (rule_set.apply (c, lookup_context));
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001977 }
1978
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001979 inline bool sanitize (hb_sanitize_context_t *c) const
1980 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001981 TRACE_SANITIZE (this);
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02001982 return TRACE_RETURN (coverage.sanitize (c, this) && backtrackClassDef.sanitize (c, this) &&
1983 inputClassDef.sanitize (c, this) && lookaheadClassDef.sanitize (c, this) &&
1984 ruleSet.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001985 }
1986
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001987 protected:
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001988 USHORT format; /* Format identifier--format = 2 */
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04001989 OffsetTo<Coverage>
1990 coverage; /* Offset to Coverage table--from
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001991 * beginning of table */
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04001992 OffsetTo<ClassDef>
1993 backtrackClassDef; /* Offset to glyph ClassDef table
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001994 * containing backtrack sequence
1995 * data--from beginning of table */
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04001996 OffsetTo<ClassDef>
1997 inputClassDef; /* Offset to glyph ClassDef
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001998 * table containing input sequence
1999 * data--from beginning of table */
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002000 OffsetTo<ClassDef>
2001 lookaheadClassDef; /* Offset to glyph ClassDef table
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002002 * containing lookahead sequence
2003 * data--from beginning of table */
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002004 OffsetArrayOf<ChainRuleSet>
2005 ruleSet; /* Array of ChainRuleSet tables
2006 * ordered by class */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04002007 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04002008 DEFINE_SIZE_ARRAY (12, ruleSet);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002009};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002010
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002011struct ChainContextFormat3
2012{
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002013 inline void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002014 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002015 TRACE_CLOSURE (this);
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002016 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2017
2018 if (!(this+input[0]).intersects (c->glyphs))
2019 return;
2020
2021 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2022 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2023 struct ChainContextClosureLookupContext lookup_context = {
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002024 {intersects_coverage},
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002025 {this, this, this}
2026 };
2027 chain_context_closure_lookup (c,
2028 backtrack.len, (const USHORT *) backtrack.array,
2029 input.len, (const USHORT *) input.array + 1,
2030 lookahead.len, (const USHORT *) lookahead.array,
2031 lookup.len, lookup.array,
2032 lookup_context);
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002033 }
2034
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002035 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
2036 {
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002037 TRACE_COLLECT_GLYPHS (this);
2038 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2039
Behdad Esfahbod83035932012-12-04 17:08:41 -05002040 (this+input[0]).add_coverage (c->input);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002041
2042 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2043 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2044 struct ChainContextCollectGlyphsLookupContext lookup_context = {
2045 {collect_coverage},
2046 {this, this, this}
2047 };
2048 chain_context_collect_glyphs_lookup (c,
2049 backtrack.len, (const USHORT *) backtrack.array,
2050 input.len, (const USHORT *) input.array + 1,
2051 lookahead.len, (const USHORT *) lookahead.array,
2052 lookup.len, lookup.array,
2053 lookup_context);
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002054 }
2055
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002056 inline bool would_apply (hb_would_apply_context_t *c) const
2057 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002058 TRACE_WOULD_APPLY (this);
Behdad Esfahbode6f74792012-07-28 18:34:58 -04002059
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002060 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002061 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2062 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2063 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002064 {match_coverage},
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002065 {this, this, this}
2066 };
2067 return TRACE_RETURN (chain_context_would_apply_lookup (c,
2068 backtrack.len, (const USHORT *) backtrack.array,
2069 input.len, (const USHORT *) input.array + 1,
2070 lookahead.len, (const USHORT *) lookahead.array,
2071 lookup.len, lookup.array, lookup_context));
2072 }
2073
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002074 inline const Coverage &get_coverage (void) const
2075 {
2076 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2077 return this+input[0];
2078 }
2079
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002080 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002081 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002082 TRACE_APPLY (this);
Behdad Esfahbode961c862010-04-21 15:56:11 -04002083 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04002084
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05002085 unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodacea1832012-05-11 02:33:11 +02002086 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002087
Behdad Esfahbode961c862010-04-21 15:56:11 -04002088 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2089 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002090 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002091 {match_coverage},
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04002092 {this, this, this}
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04002093 };
Behdad Esfahbodacea1832012-05-11 02:33:11 +02002094 return TRACE_RETURN (chain_context_apply_lookup (c,
2095 backtrack.len, (const USHORT *) backtrack.array,
2096 input.len, (const USHORT *) input.array + 1,
2097 lookahead.len, (const USHORT *) lookahead.array,
2098 lookup.len, lookup.array, lookup_context));
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002099 }
2100
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002101 inline bool sanitize (hb_sanitize_context_t *c) const
2102 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002103 TRACE_SANITIZE (this);
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02002104 if (!backtrack.sanitize (c, this)) return TRACE_RETURN (false);
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002105 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02002106 if (!input.sanitize (c, this)) return TRACE_RETURN (false);
Behdad Esfahbod9df0a522014-12-12 20:54:28 -08002107 if (!input.len) return TRACE_RETURN (false); /* To be consistent with Context. */
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002108 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02002109 if (!lookahead.sanitize (c, this)) return TRACE_RETURN (false);
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002110 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02002111 return TRACE_RETURN (lookup.sanitize (c));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002112 }
2113
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002114 protected:
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002115 USHORT format; /* Format identifier--format = 3 */
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04002116 OffsetArrayOf<Coverage>
Behdad Esfahbod13ed4402009-05-18 02:14:37 -04002117 backtrack; /* Array of coverage tables
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002118 * in backtracking sequence, in glyph
2119 * sequence order */
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04002120 OffsetArrayOf<Coverage>
Behdad Esfahbod13ed4402009-05-18 02:14:37 -04002121 inputX ; /* Array of coverage
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002122 * tables in input sequence, in glyph
2123 * sequence order */
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04002124 OffsetArrayOf<Coverage>
Behdad Esfahbod13ed4402009-05-18 02:14:37 -04002125 lookaheadX; /* Array of coverage tables
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002126 * in lookahead sequence, in glyph
2127 * sequence order */
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04002128 ArrayOf<LookupRecord>
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04002129 lookupX; /* Array of LookupRecords--in
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04002130 * design order) */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04002131 public:
Behdad Esfahbodbea34c72010-05-10 17:28:16 -04002132 DEFINE_SIZE_MIN (10);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002133};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002134
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002135struct ChainContext
2136{
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002137 template <typename context_t>
Behdad Esfahbod9c5a9ee2013-03-09 01:55:04 -05002138 inline typename context_t::return_t dispatch (context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002139 {
Behdad Esfahbod00f6a8e2014-12-12 20:36:49 -08002140 TRACE_DISPATCH (this, u.format);
Behdad Esfahbod50b8dc72015-02-17 18:14:17 +03002141 if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002142 switch (u.format) {
Behdad Esfahbod9c5a9ee2013-03-09 01:55:04 -05002143 case 1: return TRACE_RETURN (c->dispatch (u.format1));
2144 case 2: return TRACE_RETURN (c->dispatch (u.format2));
2145 case 3: return TRACE_RETURN (c->dispatch (u.format3));
Behdad Esfahbodf48ec0e2012-11-23 17:23:41 -05002146 default:return TRACE_RETURN (c->default_return_value ());
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002147 }
2148 }
2149
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002150 inline bool sanitize (hb_sanitize_context_t *c) const
2151 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002152 TRACE_SANITIZE (this);
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02002153 if (!u.format.sanitize (c)) return TRACE_RETURN (false);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002154 switch (u.format) {
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02002155 case 1: return TRACE_RETURN (u.format1.sanitize (c));
2156 case 2: return TRACE_RETURN (u.format2.sanitize (c));
2157 case 3: return TRACE_RETURN (u.format3.sanitize (c));
2158 default:return TRACE_RETURN (true);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002159 }
2160 }
2161
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002162 protected:
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002163 union {
2164 USHORT format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -04002165 ChainContextFormat1 format1;
2166 ChainContextFormat2 format2;
2167 ChainContextFormat3 format3;
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002168 } u;
2169};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002170
2171
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002172struct ExtensionFormat1
2173{
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002174 inline unsigned int get_type (void) const { return extensionLookupType; }
Behdad Esfahbod3b2c2df2010-04-22 16:51:42 -04002175 inline unsigned int get_offset (void) const { return extensionOffset; }
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002176
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002177 inline bool sanitize (hb_sanitize_context_t *c) const
2178 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002179 TRACE_SANITIZE (this);
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02002180 return TRACE_RETURN (c->check_struct (this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002181 }
2182
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002183 protected:
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002184 USHORT format; /* Format identifier. Set to 1. */
2185 USHORT extensionLookupType; /* Lookup type of subtable referenced
2186 * by ExtensionOffset (i.e. the
2187 * extension subtable). */
Behdad Esfahbod81f2af42010-04-22 00:58:49 -04002188 ULONG extensionOffset; /* Offset to the extension subtable,
2189 * of lookup type subtable. */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04002190 public:
2191 DEFINE_SIZE_STATIC (8);
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002192};
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002193
Behdad Esfahbod653eeb22012-11-23 16:57:36 -05002194template <typename T>
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002195struct Extension
2196{
2197 inline unsigned int get_type (void) const
2198 {
2199 switch (u.format) {
Behdad Esfahboddacebca2010-05-10 19:45:41 -04002200 case 1: return u.format1.get_type ();
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002201 default:return 0;
2202 }
2203 }
Behdad Esfahbod3b2c2df2010-04-22 16:51:42 -04002204 inline unsigned int get_offset (void) const
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002205 {
2206 switch (u.format) {
Behdad Esfahboddacebca2010-05-10 19:45:41 -04002207 case 1: return u.format1.get_offset ();
Behdad Esfahbod3b2c2df2010-04-22 16:51:42 -04002208 default:return 0;
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002209 }
2210 }
2211
Behdad Esfahbod7dddd4e2012-11-23 17:04:55 -05002212 template <typename X>
2213 inline const X& get_subtable (void) const
2214 {
2215 unsigned int offset = get_offset ();
2216 if (unlikely (!offset)) return Null(typename T::LookupSubTable);
2217 return StructAtOffset<typename T::LookupSubTable> (this, offset);
2218 }
2219
Behdad Esfahbod653eeb22012-11-23 16:57:36 -05002220 template <typename context_t>
Behdad Esfahbod9c5a9ee2013-03-09 01:55:04 -05002221 inline typename context_t::return_t dispatch (context_t *c) const
Behdad Esfahbod653eeb22012-11-23 16:57:36 -05002222 {
Behdad Esfahbod9c5a9ee2013-03-09 01:55:04 -05002223 return get_subtable<typename T::LookupSubTable> ().dispatch (c, get_type ());
Behdad Esfahbod653eeb22012-11-23 16:57:36 -05002224 }
2225
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002226 inline bool sanitize_self (hb_sanitize_context_t *c) const
2227 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002228 TRACE_SANITIZE (this);
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02002229 if (!u.format.sanitize (c)) return TRACE_RETURN (false);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002230 switch (u.format) {
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02002231 case 1: return TRACE_RETURN (u.format1.sanitize (c));
2232 default:return TRACE_RETURN (true);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002233 }
2234 }
2235
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002236 inline bool sanitize (hb_sanitize_context_t *c) const
2237 {
Behdad Esfahboded2e1352012-11-23 17:10:40 -05002238 TRACE_SANITIZE (this);
2239 if (!sanitize_self (c)) return TRACE_RETURN (false);
2240 unsigned int offset = get_offset ();
2241 if (unlikely (!offset)) return TRACE_RETURN (true);
2242 return TRACE_RETURN (StructAtOffset<typename T::LookupSubTable> (this, offset).sanitize (c, get_type ()));
2243 }
2244
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002245 protected:
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002246 union {
2247 USHORT format; /* Format identifier */
Behdad Esfahbod6d08c7f2012-07-11 18:01:27 -04002248 ExtensionFormat1 format1;
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002249 } u;
2250};
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002251
2252
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04002253/*
2254 * GSUB/GPOS Common
2255 */
2256
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002257struct GSUBGPOS
2258{
Behdad Esfahboda328d662009-08-04 20:27:05 -04002259 static const hb_tag_t GSUBTag = HB_OT_TAG_GSUB;
2260 static const hb_tag_t GPOSTag = HB_OT_TAG_GPOS;
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04002261
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04002262 inline unsigned int get_script_count (void) const
2263 { return (this+scriptList).len; }
2264 inline const Tag& get_script_tag (unsigned int i) const
2265 { return (this+scriptList).get_tag (i); }
Behdad Esfahbode21899b2009-11-04 16:36:14 -05002266 inline unsigned int get_script_tags (unsigned int start_offset,
2267 unsigned int *script_count /* IN/OUT */,
2268 hb_tag_t *script_tags /* OUT */) const
2269 { return (this+scriptList).get_tags (start_offset, script_count, script_tags); }
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04002270 inline const Script& get_script (unsigned int i) const
2271 { return (this+scriptList)[i]; }
2272 inline bool find_script_index (hb_tag_t tag, unsigned int *index) const
2273 { return (this+scriptList).find_index (tag, index); }
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04002274
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04002275 inline unsigned int get_feature_count (void) const
2276 { return (this+featureList).len; }
Jonathan Kewda132932014-04-27 14:05:24 +01002277 inline hb_tag_t get_feature_tag (unsigned int i) const
2278 { return i == Index::NOT_FOUND_INDEX ? HB_TAG_NONE : (this+featureList).get_tag (i); }
Behdad Esfahbode21899b2009-11-04 16:36:14 -05002279 inline unsigned int get_feature_tags (unsigned int start_offset,
2280 unsigned int *feature_count /* IN/OUT */,
2281 hb_tag_t *feature_tags /* OUT */) const
2282 { return (this+featureList).get_tags (start_offset, feature_count, feature_tags); }
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04002283 inline const Feature& get_feature (unsigned int i) const
2284 { return (this+featureList)[i]; }
2285 inline bool find_feature_index (hb_tag_t tag, unsigned int *index) const
2286 { return (this+featureList).find_index (tag, index); }
2287
2288 inline unsigned int get_lookup_count (void) const
2289 { return (this+lookupList).len; }
2290 inline const Lookup& get_lookup (unsigned int i) const
2291 { return (this+lookupList)[i]; }
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04002292
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002293 inline bool sanitize (hb_sanitize_context_t *c) const
2294 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002295 TRACE_SANITIZE (this);
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02002296 return TRACE_RETURN (version.sanitize (c) && likely (version.major == 1) &&
2297 scriptList.sanitize (c, this) &&
2298 featureList.sanitize (c, this) &&
2299 lookupList.sanitize (c, this));
Behdad Esfahbodcd3827e2009-08-04 02:09:34 -04002300 }
2301
Behdad Esfahbod212aba62009-05-24 00:50:27 -04002302 protected:
Behdad Esfahbod87fcdcb2009-05-24 01:03:24 -04002303 FixedVersion version; /* Version of the GSUB/GPOS table--initially set
Behdad Esfahbod76271002014-07-11 14:54:42 -04002304 * to 0x00010000u */
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04002305 OffsetTo<ScriptList>
2306 scriptList; /* ScriptList table */
2307 OffsetTo<FeatureList>
2308 featureList; /* FeatureList table */
2309 OffsetTo<LookupList>
2310 lookupList; /* LookupList table */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04002311 public:
2312 DEFINE_SIZE_STATIC (10);
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04002313};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002314
Behdad Esfahbod6f20f722009-05-17 20:28:01 -04002315
Behdad Esfahbod7d52e662012-11-16 18:49:54 -08002316} /* namespace OT */
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -04002317
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04002318
Behdad Esfahbod5f5b24f2009-08-02 20:03:12 -04002319#endif /* HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH */