blob: cd91cf55f1a90edb6d534425749bc4cc3b0cef9e [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 Esfahbod40ec3bb2017-11-03 16:57:30 -040032#include "hb-private.hh"
33#include "hb-debug.hh"
Behdad Esfahbod22da7fd2010-05-12 18:23:21 -040034#include "hb-buffer-private.hh"
Behdad Esfahbod7a750ac2011-08-17 14:19:59 +020035#include "hb-ot-layout-gdef-table.hh"
Behdad Esfahbod1336ecd2012-08-01 21:46:36 -040036#include "hb-set-private.hh"
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -040037
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -040038
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -040039namespace OT {
40
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -040041
Behdad Esfahbod77a1a2b2015-10-09 12:20:58 -040042struct hb_closure_context_t :
43 hb_dispatch_context_t<hb_closure_context_t, hb_void_t, HB_DEBUG_CLOSURE>
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -040044{
Behdad Esfahboda1733db2012-11-23 16:40:04 -050045 inline const char *get_name (void) { return "CLOSURE"; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -050046 typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
47 template <typename T>
Behdad Esfahbod9c5a9ee2013-03-09 01:55:04 -050048 inline return_t dispatch (const T &obj) { obj.closure (this); return HB_VOID; }
Behdad Esfahbod130bb3f2012-12-05 16:49:47 -050049 static return_t default_return_value (void) { return HB_VOID; }
Behdad Esfahbod7b912c12013-01-04 01:25:27 -060050 bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -050051 return_t recurse (unsigned int lookup_index)
52 {
Behdad Esfahbod9b346772012-11-23 17:55:40 -050053 if (unlikely (nesting_level_left == 0 || !recurse_func))
Behdad Esfahbod2005fa52012-11-22 14:38:10 -050054 return default_return_value ();
Behdad Esfahbod44fc2372012-11-21 23:33:13 -050055
56 nesting_level_left--;
57 recurse_func (this, lookup_index);
58 nesting_level_left++;
Behdad Esfahbod130bb3f2012-12-05 16:49:47 -050059 return HB_VOID;
Behdad Esfahbod44fc2372012-11-21 23:33:13 -050060 }
61
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -040062 hb_face_t *face;
Behdad Esfahbod6a9be5b2012-04-23 22:23:17 -040063 hb_set_t *glyphs;
Behdad Esfahbod44fc2372012-11-21 23:33:13 -050064 recurse_func_t recurse_func;
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -040065 unsigned int nesting_level_left;
66 unsigned int debug_depth;
67
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -040068 hb_closure_context_t (hb_face_t *face_,
Behdad Esfahbod6a9be5b2012-04-23 22:23:17 -040069 hb_set_t *glyphs_,
Behdad Esfahbod5ba45042015-11-02 15:43:08 -080070 unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
Behdad Esfahbode72b3602012-07-19 14:35:23 -040071 face (face_),
72 glyphs (glyphs_),
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +020073 recurse_func (nullptr),
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -040074 nesting_level_left (nesting_level_left_),
75 debug_depth (0) {}
Behdad Esfahbod9b346772012-11-23 17:55:40 -050076
77 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -040078};
79
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -040080
Behdad Esfahbod77a1a2b2015-10-09 12:20:58 -040081struct hb_would_apply_context_t :
82 hb_dispatch_context_t<hb_would_apply_context_t, bool, HB_DEBUG_WOULD_APPLY>
Behdad Esfahbode72b3602012-07-19 14:35:23 -040083{
Behdad Esfahboda1733db2012-11-23 16:40:04 -050084 inline const char *get_name (void) { return "WOULD_APPLY"; }
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -050085 template <typename T>
Behdad Esfahbod9c5a9ee2013-03-09 01:55:04 -050086 inline return_t dispatch (const T &obj) { return obj.would_apply (this); }
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -050087 static return_t default_return_value (void) { return false; }
Behdad Esfahbod7b912c12013-01-04 01:25:27 -060088 bool stop_sublookup_iteration (return_t r) const { return r; }
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -050089
Behdad Esfahbode72b3602012-07-19 14:35:23 -040090 hb_face_t *face;
Behdad Esfahbod472f2292012-08-07 22:25:24 -040091 const hb_codepoint_t *glyphs;
Behdad Esfahbode72b3602012-07-19 14:35:23 -040092 unsigned int len;
Behdad Esfahbodd9b204d2012-08-23 16:22:28 -040093 bool zero_context;
Behdad Esfahbode72b3602012-07-19 14:35:23 -040094 unsigned int debug_depth;
95
96 hb_would_apply_context_t (hb_face_t *face_,
Behdad Esfahbod472f2292012-08-07 22:25:24 -040097 const hb_codepoint_t *glyphs_,
98 unsigned int len_,
Behdad Esfahbod2bd9fe32012-09-04 15:15:19 -040099 bool zero_context_) :
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400100 face (face_),
Behdad Esfahbod472f2292012-08-07 22:25:24 -0400101 glyphs (glyphs_),
102 len (len_),
Behdad Esfahbodd9b204d2012-08-23 16:22:28 -0400103 zero_context (zero_context_),
Behdad Esfahboda1733db2012-11-23 16:40:04 -0500104 debug_depth (0) {}
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400105};
106
107
Behdad Esfahbod77a1a2b2015-10-09 12:20:58 -0400108struct hb_collect_glyphs_context_t :
109 hb_dispatch_context_t<hb_collect_glyphs_context_t, hb_void_t, HB_DEBUG_COLLECT_GLYPHS>
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800110{
Behdad Esfahboda1733db2012-11-23 16:40:04 -0500111 inline const char *get_name (void) { return "COLLECT_GLYPHS"; }
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500112 typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index);
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500113 template <typename T>
Behdad Esfahbod9c5a9ee2013-03-09 01:55:04 -0500114 inline return_t dispatch (const T &obj) { obj.collect_glyphs (this); return HB_VOID; }
Behdad Esfahbod130bb3f2012-12-05 16:49:47 -0500115 static return_t default_return_value (void) { return HB_VOID; }
Behdad Esfahbod7b912c12013-01-04 01:25:27 -0600116 bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500117 return_t recurse (unsigned int lookup_index)
118 {
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500119 if (unlikely (nesting_level_left == 0 || !recurse_func))
120 return default_return_value ();
121
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200122 /* Note that GPOS sets recurse_func to nullptr already, so it doesn't get
Behdad Esfahbod1bcfa062012-12-04 16:58:09 -0500123 * past the previous check. For GSUB, we only want to collect the output
Behdad Esfahbod76ea5632013-05-04 16:01:20 -0400124 * glyphs in the recursion. If output is not requested, we can go home now.
125 *
126 * Note further, that the above is not exactly correct. A recursed lookup
127 * is allowed to match input that is not matched in the context, but that's
128 * not how most fonts are built. It's possible to relax that and recurse
129 * with all sets here if it proves to be an issue.
130 */
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500131
132 if (output == hb_set_get_empty ())
Behdad Esfahbod130bb3f2012-12-05 16:49:47 -0500133 return HB_VOID;
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500134
Behdad Esfahbodfde3e4a2014-10-29 11:23:08 -0700135 /* Return if new lookup was recursed to before. */
Behdad Esfahbod8b9d9b72017-10-22 17:48:06 -0400136 if (recursed_lookups->has (lookup_index))
Behdad Esfahbodfde3e4a2014-10-29 11:23:08 -0700137 return HB_VOID;
138
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500139 hb_set_t *old_before = before;
140 hb_set_t *old_input = input;
141 hb_set_t *old_after = after;
142 before = input = after = hb_set_get_empty ();
Behdad Esfahbod1bcfa062012-12-04 16:58:09 -0500143
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500144 nesting_level_left--;
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500145 recurse_func (this, lookup_index);
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500146 nesting_level_left++;
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500147
148 before = old_before;
149 input = old_input;
150 after = old_after;
151
Behdad Esfahbod8b9d9b72017-10-22 17:48:06 -0400152 recursed_lookups->add (lookup_index);
Behdad Esfahbodfde3e4a2014-10-29 11:23:08 -0700153
Behdad Esfahbod130bb3f2012-12-05 16:49:47 -0500154 return HB_VOID;
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500155 }
156
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800157 hb_face_t *face;
Behdad Esfahbod83035932012-12-04 17:08:41 -0500158 hb_set_t *before;
159 hb_set_t *input;
160 hb_set_t *after;
161 hb_set_t *output;
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500162 recurse_func_t recurse_func;
Behdad Esfahbod8b9d9b72017-10-22 17:48:06 -0400163 hb_set_t *recursed_lookups;
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500164 unsigned int nesting_level_left;
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800165 unsigned int debug_depth;
166
167 hb_collect_glyphs_context_t (hb_face_t *face_,
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200168 hb_set_t *glyphs_before, /* OUT. May be nullptr */
169 hb_set_t *glyphs_input, /* OUT. May be nullptr */
170 hb_set_t *glyphs_after, /* OUT. May be nullptr */
171 hb_set_t *glyphs_output, /* OUT. May be nullptr */
Behdad Esfahbod5ba45042015-11-02 15:43:08 -0800172 unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800173 face (face_),
Behdad Esfahbod83035932012-12-04 17:08:41 -0500174 before (glyphs_before ? glyphs_before : hb_set_get_empty ()),
175 input (glyphs_input ? glyphs_input : hb_set_get_empty ()),
176 after (glyphs_after ? glyphs_after : hb_set_get_empty ()),
177 output (glyphs_output ? glyphs_output : hb_set_get_empty ()),
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200178 recurse_func (nullptr),
Behdad Esfahbod8b9d9b72017-10-22 17:48:06 -0400179 recursed_lookups (nullptr),
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500180 nesting_level_left (nesting_level_left_),
Behdad Esfahbodfde3e4a2014-10-29 11:23:08 -0700181 debug_depth (0)
182 {
Behdad Esfahbod8b9d9b72017-10-22 17:48:06 -0400183 recursed_lookups = hb_set_create ();
Behdad Esfahbodfde3e4a2014-10-29 11:23:08 -0700184 }
185 ~hb_collect_glyphs_context_t (void)
186 {
Behdad Esfahbod8b9d9b72017-10-22 17:48:06 -0400187 hb_set_destroy (recursed_lookups);
Behdad Esfahbodfde3e4a2014-10-29 11:23:08 -0700188 }
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500189
190 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800191};
192
193
194
Behdad Esfahbod77a1a2b2015-10-09 12:20:58 -0400195/* XXX Can we remove this? */
196
Behdad Esfahbod8e36ccf2015-02-17 19:15:34 +0300197template <typename set_t>
Behdad Esfahbod77a1a2b2015-10-09 12:20:58 -0400198struct hb_add_coverage_context_t :
199 hb_dispatch_context_t<hb_add_coverage_context_t<set_t>, const Coverage &, HB_DEBUG_GET_COVERAGE>
Behdad Esfahbod2005fa52012-11-22 14:38:10 -0500200{
Behdad Esfahboda1733db2012-11-23 16:40:04 -0500201 inline const char *get_name (void) { return "GET_COVERAGE"; }
Behdad Esfahbod2005fa52012-11-22 14:38:10 -0500202 typedef const Coverage &return_t;
203 template <typename T>
Behdad Esfahbod9c5a9ee2013-03-09 01:55:04 -0500204 inline return_t dispatch (const T &obj) { return obj.get_coverage (); }
Behdad Esfahboda1733db2012-11-23 16:40:04 -0500205 static return_t default_return_value (void) { return Null(Coverage); }
Behdad Esfahbod8e36ccf2015-02-17 19:15:34 +0300206 bool stop_sublookup_iteration (return_t r) const
207 {
208 r.add_coverage (set);
209 return false;
210 }
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500211
Behdad Esfahbod8e36ccf2015-02-17 19:15:34 +0300212 hb_add_coverage_context_t (set_t *set_) :
213 set (set_),
Behdad Esfahboda1733db2012-11-23 16:40:04 -0500214 debug_depth (0) {}
215
Behdad Esfahbod8e36ccf2015-02-17 19:15:34 +0300216 set_t *set;
Behdad Esfahboda1733db2012-11-23 16:40:04 -0500217 unsigned int debug_depth;
Behdad Esfahbod2005fa52012-11-22 14:38:10 -0500218};
219
220
Behdad Esfahbod77a1a2b2015-10-09 12:20:58 -0400221struct hb_apply_context_t :
222 hb_dispatch_context_t<hb_apply_context_t, bool, HB_DEBUG_APPLY>
Behdad Esfahbod1376fb72010-04-29 02:19:21 -0400223{
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500224 struct matcher_t
225 {
226 inline matcher_t (void) :
227 lookup_props (0),
Behdad Esfahbodcfc507c2013-02-14 10:40:12 -0500228 ignore_zwnj (false),
229 ignore_zwj (false),
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500230 mask (-1),
231#define arg1(arg) (arg) /* Remove the macro to see why it's needed! */
232 syllable arg1(0),
233#undef arg1
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200234 match_func (nullptr),
235 match_data (nullptr) {};
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500236
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -0800237 typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const UINT16 &value, const void *data);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500238
239 inline void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; }
Behdad Esfahbod0b454792013-02-14 10:46:52 -0500240 inline void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500241 inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
242 inline void set_mask (hb_mask_t mask_) { mask = mask_; }
243 inline void set_syllable (uint8_t syllable_) { syllable = syllable_; }
244 inline void set_match_func (match_func_t match_func_,
245 const void *match_data_)
246 { match_func = match_func_; match_data = match_data_; }
247
Behdad Esfahbod2b2a6e82013-02-21 15:07:03 -0500248 enum may_match_t {
249 MATCH_NO,
250 MATCH_YES,
251 MATCH_MAYBE
252 };
253
254 inline may_match_t may_match (const hb_glyph_info_t &info,
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -0800255 const UINT16 *glyph_data) const
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500256 {
Behdad Esfahbod2b2a6e82013-02-21 15:07:03 -0500257 if (!(info.mask & mask) ||
258 (syllable && syllable != info.syllable ()))
259 return MATCH_NO;
260
261 if (match_func)
262 return match_func (info.codepoint, *glyph_data, match_data) ? MATCH_YES : MATCH_NO;
263
264 return MATCH_MAYBE;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500265 }
266
267 enum may_skip_t {
268 SKIP_NO,
269 SKIP_YES,
270 SKIP_MAYBE
271 };
272
273 inline may_skip_t
274 may_skip (const hb_apply_context_t *c,
275 const hb_glyph_info_t &info) const
276 {
Behdad Esfahbodb98c5db2014-07-16 13:44:01 -0400277 if (!c->check_glyph_property (&info, lookup_props))
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500278 return SKIP_YES;
279
Khaled Hosny06cfe3f2017-05-17 21:32:47 +0300280 if (unlikely (_hb_glyph_info_is_default_ignorable_and_not_hidden (&info) &&
Behdad Esfahbod0b454792013-02-14 10:46:52 -0500281 (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) &&
Behdad Esfahbod4ba796b2015-07-22 17:41:31 +0100282 (ignore_zwj || !_hb_glyph_info_is_zwj (&info))))
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500283 return SKIP_MAYBE;
284
285 return SKIP_NO;
286 }
287
288 protected:
289 unsigned int lookup_props;
290 bool ignore_zwnj;
Behdad Esfahbod0b454792013-02-14 10:46:52 -0500291 bool ignore_zwj;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500292 hb_mask_t mask;
293 uint8_t syllable;
294 match_func_t match_func;
295 const void *match_data;
296 };
297
Behdad Esfahbod69626692015-01-29 13:08:41 +0100298 struct skipping_iterator_t
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500299 {
Behdad Esfahbod514564f2015-01-29 13:48:48 +0100300 inline void init (hb_apply_context_t *c_, bool context_match = false)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500301 {
Behdad Esfahbod514564f2015-01-29 13:48:48 +0100302 c = c_;
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200303 match_glyph_data = nullptr;
304 matcher.set_match_func (nullptr, nullptr);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500305 matcher.set_lookup_props (c->lookup_props);
Behdad Esfahboda8cf7b42013-03-19 05:53:26 -0400306 /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100307 matcher.set_ignore_zwnj (c->table_index == 1 || (context_match && c->auto_zwnj));
Behdad Esfahboda8cf7b42013-03-19 05:53:26 -0400308 /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100309 matcher.set_ignore_zwj (c->table_index == 1 || (context_match || c->auto_zwj));
Behdad Esfahbod514564f2015-01-29 13:48:48 +0100310 matcher.set_mask (context_match ? -1 : c->lookup_mask);
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500311 }
Behdad Esfahbod514564f2015-01-29 13:48:48 +0100312 inline void set_lookup_props (unsigned int lookup_props)
313 {
314 matcher.set_lookup_props (lookup_props);
315 }
Behdad Esfahbod4a6b1ee2015-10-21 11:20:55 -0200316 inline void set_match_func (matcher_t::match_func_t match_func_,
317 const void *match_data_,
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -0800318 const UINT16 glyph_data[])
Behdad Esfahbodc074ebc2013-02-13 11:22:42 -0500319 {
Behdad Esfahbod4a6b1ee2015-10-21 11:20:55 -0200320 matcher.set_match_func (match_func_, match_data_);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500321 match_glyph_data = glyph_data;
Behdad Esfahbodc074ebc2013-02-13 11:22:42 -0500322 }
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500323
Behdad Esfahbodb051be52015-01-29 13:40:39 +0100324 inline void reset (unsigned int start_index_,
325 unsigned int num_items_)
326 {
327 idx = start_index_;
328 num_items = num_items_;
329 end = c->buffer->len;
330 matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
331 }
332
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500333 inline void reject (void) { num_items++; match_glyph_data--; }
Behdad Esfahbod69626692015-01-29 13:08:41 +0100334
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200335 inline matcher_t::may_skip_t
336 may_skip (const hb_apply_context_t *c,
337 const hb_glyph_info_t &info) const
338 {
339 return matcher.may_skip (c, info);
340 }
341
Behdad Esfahbodc074ebc2013-02-13 11:22:42 -0500342 inline bool next (void)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500343 {
Behdad Esfahbod506ffeb2012-01-18 16:07:53 -0500344 assert (num_items > 0);
Behdad Esfahbod37d13ac2015-01-29 11:38:01 +0100345 while (idx + num_items < end)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500346 {
Behdad Esfahboda4a48fe2012-01-17 18:08:41 -0500347 idx++;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500348 const hb_glyph_info_t &info = c->buffer->info[idx];
349
Behdad Esfahbodff93ac82013-02-21 14:51:40 -0500350 matcher_t::may_skip_t skip = matcher.may_skip (c, info);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500351 if (unlikely (skip == matcher_t::SKIP_YES))
352 continue;
353
Behdad Esfahbod2b2a6e82013-02-21 15:07:03 -0500354 matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
Behdad Esfahbod722e8b82013-02-21 15:37:51 -0500355 if (match == matcher_t::MATCH_YES ||
356 (match == matcher_t::MATCH_MAYBE &&
357 skip == matcher_t::SKIP_NO))
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500358 {
359 num_items--;
360 match_glyph_data++;
361 return true;
362 }
363
364 if (skip == matcher_t::SKIP_NO)
Behdad Esfahbod722e8b82013-02-21 15:37:51 -0500365 return false;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500366 }
367 return false;
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500368 }
Behdad Esfahbodc074ebc2013-02-13 11:22:42 -0500369 inline bool prev (void)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500370 {
Behdad Esfahbod506ffeb2012-01-18 16:07:53 -0500371 assert (num_items > 0);
Behdad Esfahbod37d13ac2015-01-29 11:38:01 +0100372 while (idx >= num_items)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500373 {
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500374 idx--;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500375 const hb_glyph_info_t &info = c->buffer->out_info[idx];
376
Behdad Esfahbodff93ac82013-02-21 14:51:40 -0500377 matcher_t::may_skip_t skip = matcher.may_skip (c, info);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500378 if (unlikely (skip == matcher_t::SKIP_YES))
379 continue;
380
Behdad Esfahbod2b2a6e82013-02-21 15:07:03 -0500381 matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
Behdad Esfahbod722e8b82013-02-21 15:37:51 -0500382 if (match == matcher_t::MATCH_YES ||
383 (match == matcher_t::MATCH_MAYBE &&
384 skip == matcher_t::SKIP_NO))
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500385 {
386 num_items--;
387 match_glyph_data++;
388 return true;
389 }
390
391 if (skip == matcher_t::SKIP_NO)
Behdad Esfahbod722e8b82013-02-21 15:37:51 -0500392 return false;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500393 }
394 return false;
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500395 }
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500396
397 unsigned int idx;
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400398 protected:
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500399 hb_apply_context_t *c;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500400 matcher_t matcher;
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -0800401 const UINT16 *match_glyph_data;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500402
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500403 unsigned int num_items;
Behdad Esfahbod69626692015-01-29 13:08:41 +0100404 unsigned int end;
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500405 };
406
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100407
408 inline const char *get_name (void) { return "APPLY"; }
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100409 typedef return_t (*recurse_func_t) (hb_apply_context_t *c, unsigned int lookup_index);
410 template <typename T>
411 inline return_t dispatch (const T &obj) { return obj.apply (this); }
412 static return_t default_return_value (void) { return false; }
413 bool stop_sublookup_iteration (return_t r) const { return r; }
414 return_t recurse (unsigned int lookup_index)
415 {
Behdad Esfahbodbaf77792017-11-14 21:53:48 -0800416 if (unlikely (nesting_level_left == 0 || !recurse_func || buffer->max_ops-- <= 0))
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100417 return default_return_value ();
418
419 nesting_level_left--;
420 bool ret = recurse_func (this, lookup_index);
421 nesting_level_left++;
422 return ret;
423 }
424
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100425 skipping_iterator_t iter_input, iter_context;
426
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100427 hb_font_t *font;
428 hb_face_t *face;
429 hb_buffer_t *buffer;
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100430 recurse_func_t recurse_func;
431 const GDEF &gdef;
432 const VariationStore &var_store;
433
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100434 hb_direction_t direction;
435 hb_mask_t lookup_mask;
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100436 unsigned int table_index; /* GSUB/GPOS */
Behdad Esfahbod2c8b3b22015-08-18 14:36:43 +0100437 unsigned int lookup_index;
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100438 unsigned int lookup_props;
439 unsigned int nesting_level_left;
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100440 unsigned int debug_depth;
441
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100442 bool auto_zwnj;
443 bool auto_zwj;
444 bool has_glyph_classes;
445
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100446
447 hb_apply_context_t (unsigned int table_index_,
448 hb_font_t *font_,
449 hb_buffer_t *buffer_) :
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100450 iter_input (), iter_context (),
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100451 font (font_), face (font->face), buffer (buffer_),
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200452 recurse_func (nullptr),
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100453 gdef (*hb_ot_layout_from_face (face)->gdef),
454 var_store (gdef.get_var_store ()),
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100455 direction (buffer_->props.direction),
456 lookup_mask (1),
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100457 table_index (table_index_),
Behdad Esfahbod2c8b3b22015-08-18 14:36:43 +0100458 lookup_index ((unsigned int) -1),
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100459 lookup_props (0),
460 nesting_level_left (HB_MAX_NESTING_LEVEL),
461 debug_depth (0),
462 auto_zwnj (true),
463 auto_zwj (true),
464 has_glyph_classes (gdef.has_glyph_classes ()) {}
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100465
466 inline void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; }
467 inline void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; }
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100468 inline void set_auto_zwnj (bool auto_zwnj_) { auto_zwnj = auto_zwnj_; }
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100469 inline void set_recurse_func (recurse_func_t func) { recurse_func = func; }
Behdad Esfahbod2c8b3b22015-08-18 14:36:43 +0100470 inline void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; }
Behdad Esfahbod365576d2015-01-29 13:59:42 +0100471 inline void set_lookup_props (unsigned int lookup_props_)
472 {
473 lookup_props = lookup_props_;
474 iter_input.init (this, false);
475 iter_context.init (this, true);
476 }
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100477
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400478 inline bool
479 match_properties_mark (hb_codepoint_t glyph,
480 unsigned int glyph_props,
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700481 unsigned int match_props) const
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400482 {
483 /* If using mark filtering sets, the high short of
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700484 * match_props has the set index.
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400485 */
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700486 if (match_props & LookupFlag::UseMarkFilteringSet)
487 return gdef.mark_set_covers (match_props >> 16, glyph);
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400488
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700489 /* The second byte of match_props has the meaning
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400490 * "ignore marks of attachment type different than
491 * the attachment type specified."
492 */
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700493 if (match_props & LookupFlag::MarkAttachmentType)
494 return (match_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400495
496 return true;
497 }
498
499 inline bool
Behdad Esfahbodb98c5db2014-07-16 13:44:01 -0400500 check_glyph_property (const hb_glyph_info_t *info,
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700501 unsigned int match_props) const
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400502 {
Behdad Esfahbodb98c5db2014-07-16 13:44:01 -0400503 hb_codepoint_t glyph = info->codepoint;
504 unsigned int glyph_props = _hb_glyph_info_get_glyph_props (info);
505
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400506 /* Not covered, if, for example, glyph class is ligature and
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700507 * match_props includes LookupFlags::IgnoreLigatures
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400508 */
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700509 if (glyph_props & match_props & LookupFlag::IgnoreFlags)
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400510 return false;
511
Behdad Esfahbod5a08ecf2012-11-16 13:34:29 -0800512 if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK))
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700513 return match_properties_mark (glyph, glyph_props, match_props);
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400514
515 return true;
516 }
517
Behdad Esfahboda0161742013-10-18 00:06:30 +0200518 inline void _set_glyph_props (hb_codepoint_t glyph_index,
Behdad Esfahbod71b4c992013-10-28 00:20:59 +0100519 unsigned int class_guess = 0,
Behdad Esfahbod832a6f92014-06-04 16:57:42 -0400520 bool ligature = false,
521 bool component = false) const
Behdad Esfahbod60da7632012-07-16 16:13:32 -0400522 {
Behdad Esfahbod09675a82013-10-18 01:05:58 +0200523 unsigned int add_in = _hb_glyph_info_get_glyph_props (&buffer->cur()) &
524 HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE;
525 add_in |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED;
526 if (ligature)
Behdad Esfahbod832a6f92014-06-04 16:57:42 -0400527 {
Behdad Esfahbod09675a82013-10-18 01:05:58 +0200528 add_in |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED;
Behdad Esfahbod832a6f92014-06-04 16:57:42 -0400529 /* In the only place that the MULTIPLIED bit is used, Uniscribe
530 * seems to only care about the "last" transformation between
531 * Ligature and Multiple substitions. Ie. if you ligate, expand,
532 * and ligate again, it forgives the multiplication and acts as
533 * if only ligation happened. As such, clear MULTIPLIED bit.
534 */
535 add_in &= ~HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
536 }
537 if (component)
538 add_in |= HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
Behdad Esfahbod2fca1422012-07-30 18:46:41 -0400539 if (likely (has_glyph_classes))
Behdad Esfahbod05ad6b52013-10-18 00:45:59 +0200540 _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | gdef.get_glyph_props (glyph_index));
Behdad Esfahbod05bd1b62012-07-30 19:30:01 -0400541 else if (class_guess)
Behdad Esfahbod09675a82013-10-18 01:05:58 +0200542 _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | class_guess);
Behdad Esfahbod60da7632012-07-16 16:13:32 -0400543 }
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500544
Behdad Esfahboda0161742013-10-18 00:06:30 +0200545 inline void replace_glyph (hb_codepoint_t glyph_index) const
Behdad Esfahbod3ec77d62012-06-08 21:44:06 -0400546 {
Behdad Esfahboda0161742013-10-18 00:06:30 +0200547 _set_glyph_props (glyph_index);
Behdad Esfahbod98370e82010-10-27 17:39:01 -0400548 buffer->replace_glyph (glyph_index);
549 }
Behdad Esfahboda0161742013-10-18 00:06:30 +0200550 inline void replace_glyph_inplace (hb_codepoint_t glyph_index) const
Behdad Esfahbod7fbbf862012-07-30 18:36:42 -0400551 {
Behdad Esfahboda0161742013-10-18 00:06:30 +0200552 _set_glyph_props (glyph_index);
Behdad Esfahbod7fbbf862012-07-30 18:36:42 -0400553 buffer->cur().codepoint = glyph_index;
554 }
Behdad Esfahboda0161742013-10-18 00:06:30 +0200555 inline void replace_glyph_with_ligature (hb_codepoint_t glyph_index,
556 unsigned int class_guess) const
557 {
Behdad Esfahbod09675a82013-10-18 01:05:58 +0200558 _set_glyph_props (glyph_index, class_guess, true);
Behdad Esfahboda0161742013-10-18 00:06:30 +0200559 buffer->replace_glyph (glyph_index);
560 }
Behdad Esfahbod832a6f92014-06-04 16:57:42 -0400561 inline void output_glyph_for_component (hb_codepoint_t glyph_index,
562 unsigned int class_guess) const
Behdad Esfahboda0161742013-10-18 00:06:30 +0200563 {
Behdad Esfahbod832a6f92014-06-04 16:57:42 -0400564 _set_glyph_props (glyph_index, class_guess, false, true);
Behdad Esfahboda0161742013-10-18 00:06:30 +0200565 buffer->output_glyph (glyph_index);
566 }
Behdad Esfahbod1376fb72010-04-29 02:19:21 -0400567};
568
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -0400569
Behdad Esfahbod94a23aa2010-05-05 01:13:09 -0400570
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -0800571typedef bool (*intersects_func_t) (hb_set_t *glyphs, const UINT16 &value, const void *data);
572typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const UINT16 &value, const void *data);
573typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const UINT16 &value, const void *data);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -0400574
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400575struct ContextClosureFuncs
576{
577 intersects_func_t intersects;
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400578};
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500579struct ContextCollectGlyphsFuncs
580{
581 collect_glyphs_func_t collect;
582};
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400583struct ContextApplyFuncs
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400584{
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -0400585 match_func_t match;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -0400586};
587
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500588
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -0800589static inline bool intersects_glyph (hb_set_t *glyphs, const UINT16 &value, const void *data HB_UNUSED)
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400590{
591 return glyphs->has (value);
592}
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -0800593static inline bool intersects_class (hb_set_t *glyphs, const UINT16 &value, const void *data)
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400594{
595 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
596 return class_def.intersects_class (glyphs, value);
597}
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -0800598static inline bool intersects_coverage (hb_set_t *glyphs, const UINT16 &value, const void *data)
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400599{
600 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
601 return (data+coverage).intersects (glyphs);
602}
603
604static inline bool intersects_array (hb_closure_context_t *c,
605 unsigned int count,
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -0800606 const UINT16 values[],
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400607 intersects_func_t intersects_func,
608 const void *intersects_data)
609{
610 for (unsigned int i = 0; i < count; i++)
611 if (likely (!intersects_func (c->glyphs, values[i], intersects_data)))
612 return false;
613 return true;
614}
615
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -0400616
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -0800617static inline void collect_glyph (hb_set_t *glyphs, const UINT16 &value, const void *data HB_UNUSED)
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500618{
619 glyphs->add (value);
620}
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -0800621static inline void collect_class (hb_set_t *glyphs, const UINT16 &value, const void *data)
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500622{
623 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
624 class_def.add_class (glyphs, value);
625}
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -0800626static inline void collect_coverage (hb_set_t *glyphs, const UINT16 &value, const void *data)
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500627{
628 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
629 (data+coverage).add_coverage (glyphs);
630}
Behdad Esfahbod0beb66e2012-12-05 18:46:04 -0500631static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -0500632 hb_set_t *glyphs,
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500633 unsigned int count,
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -0800634 const UINT16 values[],
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500635 collect_glyphs_func_t collect_func,
636 const void *collect_data)
637{
638 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbodf1b12782012-11-24 01:55:34 -0500639 collect_func (glyphs, values[i], collect_data);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500640}
641
642
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -0800643static inline bool match_glyph (hb_codepoint_t glyph_id, const UINT16 &value, const void *data HB_UNUSED)
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400644{
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -0400645 return glyph_id == value;
646}
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -0800647static inline bool match_class (hb_codepoint_t glyph_id, const UINT16 &value, const void *data)
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400648{
Behdad Esfahbod2b5a59c2009-08-04 11:38:50 -0400649 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -0400650 return class_def.get_class (glyph_id) == value;
651}
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -0800652static inline bool match_coverage (hb_codepoint_t glyph_id, const UINT16 &value, const void *data)
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400653{
Behdad Esfahbod6b54c5d2009-05-18 18:30:25 -0400654 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400655 return (data+coverage).get_coverage (glyph_id) != NOT_COVERED;
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -0400656}
657
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400658static inline bool would_match_input (hb_would_apply_context_t *c,
659 unsigned int count, /* Including the first glyph (not matched) */
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -0800660 const UINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400661 match_func_t match_func,
662 const void *match_data)
663{
664 if (count != c->len)
665 return false;
666
667 for (unsigned int i = 1; i < count; i++)
Behdad Esfahbod472f2292012-08-07 22:25:24 -0400668 if (likely (!match_func (c->glyphs[i], input[i - 1], match_data)))
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400669 return false;
670
671 return true;
672}
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400673static inline bool match_input (hb_apply_context_t *c,
Behdad Esfahbode072c242009-05-18 03:47:31 -0400674 unsigned int count, /* Including the first glyph (not matched) */
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -0800675 const UINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -0400676 match_func_t match_func,
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -0400677 const void *match_data,
Behdad Esfahbod6cc136f2013-10-17 13:55:48 +0200678 unsigned int *end_offset,
Behdad Esfahbod5ba45042015-11-02 15:43:08 -0800679 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200680 bool *p_is_mark_ligature = nullptr,
681 unsigned int *p_total_component_count = nullptr)
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -0400682{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200683 TRACE_APPLY (nullptr);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400684
Behdad Esfahbod5ba45042015-11-02 15:43:08 -0800685 if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return_trace (false);
Behdad Esfahbod6b65a762013-10-14 18:51:39 +0200686
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200687 hb_buffer_t *buffer = c->buffer;
688
Behdad Esfahbod365576d2015-01-29 13:59:42 +0100689 hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
Behdad Esfahbodb051be52015-01-29 13:40:39 +0100690 skippy_iter.reset (buffer->idx, count - 1);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500691 skippy_iter.set_match_func (match_func, match_data, input);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400692
Behdad Esfahbod191fa882012-08-28 22:58:55 -0400693 /*
694 * This is perhaps the trickiest part of OpenType... Remarks:
695 *
696 * - If all components of the ligature were marks, we call this a mark ligature.
697 *
698 * - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize
699 * it as a ligature glyph.
700 *
701 * - Ligatures cannot be formed across glyphs attached to different components
702 * of previous ligatures. Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and
703 * LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother.
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200704 * However, it would be wrong to ligate that SHADDA,FATHA sequence.
705 * There are a couple of exceptions to this:
706 *
707 * o If a ligature tries ligating with marks that belong to it itself, go ahead,
708 * assuming that the font designer knows what they are doing (otherwise it can
709 * break Indic stuff when a matra wants to ligate with a conjunct,
710 *
711 * o If two marks want to ligate and they belong to different components of the
712 * same ligature glyph, and said ligature glyph is to be ignored according to
713 * mark-filtering rules, then allow.
714 * https://github.com/behdad/harfbuzz/issues/545
Behdad Esfahbod191fa882012-08-28 22:58:55 -0400715 */
716
Behdad Esfahbod101303d2013-10-18 00:42:39 +0200717 bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->cur());
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400718
719 unsigned int total_component_count = 0;
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200720 total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur());
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400721
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200722 unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
723 unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -0400724
Behdad Esfahbod621c49c2017-10-04 15:06:48 +0200725 enum {
726 LIGBASE_NOT_CHECKED,
727 LIGBASE_MAY_NOT_SKIP,
728 LIGBASE_MAY_SKIP
729 } ligbase = LIGBASE_NOT_CHECKED;
730
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200731 match_positions[0] = buffer->idx;
Behdad Esfahbod370f03e2012-01-16 17:03:55 -0500732 for (unsigned int i = 1; i < count; i++)
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400733 {
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100734 if (!skippy_iter.next ()) return_trace (false);
Behdad Esfahbod6cc136f2013-10-17 13:55:48 +0200735
736 match_positions[i] = skippy_iter.idx;
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400737
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200738 unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]);
739 unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400740
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200741 if (first_lig_id && first_lig_comp)
742 {
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400743 /* If first component was attached to a previous ligature component,
744 * all subsequent components should be attached to the same ligature
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200745 * component, otherwise we shouldn't ligate them... */
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400746 if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200747 {
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200748 /* ...unless, we are attached to a base ligature and that base
749 * ligature is ignorable. */
Behdad Esfahbod621c49c2017-10-04 15:06:48 +0200750 if (ligbase == LIGBASE_NOT_CHECKED)
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200751 {
Behdad Esfahbod621c49c2017-10-04 15:06:48 +0200752 bool found = false;
753 const hb_glyph_info_t *out = buffer->out_info;
754 unsigned int j = buffer->out_len;
755 while (j && _hb_glyph_info_get_lig_id (&out[j - 1]) == first_lig_id)
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200756 {
Behdad Esfahbod621c49c2017-10-04 15:06:48 +0200757 if (_hb_glyph_info_get_lig_comp (&out[j - 1]) == 0)
758 {
759 j--;
760 found = true;
761 break;
762 }
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200763 j--;
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200764 }
Behdad Esfahbod621c49c2017-10-04 15:06:48 +0200765
766 if (found && skippy_iter.may_skip (c, out[j]) == hb_apply_context_t::matcher_t::SKIP_YES)
767 ligbase = LIGBASE_MAY_SKIP;
768 else
769 ligbase = LIGBASE_MAY_NOT_SKIP;
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200770 }
771
Behdad Esfahbod621c49c2017-10-04 15:06:48 +0200772 if (ligbase == LIGBASE_MAY_NOT_SKIP)
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200773 return_trace (false);
774 }
775 }
776 else
Behdad Esfahbod621c49c2017-10-04 15:06:48 +0200777 {
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400778 /* If first component was NOT attached to a previous ligature component,
779 * all subsequent components should also NOT be attached to any ligature
780 * component, unless they are attached to the first component itself! */
781 if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id))
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100782 return_trace (false);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400783 }
784
Behdad Esfahbod101303d2013-10-18 00:42:39 +0200785 is_mark_ligature = is_mark_ligature && _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx]);
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200786 total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -0400787 }
788
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200789 *end_offset = skippy_iter.idx - buffer->idx + 1;
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400790
Behdad Esfahbod191fa882012-08-28 22:58:55 -0400791 if (p_is_mark_ligature)
792 *p_is_mark_ligature = is_mark_ligature;
793
794 if (p_total_component_count)
795 *p_total_component_count = total_component_count;
796
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100797 return_trace (true);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400798}
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100799static inline bool ligate_input (hb_apply_context_t *c,
Behdad Esfahbode714fe62013-10-17 13:49:51 +0200800 unsigned int count, /* Including the first glyph */
Behdad Esfahbod5ba45042015-11-02 15:43:08 -0800801 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
Behdad Esfahbode714fe62013-10-17 13:49:51 +0200802 unsigned int match_length,
Behdad Esfahboda177d022012-08-28 23:18:22 -0400803 hb_codepoint_t lig_glyph,
Behdad Esfahboda177d022012-08-28 23:18:22 -0400804 bool is_mark_ligature,
805 unsigned int total_component_count)
806{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200807 TRACE_APPLY (nullptr);
Behdad Esfahbode714fe62013-10-17 13:49:51 +0200808
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200809 hb_buffer_t *buffer = c->buffer;
810
811 buffer->merge_clusters (buffer->idx, buffer->idx + match_length);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500812
Behdad Esfahboda177d022012-08-28 23:18:22 -0400813 /*
814 * - If it *is* a mark ligature, we don't allocate a new ligature id, and leave
815 * the ligature to keep its old ligature id. This will allow it to attach to
816 * a base ligature in GPOS. Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH,
817 * and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA wit a
818 * ligature id and component value of 2. Then if SHADDA,FATHA form a ligature
819 * later, we don't want them to lose their ligature id/component, otherwise
820 * GPOS will fail to correctly position the mark ligature on top of the
821 * LAM,LAM,HEH ligature. See:
822 * https://bugzilla.gnome.org/show_bug.cgi?id=676343
823 *
824 * - If a ligature is formed of components that some of which are also ligatures
825 * themselves, and those ligature components had marks attached to *their*
826 * components, we have to attach the marks to the new ligature component
827 * positions! Now *that*'s tricky! And these marks may be following the
828 * last component of the whole sequence, so we should loop forward looking
829 * for them and update them.
830 *
831 * Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a
832 * 'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature
833 * id and component == 1. Now, during 'liga', the LAM and the LAM-HEH ligature
834 * form a LAM-LAM-HEH ligature. We need to reassign the SHADDA and FATHA to
835 * the new ligature with a component value of 2.
836 *
837 * This in fact happened to a font... See:
838 * https://bugzilla.gnome.org/show_bug.cgi?id=437633
839 */
840
Behdad Esfahbod5a08ecf2012-11-16 13:34:29 -0800841 unsigned int klass = is_mark_ligature ? 0 : HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200842 unsigned int lig_id = is_mark_ligature ? 0 : _hb_allocate_lig_id (buffer);
843 unsigned int last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
844 unsigned int last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
Behdad Esfahboda177d022012-08-28 23:18:22 -0400845 unsigned int components_so_far = last_num_components;
846
847 if (!is_mark_ligature)
Behdad Esfahbod7e08f122013-05-27 14:48:34 -0400848 {
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200849 _hb_glyph_info_set_lig_props_for_ligature (&buffer->cur(), lig_id, total_component_count);
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200850 if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
Behdad Esfahbod3d436d32013-10-28 21:00:37 +0100851 {
Behdad Esfahbod82596692015-11-02 17:44:05 -0800852 _hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER);
Behdad Esfahbod3d436d32013-10-28 21:00:37 +0100853 }
Behdad Esfahbod7e08f122013-05-27 14:48:34 -0400854 }
Behdad Esfahboda0161742013-10-18 00:06:30 +0200855 c->replace_glyph_with_ligature (lig_glyph, klass);
Behdad Esfahboda177d022012-08-28 23:18:22 -0400856
857 for (unsigned int i = 1; i < count; i++)
858 {
Behdad Esfahbodabadc172015-11-18 17:52:08 -0800859 while (buffer->idx < match_positions[i] && !buffer->in_error)
Behdad Esfahboda177d022012-08-28 23:18:22 -0400860 {
861 if (!is_mark_ligature) {
Behdad Esfahbod2f02fc72015-12-17 15:21:14 +0000862 unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
863 if (this_comp == 0)
Behdad Esfahbod100fbea2015-12-17 15:23:09 +0000864 this_comp = last_num_components;
Behdad Esfahboda177d022012-08-28 23:18:22 -0400865 unsigned int new_lig_comp = components_so_far - last_num_components +
Behdad Esfahbod2f02fc72015-12-17 15:21:14 +0000866 MIN (this_comp, last_num_components);
867 _hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
Behdad Esfahboda177d022012-08-28 23:18:22 -0400868 }
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200869 buffer->next_glyph ();
Behdad Esfahboda177d022012-08-28 23:18:22 -0400870 }
871
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200872 last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
873 last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
Behdad Esfahboda177d022012-08-28 23:18:22 -0400874 components_so_far += last_num_components;
875
876 /* Skip the base glyph */
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200877 buffer->idx++;
Behdad Esfahboda177d022012-08-28 23:18:22 -0400878 }
879
880 if (!is_mark_ligature && last_lig_id) {
881 /* Re-adjust components for any marks following. */
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200882 for (unsigned int i = buffer->idx; i < buffer->len; i++) {
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200883 if (last_lig_id == _hb_glyph_info_get_lig_id (&buffer->info[i])) {
Behdad Esfahbod2f02fc72015-12-17 15:21:14 +0000884 unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->info[i]);
885 if (!this_comp)
886 break;
Behdad Esfahboda177d022012-08-28 23:18:22 -0400887 unsigned int new_lig_comp = components_so_far - last_num_components +
Behdad Esfahbod2f02fc72015-12-17 15:21:14 +0000888 MIN (this_comp, last_num_components);
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200889 _hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
Behdad Esfahboda177d022012-08-28 23:18:22 -0400890 } else
891 break;
892 }
893 }
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100894 return_trace (true);
Behdad Esfahboda177d022012-08-28 23:18:22 -0400895}
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400896
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400897static inline bool match_backtrack (hb_apply_context_t *c,
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400898 unsigned int count,
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -0800899 const UINT16 backtrack[],
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400900 match_func_t match_func,
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +0200901 const void *match_data,
902 unsigned int *match_start)
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400903{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200904 TRACE_APPLY (nullptr);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400905
Behdad Esfahbod365576d2015-01-29 13:59:42 +0100906 hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
Behdad Esfahbodb051be52015-01-29 13:40:39 +0100907 skippy_iter.reset (c->buffer->backtrack_len (), count);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500908 skippy_iter.set_match_func (match_func, match_data, backtrack);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400909
Behdad Esfahbod4d3aeb82012-01-16 16:43:26 -0500910 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500911 if (!skippy_iter.prev ())
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100912 return_trace (false);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400913
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +0200914 *match_start = skippy_iter.idx;
915
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100916 return_trace (true);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400917}
918
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400919static inline bool match_lookahead (hb_apply_context_t *c,
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400920 unsigned int count,
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -0800921 const UINT16 lookahead[],
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400922 match_func_t match_func,
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -0400923 const void *match_data,
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +0200924 unsigned int offset,
925 unsigned int *end_index)
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400926{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200927 TRACE_APPLY (nullptr);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400928
Behdad Esfahbod365576d2015-01-29 13:59:42 +0100929 hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
Behdad Esfahbodb051be52015-01-29 13:40:39 +0100930 skippy_iter.reset (c->buffer->idx + offset - 1, count);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500931 skippy_iter.set_match_func (match_func, match_data, lookahead);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400932
Behdad Esfahbod370f03e2012-01-16 17:03:55 -0500933 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500934 if (!skippy_iter.next ())
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100935 return_trace (false);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400936
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +0200937 *end_index = skippy_iter.idx + 1;
938
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100939 return_trace (true);
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -0400940}
941
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -0400942
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -0400943
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400944struct LookupRecord
945{
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300946 inline bool sanitize (hb_sanitize_context_t *c) const
947 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500948 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100949 return_trace (c->check_struct (this));
Behdad Esfahbodcd3827e2009-08-04 02:09:34 -0400950 }
951
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -0800952 UINT16 sequenceIndex; /* Index into current glyph
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -0400953 * sequence--first glyph = 0 */
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -0800954 UINT16 lookupListIndex; /* Lookup to apply to that
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -0400955 * position--zero--based */
Behdad Esfahbod569da922010-05-10 16:38:32 -0400956 public:
957 DEFINE_SIZE_STATIC (4);
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -0400958};
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -0400959
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -0400960
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500961template <typename context_t>
962static inline void recurse_lookups (context_t *c,
963 unsigned int lookupCount,
964 const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400965{
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400966 for (unsigned int i = 0; i < lookupCount; i++)
Behdad Esfahbod86522e42013-07-22 19:07:53 -0400967 c->recurse (lookupRecord[i].lookupListIndex);
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400968}
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -0400969
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400970static inline bool apply_lookup (hb_apply_context_t *c,
Behdad Esfahbode072c242009-05-18 03:47:31 -0400971 unsigned int count, /* Including the first glyph */
Behdad Esfahbod5ba45042015-11-02 15:43:08 -0800972 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
Behdad Esfahbode072c242009-05-18 03:47:31 -0400973 unsigned int lookupCount,
Behdad Esfahbod6b65a762013-10-14 18:51:39 +0200974 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
975 unsigned int match_length)
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -0400976{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200977 TRACE_APPLY (nullptr);
Behdad Esfahbod902cc8a2012-11-23 15:06:59 -0500978
Behdad Esfahbod6b65a762013-10-14 18:51:39 +0200979 hb_buffer_t *buffer = c->buffer;
jfkthame44f7d6e2017-02-17 03:03:24 +0000980 int end;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -0400981
Behdad Esfahbod6b65a762013-10-14 18:51:39 +0200982 /* All positions are distance from beginning of *output* buffer.
983 * Adjust. */
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400984 {
Behdad Esfahbod6b65a762013-10-14 18:51:39 +0200985 unsigned int bl = buffer->backtrack_len ();
986 end = bl + match_length;
Behdad Esfahbod8751de52013-07-18 16:29:50 -0400987
Behdad Esfahbod6b65a762013-10-14 18:51:39 +0200988 int delta = bl - buffer->idx;
989 /* Convert positions to new indexing. */
990 for (unsigned int j = 0; j < count; j++)
991 match_positions[j] += delta;
Behdad Esfahbod8820bb22013-02-14 07:41:03 -0500992 }
Behdad Esfahbode73a0c22009-05-18 04:15:25 -0400993
Behdad Esfahbodb87e36f2016-02-19 14:52:31 +0700994 for (unsigned int i = 0; i < lookupCount && !buffer->in_error; i++)
Behdad Esfahbod6b65a762013-10-14 18:51:39 +0200995 {
996 unsigned int idx = lookupRecord[i].sequenceIndex;
997 if (idx >= count)
998 continue;
999
Behdad Esfahbod9cc1ed42015-11-19 12:39:09 -08001000 /* Don't recurse to ourself at same position.
1001 * Note that this test is too naive, it doesn't catch longer loops. */
1002 if (idx == 0 && lookupRecord[i].lookupListIndex == c->lookup_index)
1003 continue;
1004
Behdad Esfahbode5930722017-11-14 15:47:55 -08001005 if (unlikely (!buffer->move_to (match_positions[idx])))
1006 break;
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001007
Behdad Esfahbodbaf77792017-11-14 21:53:48 -08001008 if (unlikely (buffer->max_ops <= 0))
1009 break;
1010
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001011 unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
1012 if (!c->recurse (lookupRecord[i].lookupListIndex))
1013 continue;
1014
1015 unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len ();
1016 int delta = new_len - orig_len;
1017
1018 if (!delta)
1019 continue;
1020
Behdad Esfahbod9ac9af72017-03-05 13:51:01 -08001021 /* Recursed lookup changed buffer len. Adjust.
1022 *
1023 * TODO:
1024 *
1025 * Right now, if buffer length increased by n, we assume n new glyphs
1026 * were added right after the current position, and if buffer length
1027 * was decreased by n, we assume n match positions after the current
1028 * one where removed. The former (buffer length increased) case is
1029 * fine, but the decrease case can be improved in at least two ways,
1030 * both of which are significant:
1031 *
1032 * - If recursed-to lookup is MultipleSubst and buffer length
1033 * decreased, then it's current match position that was deleted,
1034 * NOT the one after it.
1035 *
1036 * - If buffer length was decreased by n, it does not necessarily
1037 * mean that n match positions where removed, as there might
1038 * have been marks and default-ignorables in the sequence. We
1039 * should instead drop match positions between current-position
1040 * and current-position + n instead.
1041 *
1042 * It should be possible to construct tests for both of these cases.
1043 */
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001044
jfkthame44f7d6e2017-02-17 03:03:24 +00001045 end += delta;
Behdad Esfahbod47e7a182017-03-10 13:23:02 -08001046 if (end <= int (match_positions[idx]))
Behdad Esfahbod359dead2016-05-06 16:19:19 +01001047 {
Behdad Esfahbod4b4a1b92016-12-21 23:10:43 -06001048 /* End might end up being smaller than match_positions[idx] if the recursed
Behdad Esfahbod47e7a182017-03-10 13:23:02 -08001049 * lookup ended up removing many items, more than we have had matched.
Behdad Esfahbod4b4a1b92016-12-21 23:10:43 -06001050 * Just never rewind end back and get out of here.
1051 * https://bugs.chromium.org/p/chromium/issues/detail?id=659496 */
1052 end = match_positions[idx];
Behdad Esfahbod47e7a182017-03-10 13:23:02 -08001053 /* There can't be any further changes. */
Behdad Esfahbod359dead2016-05-06 16:19:19 +01001054 break;
1055 }
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001056
1057 unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */
1058
1059 if (delta > 0)
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001060 {
Behdad Esfahbod5ba45042015-11-02 15:43:08 -08001061 if (unlikely (delta + count > HB_MAX_CONTEXT_LENGTH))
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001062 break;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001063 }
1064 else
1065 {
Behdad Esfahbod47e7a182017-03-10 13:23:02 -08001066 /* NOTE: delta is negative. */
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001067 delta = MAX (delta, (int) next - (int) count);
1068 next -= delta;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001069 }
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001070
1071 /* Shift! */
1072 memmove (match_positions + next + delta, match_positions + next,
1073 (count - next) * sizeof (match_positions[0]));
1074 next += delta;
1075 count += delta;
1076
1077 /* Fill in new entries. */
1078 for (unsigned int j = idx + 1; j < next; j++)
1079 match_positions[j] = match_positions[j - 1] + 1;
1080
1081 /* And fixup the rest. */
1082 for (; next < count; next++)
1083 match_positions[next] += delta;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001084 }
1085
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001086 buffer->move_to (end);
1087
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001088 return_trace (true);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001089}
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001090
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04001091
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001092
1093/* Contextual lookups */
1094
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001095struct ContextClosureLookupContext
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001096{
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001097 ContextClosureFuncs funcs;
1098 const void *intersects_data;
1099};
1100
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001101struct ContextCollectGlyphsLookupContext
1102{
1103 ContextCollectGlyphsFuncs funcs;
1104 const void *collect_data;
1105};
1106
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001107struct ContextApplyLookupContext
1108{
1109 ContextApplyFuncs funcs;
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04001110 const void *match_data;
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001111};
1112
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001113static inline void context_closure_lookup (hb_closure_context_t *c,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001114 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08001115 const UINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001116 unsigned int lookupCount,
1117 const LookupRecord lookupRecord[],
1118 ContextClosureLookupContext &lookup_context)
1119{
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001120 if (intersects_array (c,
1121 inputCount ? inputCount - 1 : 0, input,
1122 lookup_context.funcs.intersects, lookup_context.intersects_data))
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001123 recurse_lookups (c,
1124 lookupCount, lookupRecord);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001125}
1126
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001127static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
1128 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08001129 const UINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001130 unsigned int lookupCount,
1131 const LookupRecord lookupRecord[],
1132 ContextCollectGlyphsLookupContext &lookup_context)
1133{
Behdad Esfahbod83035932012-12-04 17:08:41 -05001134 collect_array (c, c->input,
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001135 inputCount ? inputCount - 1 : 0, input,
1136 lookup_context.funcs.collect, lookup_context.collect_data);
1137 recurse_lookups (c,
1138 lookupCount, lookupRecord);
1139}
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001140
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001141static inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
1142 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08001143 const UINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbod0beb66e2012-12-05 18:46:04 -05001144 unsigned int lookupCount HB_UNUSED,
1145 const LookupRecord lookupRecord[] HB_UNUSED,
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001146 ContextApplyLookupContext &lookup_context)
1147{
1148 return would_match_input (c,
1149 inputCount, input,
1150 lookup_context.funcs.match, lookup_context.match_data);
1151}
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001152static inline bool context_apply_lookup (hb_apply_context_t *c,
1153 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08001154 const UINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001155 unsigned int lookupCount,
1156 const LookupRecord lookupRecord[],
1157 ContextApplyLookupContext &lookup_context)
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001158{
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001159 unsigned int match_length = 0;
Behdad Esfahbod5ba45042015-11-02 15:43:08 -08001160 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001161 return match_input (c,
Behdad Esfahbod41697102010-05-05 01:37:58 -04001162 inputCount, input,
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001163 lookup_context.funcs.match, lookup_context.match_data,
1164 &match_length, match_positions)
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001165 && (c->buffer->unsafe_to_break (c->buffer->idx, c->buffer->idx + match_length),
1166 apply_lookup (c,
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001167 inputCount, match_positions,
1168 lookupCount, lookupRecord,
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001169 match_length));
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001170}
1171
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001172struct Rule
1173{
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001174 inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001175 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001176 TRACE_CLOSURE (this);
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001177 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001178 context_closure_lookup (c,
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001179 inputCount, inputZ,
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001180 lookupCount, lookupRecord,
1181 lookup_context);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001182 }
1183
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001184 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const
1185 {
1186 TRACE_COLLECT_GLYPHS (this);
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001187 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001188 context_collect_glyphs_lookup (c,
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001189 inputCount, inputZ,
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001190 lookupCount, lookupRecord,
1191 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 Esfahbod093c5202014-12-12 21:07:53 -08001197 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001198 return_trace (context_would_apply_lookup (c, inputCount, inputZ, lookupCount, lookupRecord, lookup_context));
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001199 }
1200
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001201 inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001202 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001203 TRACE_APPLY (this);
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001204 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (inputZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001205 return_trace (context_apply_lookup (c, inputCount, inputZ, lookupCount, lookupRecord, lookup_context));
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001206 }
1207
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001208 public:
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001209 inline bool sanitize (hb_sanitize_context_t *c) const
1210 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001211 TRACE_SANITIZE (this);
Behdad Esfahbod5aad8192017-11-03 17:16:26 -04001212 return_trace (inputCount.sanitize (c) &&
1213 lookupCount.sanitize (c) &&
1214 c->check_range (inputZ,
1215 inputZ[0].static_size * inputCount +
1216 lookupRecordX[0].static_size * lookupCount));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001217 }
1218
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001219 protected:
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08001220 UINT16 inputCount; /* Total number of glyphs in input
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001221 * glyph sequence--includes the first
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001222 * glyph */
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08001223 UINT16 lookupCount; /* Number of LookupRecords */
1224 UINT16 inputZ[VAR]; /* Array of match inputs--start with
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001225 * second glyph */
Behdad Esfahbodd3480ba2009-11-03 10:47:29 -05001226 LookupRecord lookupRecordX[VAR]; /* Array of LookupRecords--in
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001227 * design order */
Behdad Esfahbod569da922010-05-10 16:38:32 -04001228 public:
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001229 DEFINE_SIZE_ARRAY2 (4, inputZ, lookupRecordX);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001230};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001231
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001232struct RuleSet
1233{
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001234 inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001235 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001236 TRACE_CLOSURE (this);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001237 unsigned int num_rules = rule.len;
1238 for (unsigned int i = 0; i < num_rules; i++)
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001239 (this+rule[i]).closure (c, lookup_context);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001240 }
1241
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001242 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const
1243 {
1244 TRACE_COLLECT_GLYPHS (this);
1245 unsigned int num_rules = rule.len;
1246 for (unsigned int i = 0; i < num_rules; i++)
1247 (this+rule[i]).collect_glyphs (c, lookup_context);
1248 }
1249
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001250 inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
1251 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001252 TRACE_WOULD_APPLY (this);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001253 unsigned int num_rules = rule.len;
1254 for (unsigned int i = 0; i < num_rules; i++)
1255 {
1256 if ((this+rule[i]).would_apply (c, lookup_context))
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001257 return_trace (true);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001258 }
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001259 return_trace (false);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001260 }
1261
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001262 inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001263 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001264 TRACE_APPLY (this);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001265 unsigned int num_rules = rule.len;
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001266 for (unsigned int i = 0; i < num_rules; i++)
1267 {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001268 if ((this+rule[i]).apply (c, lookup_context))
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001269 return_trace (true);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001270 }
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001271 return_trace (false);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001272 }
1273
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001274 inline bool sanitize (hb_sanitize_context_t *c) const
1275 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001276 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001277 return_trace (rule.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001278 }
1279
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001280 protected:
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001281 OffsetArrayOf<Rule>
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001282 rule; /* Array of Rule tables
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001283 * ordered by preference */
Behdad Esfahboded074222010-05-10 18:08:46 -04001284 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04001285 DEFINE_SIZE_ARRAY (2, rule);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001286};
1287
1288
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001289struct ContextFormat1
1290{
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001291 inline void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001292 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001293 TRACE_CLOSURE (this);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001294
1295 const Coverage &cov = (this+coverage);
1296
1297 struct ContextClosureLookupContext lookup_context = {
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001298 {intersects_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001299 nullptr
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001300 };
1301
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001302 unsigned int count = ruleSet.len;
1303 for (unsigned int i = 0; i < count; i++)
1304 if (cov.intersects_coverage (c->glyphs, i)) {
1305 const RuleSet &rule_set = this+ruleSet[i];
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001306 rule_set.closure (c, lookup_context);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001307 }
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001308 }
1309
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001310 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1311 {
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001312 TRACE_COLLECT_GLYPHS (this);
Behdad Esfahbod83035932012-12-04 17:08:41 -05001313 (this+coverage).add_coverage (c->input);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001314
1315 struct ContextCollectGlyphsLookupContext lookup_context = {
1316 {collect_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001317 nullptr
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001318 };
1319
1320 unsigned int count = ruleSet.len;
1321 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001322 (this+ruleSet[i]).collect_glyphs (c, lookup_context);
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001323 }
1324
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001325 inline bool would_apply (hb_would_apply_context_t *c) const
1326 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001327 TRACE_WOULD_APPLY (this);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001328
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05001329 const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001330 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001331 {match_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001332 nullptr
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001333 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001334 return_trace (rule_set.would_apply (c, lookup_context));
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001335 }
1336
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001337 inline const Coverage &get_coverage (void) const
1338 {
1339 return this+coverage;
1340 }
1341
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001342 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001343 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001344 TRACE_APPLY (this);
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05001345 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -04001346 if (likely (index == NOT_COVERED))
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001347 return_trace (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04001348
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001349 const RuleSet &rule_set = this+ruleSet[index];
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001350 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001351 {match_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001352 nullptr
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001353 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001354 return_trace (rule_set.apply (c, lookup_context));
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001355 }
1356
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001357 inline bool sanitize (hb_sanitize_context_t *c) const
1358 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001359 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001360 return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001361 }
1362
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001363 protected:
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08001364 UINT16 format; /* Format identifier--format = 1 */
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001365 OffsetTo<Coverage>
1366 coverage; /* Offset to Coverage table--from
1367 * beginning of table */
1368 OffsetArrayOf<RuleSet>
1369 ruleSet; /* Array of RuleSet tables
1370 * ordered by Coverage Index */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04001371 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04001372 DEFINE_SIZE_ARRAY (6, ruleSet);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001373};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001374
1375
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001376struct ContextFormat2
1377{
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001378 inline void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001379 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001380 TRACE_CLOSURE (this);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001381 if (!(this+coverage).intersects (c->glyphs))
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001382 return;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001383
1384 const ClassDef &class_def = this+classDef;
1385
1386 struct ContextClosureLookupContext lookup_context = {
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001387 {intersects_class},
Behdad Esfahbod11fba792013-01-02 23:36:37 -06001388 &class_def
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001389 };
1390
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001391 unsigned int count = ruleSet.len;
1392 for (unsigned int i = 0; i < count; i++)
1393 if (class_def.intersects_class (c->glyphs, i)) {
1394 const RuleSet &rule_set = this+ruleSet[i];
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001395 rule_set.closure (c, lookup_context);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001396 }
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001397 }
1398
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001399 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1400 {
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001401 TRACE_COLLECT_GLYPHS (this);
Behdad Esfahbod83035932012-12-04 17:08:41 -05001402 (this+coverage).add_coverage (c->input);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001403
Behdad Esfahbod11fba792013-01-02 23:36:37 -06001404 const ClassDef &class_def = this+classDef;
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001405 struct ContextCollectGlyphsLookupContext lookup_context = {
1406 {collect_class},
Behdad Esfahbod11fba792013-01-02 23:36:37 -06001407 &class_def
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001408 };
1409
1410 unsigned int count = ruleSet.len;
1411 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001412 (this+ruleSet[i]).collect_glyphs (c, lookup_context);
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001413 }
1414
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001415 inline bool would_apply (hb_would_apply_context_t *c) const
1416 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001417 TRACE_WOULD_APPLY (this);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001418
1419 const ClassDef &class_def = this+classDef;
Behdad Esfahbod2dc11412012-11-24 19:16:34 -05001420 unsigned int index = class_def.get_class (c->glyphs[0]);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001421 const RuleSet &rule_set = this+ruleSet[index];
1422 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001423 {match_class},
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001424 &class_def
1425 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001426 return_trace (rule_set.would_apply (c, lookup_context));
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001427 }
1428
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001429 inline const Coverage &get_coverage (void) const
1430 {
1431 return this+coverage;
1432 }
1433
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001434 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001435 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001436 TRACE_APPLY (this);
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05001437 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001438 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04001439
1440 const ClassDef &class_def = this+classDef;
Behdad Esfahbod2dc11412012-11-24 19:16:34 -05001441 index = class_def.get_class (c->buffer->cur().codepoint);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001442 const RuleSet &rule_set = this+ruleSet[index];
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001443 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001444 {match_class},
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04001445 &class_def
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001446 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001447 return_trace (rule_set.apply (c, lookup_context));
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001448 }
1449
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001450 inline bool sanitize (hb_sanitize_context_t *c) const
1451 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001452 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001453 return_trace (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001454 }
1455
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001456 protected:
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08001457 UINT16 format; /* Format identifier--format = 2 */
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001458 OffsetTo<Coverage>
1459 coverage; /* Offset to Coverage table--from
1460 * beginning of table */
1461 OffsetTo<ClassDef>
1462 classDef; /* Offset to glyph ClassDef table--from
1463 * beginning of table */
1464 OffsetArrayOf<RuleSet>
1465 ruleSet; /* Array of RuleSet tables
1466 * ordered by class */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04001467 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04001468 DEFINE_SIZE_ARRAY (8, ruleSet);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001469};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001470
1471
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001472struct ContextFormat3
1473{
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001474 inline void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001475 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001476 TRACE_CLOSURE (this);
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001477 if (!(this+coverageZ[0]).intersects (c->glyphs))
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001478 return;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001479
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001480 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001481 struct ContextClosureLookupContext lookup_context = {
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001482 {intersects_coverage},
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001483 this
1484 };
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001485 context_closure_lookup (c,
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08001486 glyphCount, (const UINT16 *) (coverageZ + 1),
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001487 lookupCount, lookupRecord,
1488 lookup_context);
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001489 }
1490
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001491 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1492 {
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001493 TRACE_COLLECT_GLYPHS (this);
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001494 (this+coverageZ[0]).add_coverage (c->input);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001495
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001496 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001497 struct ContextCollectGlyphsLookupContext lookup_context = {
1498 {collect_coverage},
Behdad Esfahbode75943d2012-11-30 08:38:24 +02001499 this
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001500 };
1501
1502 context_collect_glyphs_lookup (c,
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08001503 glyphCount, (const UINT16 *) (coverageZ + 1),
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001504 lookupCount, lookupRecord,
1505 lookup_context);
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001506 }
1507
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001508 inline bool would_apply (hb_would_apply_context_t *c) const
1509 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001510 TRACE_WOULD_APPLY (this);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001511
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001512 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001513 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001514 {match_coverage},
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001515 this
1516 };
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08001517 return_trace (context_would_apply_lookup (c, glyphCount, (const UINT16 *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001518 }
1519
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001520 inline const Coverage &get_coverage (void) const
1521 {
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001522 return this+coverageZ[0];
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001523 }
1524
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001525 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001526 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001527 TRACE_APPLY (this);
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001528 unsigned int index = (this+coverageZ[0]).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001529 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04001530
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001531 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * glyphCount);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001532 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001533 {match_coverage},
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04001534 this
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001535 };
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08001536 return_trace (context_apply_lookup (c, glyphCount, (const UINT16 *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001537 }
1538
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001539 inline bool sanitize (hb_sanitize_context_t *c) const
1540 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001541 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001542 if (!c->check_struct (this)) return_trace (false);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001543 unsigned int count = glyphCount;
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001544 if (!count) return_trace (false); /* We want to access coverageZ[0] freely. */
1545 if (!c->check_array (coverageZ, coverageZ[0].static_size, count)) return_trace (false);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001546 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001547 if (!coverageZ[i].sanitize (c, this)) return_trace (false);
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001548 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * count);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001549 return_trace (c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001550 }
1551
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001552 protected:
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08001553 UINT16 format; /* Format identifier--format = 3 */
1554 UINT16 glyphCount; /* Number of glyphs in the input glyph
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001555 * sequence */
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08001556 UINT16 lookupCount; /* Number of LookupRecords */
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04001557 OffsetTo<Coverage>
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001558 coverageZ[VAR]; /* Array of offsets to Coverage
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04001559 * table in glyph sequence order */
Behdad Esfahbodd3480ba2009-11-03 10:47:29 -05001560 LookupRecord lookupRecordX[VAR]; /* Array of LookupRecords--in
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001561 * design order */
Behdad Esfahbod569da922010-05-10 16:38:32 -04001562 public:
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001563 DEFINE_SIZE_ARRAY2 (6, coverageZ, lookupRecordX);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001564};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001565
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001566struct Context
1567{
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001568 template <typename context_t>
Behdad Esfahbod9c5a9ee2013-03-09 01:55:04 -05001569 inline typename context_t::return_t dispatch (context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001570 {
Behdad Esfahbod00f6a8e2014-12-12 20:36:49 -08001571 TRACE_DISPATCH (this, u.format);
Behdad Esfahbodf396fbb2015-10-09 12:25:55 -04001572 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001573 switch (u.format) {
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001574 case 1: return_trace (c->dispatch (u.format1));
1575 case 2: return_trace (c->dispatch (u.format2));
1576 case 3: return_trace (c->dispatch (u.format3));
1577 default:return_trace (c->default_return_value ());
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001578 }
1579 }
1580
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001581 protected:
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001582 union {
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08001583 UINT16 format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -04001584 ContextFormat1 format1;
1585 ContextFormat2 format2;
1586 ContextFormat3 format3;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001587 } u;
1588};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001589
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001590
1591/* Chaining Contextual lookups */
1592
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001593struct ChainContextClosureLookupContext
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001594{
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001595 ContextClosureFuncs funcs;
1596 const void *intersects_data[3];
1597};
1598
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001599struct ChainContextCollectGlyphsLookupContext
1600{
1601 ContextCollectGlyphsFuncs funcs;
1602 const void *collect_data[3];
1603};
1604
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001605struct ChainContextApplyLookupContext
1606{
1607 ContextApplyFuncs funcs;
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04001608 const void *match_data[3];
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001609};
1610
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001611static inline void chain_context_closure_lookup (hb_closure_context_t *c,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001612 unsigned int backtrackCount,
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08001613 const UINT16 backtrack[],
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001614 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08001615 const UINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001616 unsigned int lookaheadCount,
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08001617 const UINT16 lookahead[],
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001618 unsigned int lookupCount,
1619 const LookupRecord lookupRecord[],
1620 ChainContextClosureLookupContext &lookup_context)
1621{
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001622 if (intersects_array (c,
1623 backtrackCount, backtrack,
1624 lookup_context.funcs.intersects, lookup_context.intersects_data[0])
1625 && intersects_array (c,
1626 inputCount ? inputCount - 1 : 0, input,
1627 lookup_context.funcs.intersects, lookup_context.intersects_data[1])
Behdad Esfahbod74439d02013-07-22 19:02:29 -04001628 && intersects_array (c,
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001629 lookaheadCount, lookahead,
1630 lookup_context.funcs.intersects, lookup_context.intersects_data[2]))
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001631 recurse_lookups (c,
1632 lookupCount, lookupRecord);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001633}
1634
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001635static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
1636 unsigned int backtrackCount,
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08001637 const UINT16 backtrack[],
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001638 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08001639 const UINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001640 unsigned int lookaheadCount,
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08001641 const UINT16 lookahead[],
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001642 unsigned int lookupCount,
1643 const LookupRecord lookupRecord[],
1644 ChainContextCollectGlyphsLookupContext &lookup_context)
1645{
Behdad Esfahbod83035932012-12-04 17:08:41 -05001646 collect_array (c, c->before,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001647 backtrackCount, backtrack,
1648 lookup_context.funcs.collect, lookup_context.collect_data[0]);
Behdad Esfahbod83035932012-12-04 17:08:41 -05001649 collect_array (c, c->input,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001650 inputCount ? inputCount - 1 : 0, input,
1651 lookup_context.funcs.collect, lookup_context.collect_data[1]);
Behdad Esfahbod83035932012-12-04 17:08:41 -05001652 collect_array (c, c->after,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001653 lookaheadCount, lookahead,
1654 lookup_context.funcs.collect, lookup_context.collect_data[2]);
1655 recurse_lookups (c,
1656 lookupCount, lookupRecord);
1657}
1658
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001659static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c,
1660 unsigned int backtrackCount,
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08001661 const UINT16 backtrack[] HB_UNUSED,
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001662 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08001663 const UINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001664 unsigned int lookaheadCount,
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08001665 const UINT16 lookahead[] HB_UNUSED,
Behdad Esfahbod0beb66e2012-12-05 18:46:04 -05001666 unsigned int lookupCount HB_UNUSED,
1667 const LookupRecord lookupRecord[] HB_UNUSED,
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001668 ChainContextApplyLookupContext &lookup_context)
1669{
Behdad Esfahbodd9b204d2012-08-23 16:22:28 -04001670 return (c->zero_context ? !backtrackCount && !lookaheadCount : true)
Behdad Esfahbod1f2bb172012-08-23 16:10:37 -04001671 && would_match_input (c,
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001672 inputCount, input,
1673 lookup_context.funcs.match, lookup_context.match_data[1]);
1674}
1675
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001676static inline bool chain_context_apply_lookup (hb_apply_context_t *c,
1677 unsigned int backtrackCount,
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08001678 const UINT16 backtrack[],
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001679 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08001680 const UINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001681 unsigned int lookaheadCount,
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08001682 const UINT16 lookahead[],
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001683 unsigned int lookupCount,
1684 const LookupRecord lookupRecord[],
1685 ChainContextApplyLookupContext &lookup_context)
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04001686{
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001687 unsigned int start_index = 0, match_length = 0, end_index = 0;
Behdad Esfahbod5ba45042015-11-02 15:43:08 -08001688 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
Behdad Esfahbodf19e0b02012-06-09 02:26:57 -04001689 return match_input (c,
Behdad Esfahbod41697102010-05-05 01:37:58 -04001690 inputCount, input,
1691 lookup_context.funcs.match, lookup_context.match_data[1],
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001692 &match_length, match_positions)
Behdad Esfahbodf19e0b02012-06-09 02:26:57 -04001693 && match_backtrack (c,
1694 backtrackCount, backtrack,
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001695 lookup_context.funcs.match, lookup_context.match_data[0],
1696 &start_index)
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001697 && match_lookahead (c,
Behdad Esfahbod41697102010-05-05 01:37:58 -04001698 lookaheadCount, lookahead,
1699 lookup_context.funcs.match, lookup_context.match_data[2],
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001700 match_length, &end_index)
1701 && (c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index),
1702 apply_lookup (c,
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001703 inputCount, match_positions,
1704 lookupCount, lookupRecord,
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001705 match_length));
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04001706}
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001707
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001708struct ChainRule
1709{
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001710 inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001711 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001712 TRACE_CLOSURE (this);
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08001713 const HeadlessArrayOf<UINT16> &input = StructAfter<HeadlessArrayOf<UINT16> > (backtrack);
1714 const ArrayOf<UINT16> &lookahead = StructAfter<ArrayOf<UINT16> > (input);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001715 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001716 chain_context_closure_lookup (c,
1717 backtrack.len, backtrack.array,
1718 input.len, input.array,
1719 lookahead.len, lookahead.array,
1720 lookup.len, lookup.array,
1721 lookup_context);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001722 }
1723
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001724 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
1725 {
1726 TRACE_COLLECT_GLYPHS (this);
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08001727 const HeadlessArrayOf<UINT16> &input = StructAfter<HeadlessArrayOf<UINT16> > (backtrack);
1728 const ArrayOf<UINT16> &lookahead = StructAfter<ArrayOf<UINT16> > (input);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001729 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1730 chain_context_collect_glyphs_lookup (c,
1731 backtrack.len, backtrack.array,
1732 input.len, input.array,
1733 lookahead.len, lookahead.array,
1734 lookup.len, lookup.array,
1735 lookup_context);
1736 }
1737
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001738 inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
1739 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001740 TRACE_WOULD_APPLY (this);
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08001741 const HeadlessArrayOf<UINT16> &input = StructAfter<HeadlessArrayOf<UINT16> > (backtrack);
1742 const ArrayOf<UINT16> &lookahead = StructAfter<ArrayOf<UINT16> > (input);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001743 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001744 return_trace (chain_context_would_apply_lookup (c,
1745 backtrack.len, backtrack.array,
1746 input.len, input.array,
1747 lookahead.len, lookahead.array, lookup.len,
1748 lookup.array, lookup_context));
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001749 }
1750
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001751 inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001752 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001753 TRACE_APPLY (this);
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08001754 const HeadlessArrayOf<UINT16> &input = StructAfter<HeadlessArrayOf<UINT16> > (backtrack);
1755 const ArrayOf<UINT16> &lookahead = StructAfter<ArrayOf<UINT16> > (input);
Behdad Esfahbode961c862010-04-21 15:56:11 -04001756 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001757 return_trace (chain_context_apply_lookup (c,
1758 backtrack.len, backtrack.array,
1759 input.len, input.array,
1760 lookahead.len, lookahead.array, lookup.len,
1761 lookup.array, lookup_context));
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04001762 }
1763
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001764 inline bool sanitize (hb_sanitize_context_t *c) const
1765 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001766 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001767 if (!backtrack.sanitize (c)) return_trace (false);
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08001768 const HeadlessArrayOf<UINT16> &input = StructAfter<HeadlessArrayOf<UINT16> > (backtrack);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001769 if (!input.sanitize (c)) return_trace (false);
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08001770 const ArrayOf<UINT16> &lookahead = StructAfter<ArrayOf<UINT16> > (input);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001771 if (!lookahead.sanitize (c)) return_trace (false);
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001772 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001773 return_trace (lookup.sanitize (c));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001774 }
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001775
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001776 protected:
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08001777 ArrayOf<UINT16>
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04001778 backtrack; /* Array of backtracking values
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001779 * (to be matched before the input
1780 * sequence) */
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08001781 HeadlessArrayOf<UINT16>
Behdad Esfahbode8cbaaf2009-05-18 02:03:58 -04001782 inputX; /* Array of input values (start with
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001783 * second glyph) */
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08001784 ArrayOf<UINT16>
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04001785 lookaheadX; /* Array of lookahead values's (to be
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001786 * matched after the input sequence) */
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04001787 ArrayOf<LookupRecord>
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04001788 lookupX; /* Array of LookupRecords--in
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001789 * design order) */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04001790 public:
Behdad Esfahbodbea34c72010-05-10 17:28:16 -04001791 DEFINE_SIZE_MIN (8);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001792};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001793
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001794struct ChainRuleSet
1795{
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001796 inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001797 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001798 TRACE_CLOSURE (this);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001799 unsigned int num_rules = rule.len;
1800 for (unsigned int i = 0; i < num_rules; i++)
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001801 (this+rule[i]).closure (c, lookup_context);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001802 }
1803
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001804 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
1805 {
1806 TRACE_COLLECT_GLYPHS (this);
1807 unsigned int num_rules = rule.len;
1808 for (unsigned int i = 0; i < num_rules; i++)
1809 (this+rule[i]).collect_glyphs (c, lookup_context);
1810 }
1811
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001812 inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
1813 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001814 TRACE_WOULD_APPLY (this);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001815 unsigned int num_rules = rule.len;
1816 for (unsigned int i = 0; i < num_rules; i++)
1817 if ((this+rule[i]).would_apply (c, lookup_context))
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001818 return_trace (true);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001819
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001820 return_trace (false);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001821 }
1822
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001823 inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001824 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001825 TRACE_APPLY (this);
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001826 unsigned int num_rules = rule.len;
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001827 for (unsigned int i = 0; i < num_rules; i++)
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001828 if ((this+rule[i]).apply (c, lookup_context))
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001829 return_trace (true);
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001830
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001831 return_trace (false);
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001832 }
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001833
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001834 inline bool sanitize (hb_sanitize_context_t *c) const
1835 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001836 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001837 return_trace (rule.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001838 }
1839
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001840 protected:
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001841 OffsetArrayOf<ChainRule>
1842 rule; /* Array of ChainRule tables
1843 * ordered by preference */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04001844 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04001845 DEFINE_SIZE_ARRAY (2, rule);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001846};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001847
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001848struct ChainContextFormat1
1849{
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001850 inline void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001851 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001852 TRACE_CLOSURE (this);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001853 const Coverage &cov = (this+coverage);
1854
1855 struct ChainContextClosureLookupContext lookup_context = {
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001856 {intersects_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001857 {nullptr, nullptr, nullptr}
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001858 };
1859
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001860 unsigned int count = ruleSet.len;
1861 for (unsigned int i = 0; i < count; i++)
1862 if (cov.intersects_coverage (c->glyphs, i)) {
1863 const ChainRuleSet &rule_set = this+ruleSet[i];
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001864 rule_set.closure (c, lookup_context);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001865 }
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001866 }
1867
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001868 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1869 {
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001870 TRACE_COLLECT_GLYPHS (this);
Behdad Esfahbod83035932012-12-04 17:08:41 -05001871 (this+coverage).add_coverage (c->input);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001872
1873 struct ChainContextCollectGlyphsLookupContext lookup_context = {
1874 {collect_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001875 {nullptr, nullptr, nullptr}
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001876 };
1877
1878 unsigned int count = ruleSet.len;
1879 for (unsigned int i = 0; i < count; i++)
1880 (this+ruleSet[i]).collect_glyphs (c, lookup_context);
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001881 }
1882
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001883 inline bool would_apply (hb_would_apply_context_t *c) const
1884 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001885 TRACE_WOULD_APPLY (this);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001886
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05001887 const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001888 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001889 {match_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001890 {nullptr, nullptr, nullptr}
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001891 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001892 return_trace (rule_set.would_apply (c, lookup_context));
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001893 }
1894
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001895 inline const Coverage &get_coverage (void) const
1896 {
1897 return this+coverage;
1898 }
1899
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001900 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001901 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001902 TRACE_APPLY (this);
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05001903 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001904 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04001905
1906 const ChainRuleSet &rule_set = this+ruleSet[index];
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001907 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001908 {match_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001909 {nullptr, nullptr, nullptr}
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04001910 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001911 return_trace (rule_set.apply (c, lookup_context));
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001912 }
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001913
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001914 inline bool sanitize (hb_sanitize_context_t *c) const
1915 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001916 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001917 return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001918 }
1919
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001920 protected:
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08001921 UINT16 format; /* Format identifier--format = 1 */
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001922 OffsetTo<Coverage>
1923 coverage; /* Offset to Coverage table--from
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001924 * beginning of table */
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04001925 OffsetArrayOf<ChainRuleSet>
1926 ruleSet; /* Array of ChainRuleSet tables
1927 * ordered by Coverage Index */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04001928 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04001929 DEFINE_SIZE_ARRAY (6, ruleSet);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001930};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001931
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001932struct ChainContextFormat2
1933{
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001934 inline void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001935 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001936 TRACE_CLOSURE (this);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001937 if (!(this+coverage).intersects (c->glyphs))
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001938 return;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001939
1940 const ClassDef &backtrack_class_def = this+backtrackClassDef;
1941 const ClassDef &input_class_def = this+inputClassDef;
1942 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
1943
1944 struct ChainContextClosureLookupContext lookup_context = {
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001945 {intersects_class},
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001946 {&backtrack_class_def,
1947 &input_class_def,
1948 &lookahead_class_def}
1949 };
1950
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001951 unsigned int count = ruleSet.len;
1952 for (unsigned int i = 0; i < count; i++)
1953 if (input_class_def.intersects_class (c->glyphs, i)) {
1954 const ChainRuleSet &rule_set = this+ruleSet[i];
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001955 rule_set.closure (c, lookup_context);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001956 }
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001957 }
1958
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001959 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1960 {
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001961 TRACE_COLLECT_GLYPHS (this);
Behdad Esfahbod83035932012-12-04 17:08:41 -05001962 (this+coverage).add_coverage (c->input);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001963
Behdad Esfahbod11fba792013-01-02 23:36:37 -06001964 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 Esfahbodf1b12782012-11-24 01:55:34 -05001968 struct ChainContextCollectGlyphsLookupContext lookup_context = {
1969 {collect_class},
Behdad Esfahbod11fba792013-01-02 23:36:37 -06001970 {&backtrack_class_def,
1971 &input_class_def,
1972 &lookahead_class_def}
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001973 };
1974
1975 unsigned int count = ruleSet.len;
1976 for (unsigned int i = 0; i < count; i++)
1977 (this+ruleSet[i]).collect_glyphs (c, lookup_context);
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001978 }
1979
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001980 inline bool would_apply (hb_would_apply_context_t *c) const
1981 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001982 TRACE_WOULD_APPLY (this);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001983
Behdad Esfahbod11fba792013-01-02 23:36:37 -06001984 const ClassDef &backtrack_class_def = this+backtrackClassDef;
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001985 const ClassDef &input_class_def = this+inputClassDef;
Behdad Esfahbod11fba792013-01-02 23:36:37 -06001986 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001987
Behdad Esfahbod2dc11412012-11-24 19:16:34 -05001988 unsigned int index = input_class_def.get_class (c->glyphs[0]);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001989 const ChainRuleSet &rule_set = this+ruleSet[index];
1990 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001991 {match_class},
Behdad Esfahbod11fba792013-01-02 23:36:37 -06001992 {&backtrack_class_def,
1993 &input_class_def,
1994 &lookahead_class_def}
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001995 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001996 return_trace (rule_set.would_apply (c, lookup_context));
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001997 }
1998
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001999 inline const Coverage &get_coverage (void) const
2000 {
2001 return this+coverage;
2002 }
2003
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002004 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002005 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002006 TRACE_APPLY (this);
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05002007 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002008 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002009
2010 const ClassDef &backtrack_class_def = this+backtrackClassDef;
2011 const ClassDef &input_class_def = this+inputClassDef;
2012 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2013
Behdad Esfahbod2dc11412012-11-24 19:16:34 -05002014 index = input_class_def.get_class (c->buffer->cur().codepoint);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002015 const ChainRuleSet &rule_set = this+ruleSet[index];
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002016 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002017 {match_class},
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04002018 {&backtrack_class_def,
2019 &input_class_def,
2020 &lookahead_class_def}
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002021 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002022 return_trace (rule_set.apply (c, lookup_context));
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002023 }
2024
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002025 inline bool sanitize (hb_sanitize_context_t *c) const
2026 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002027 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002028 return_trace (coverage.sanitize (c, this) &&
2029 backtrackClassDef.sanitize (c, this) &&
2030 inputClassDef.sanitize (c, this) &&
2031 lookaheadClassDef.sanitize (c, this) &&
2032 ruleSet.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002033 }
2034
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002035 protected:
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08002036 UINT16 format; /* Format identifier--format = 2 */
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002037 OffsetTo<Coverage>
2038 coverage; /* Offset to Coverage table--from
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002039 * beginning of table */
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002040 OffsetTo<ClassDef>
2041 backtrackClassDef; /* Offset to glyph ClassDef table
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002042 * containing backtrack sequence
2043 * data--from beginning of table */
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002044 OffsetTo<ClassDef>
2045 inputClassDef; /* Offset to glyph ClassDef
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002046 * table containing input sequence
2047 * data--from beginning of table */
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002048 OffsetTo<ClassDef>
2049 lookaheadClassDef; /* Offset to glyph ClassDef table
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002050 * containing lookahead sequence
2051 * data--from beginning of table */
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002052 OffsetArrayOf<ChainRuleSet>
2053 ruleSet; /* Array of ChainRuleSet tables
2054 * ordered by class */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04002055 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04002056 DEFINE_SIZE_ARRAY (12, ruleSet);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002057};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002058
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002059struct ChainContextFormat3
2060{
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002061 inline void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002062 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002063 TRACE_CLOSURE (this);
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002064 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2065
2066 if (!(this+input[0]).intersects (c->glyphs))
2067 return;
2068
2069 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2070 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2071 struct ChainContextClosureLookupContext lookup_context = {
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002072 {intersects_coverage},
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002073 {this, this, this}
2074 };
2075 chain_context_closure_lookup (c,
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08002076 backtrack.len, (const UINT16 *) backtrack.array,
2077 input.len, (const UINT16 *) input.array + 1,
2078 lookahead.len, (const UINT16 *) lookahead.array,
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002079 lookup.len, lookup.array,
2080 lookup_context);
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002081 }
2082
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002083 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
2084 {
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002085 TRACE_COLLECT_GLYPHS (this);
2086 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2087
Behdad Esfahbod83035932012-12-04 17:08:41 -05002088 (this+input[0]).add_coverage (c->input);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002089
2090 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2091 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2092 struct ChainContextCollectGlyphsLookupContext lookup_context = {
2093 {collect_coverage},
2094 {this, this, this}
2095 };
2096 chain_context_collect_glyphs_lookup (c,
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08002097 backtrack.len, (const UINT16 *) backtrack.array,
2098 input.len, (const UINT16 *) input.array + 1,
2099 lookahead.len, (const UINT16 *) lookahead.array,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002100 lookup.len, lookup.array,
2101 lookup_context);
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002102 }
2103
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002104 inline bool would_apply (hb_would_apply_context_t *c) const
2105 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002106 TRACE_WOULD_APPLY (this);
Behdad Esfahbode6f74792012-07-28 18:34:58 -04002107
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002108 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002109 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2110 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2111 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002112 {match_coverage},
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002113 {this, this, this}
2114 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002115 return_trace (chain_context_would_apply_lookup (c,
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08002116 backtrack.len, (const UINT16 *) backtrack.array,
2117 input.len, (const UINT16 *) input.array + 1,
2118 lookahead.len, (const UINT16 *) lookahead.array,
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002119 lookup.len, lookup.array, lookup_context));
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002120 }
2121
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002122 inline const Coverage &get_coverage (void) const
2123 {
2124 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2125 return this+input[0];
2126 }
2127
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002128 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002129 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002130 TRACE_APPLY (this);
Behdad Esfahbode961c862010-04-21 15:56:11 -04002131 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04002132
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05002133 unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002134 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002135
Behdad Esfahbode961c862010-04-21 15:56:11 -04002136 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2137 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002138 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002139 {match_coverage},
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04002140 {this, this, this}
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04002141 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002142 return_trace (chain_context_apply_lookup (c,
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08002143 backtrack.len, (const UINT16 *) backtrack.array,
2144 input.len, (const UINT16 *) input.array + 1,
2145 lookahead.len, (const UINT16 *) lookahead.array,
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002146 lookup.len, lookup.array, lookup_context));
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002147 }
2148
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002149 inline bool sanitize (hb_sanitize_context_t *c) const
2150 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002151 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002152 if (!backtrack.sanitize (c, this)) return_trace (false);
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002153 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002154 if (!input.sanitize (c, this)) return_trace (false);
2155 if (!input.len) return_trace (false); /* To be consistent with Context. */
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002156 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002157 if (!lookahead.sanitize (c, this)) return_trace (false);
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002158 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002159 return_trace (lookup.sanitize (c));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002160 }
2161
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002162 protected:
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08002163 UINT16 format; /* Format identifier--format = 3 */
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04002164 OffsetArrayOf<Coverage>
Behdad Esfahbod13ed4402009-05-18 02:14:37 -04002165 backtrack; /* Array of coverage tables
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002166 * in backtracking sequence, in glyph
2167 * sequence order */
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04002168 OffsetArrayOf<Coverage>
Behdad Esfahbod13ed4402009-05-18 02:14:37 -04002169 inputX ; /* Array of coverage
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002170 * tables in input sequence, in glyph
2171 * sequence order */
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04002172 OffsetArrayOf<Coverage>
Behdad Esfahbod13ed4402009-05-18 02:14:37 -04002173 lookaheadX; /* Array of coverage tables
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002174 * in lookahead sequence, in glyph
2175 * sequence order */
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04002176 ArrayOf<LookupRecord>
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04002177 lookupX; /* Array of LookupRecords--in
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04002178 * design order) */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04002179 public:
Behdad Esfahbodbea34c72010-05-10 17:28:16 -04002180 DEFINE_SIZE_MIN (10);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002181};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002182
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002183struct ChainContext
2184{
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002185 template <typename context_t>
Behdad Esfahbod9c5a9ee2013-03-09 01:55:04 -05002186 inline typename context_t::return_t dispatch (context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002187 {
Behdad Esfahbod00f6a8e2014-12-12 20:36:49 -08002188 TRACE_DISPATCH (this, u.format);
Behdad Esfahbodf396fbb2015-10-09 12:25:55 -04002189 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002190 switch (u.format) {
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002191 case 1: return_trace (c->dispatch (u.format1));
2192 case 2: return_trace (c->dispatch (u.format2));
2193 case 3: return_trace (c->dispatch (u.format3));
2194 default:return_trace (c->default_return_value ());
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002195 }
2196 }
2197
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002198 protected:
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002199 union {
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08002200 UINT16 format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -04002201 ChainContextFormat1 format1;
2202 ChainContextFormat2 format2;
2203 ChainContextFormat3 format3;
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002204 } u;
2205};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002206
2207
Behdad Esfahbod095a1252015-02-19 10:29:41 +03002208template <typename T>
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002209struct ExtensionFormat1
2210{
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002211 inline unsigned int get_type (void) const { return extensionLookupType; }
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002212
Behdad Esfahbod095a1252015-02-19 10:29:41 +03002213 template <typename X>
2214 inline const X& get_subtable (void) const
2215 {
2216 unsigned int offset = extensionOffset;
2217 if (unlikely (!offset)) return Null(typename T::LookupSubTable);
2218 return StructAtOffset<typename T::LookupSubTable> (this, offset);
2219 }
2220
2221 template <typename context_t>
2222 inline typename context_t::return_t dispatch (context_t *c) const
2223 {
2224 TRACE_DISPATCH (this, format);
Behdad Esfahbodf396fbb2015-10-09 12:25:55 -04002225 if (unlikely (!c->may_dispatch (this, this))) return_trace (c->no_dispatch_return_value ());
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002226 return_trace (get_subtable<typename T::LookupSubTable> ().dispatch (c, get_type ()));
Behdad Esfahbod095a1252015-02-19 10:29:41 +03002227 }
2228
2229 /* This is called from may_dispatch() above with hb_sanitize_context_t. */
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002230 inline bool sanitize (hb_sanitize_context_t *c) const
2231 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002232 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002233 return_trace (c->check_struct (this) && extensionOffset != 0);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002234 }
2235
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002236 protected:
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08002237 UINT16 format; /* Format identifier. Set to 1. */
2238 UINT16 extensionLookupType; /* Lookup type of subtable referenced
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002239 * by ExtensionOffset (i.e. the
2240 * extension subtable). */
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08002241 UINT32 extensionOffset; /* Offset to the extension subtable,
Behdad Esfahbod81f2af42010-04-22 00:58:49 -04002242 * of lookup type subtable. */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04002243 public:
2244 DEFINE_SIZE_STATIC (8);
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002245};
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002246
Behdad Esfahbod653eeb22012-11-23 16:57:36 -05002247template <typename T>
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002248struct Extension
2249{
2250 inline unsigned int get_type (void) const
2251 {
2252 switch (u.format) {
Behdad Esfahboddacebca2010-05-10 19:45:41 -04002253 case 1: return u.format1.get_type ();
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002254 default:return 0;
2255 }
2256 }
Behdad Esfahbod7dddd4e2012-11-23 17:04:55 -05002257 template <typename X>
2258 inline const X& get_subtable (void) const
2259 {
Behdad Esfahbod095a1252015-02-19 10:29:41 +03002260 switch (u.format) {
2261 case 1: return u.format1.template get_subtable<typename T::LookupSubTable> ();
2262 default:return Null(typename T::LookupSubTable);
2263 }
Behdad Esfahbod7dddd4e2012-11-23 17:04:55 -05002264 }
2265
Behdad Esfahbod653eeb22012-11-23 16:57:36 -05002266 template <typename context_t>
Behdad Esfahbod9c5a9ee2013-03-09 01:55:04 -05002267 inline typename context_t::return_t dispatch (context_t *c) const
Behdad Esfahbod653eeb22012-11-23 16:57:36 -05002268 {
Behdad Esfahbod095a1252015-02-19 10:29:41 +03002269 TRACE_DISPATCH (this, u.format);
Behdad Esfahbodf396fbb2015-10-09 12:25:55 -04002270 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002271 switch (u.format) {
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002272 case 1: return_trace (u.format1.dispatch (c));
2273 default:return_trace (c->default_return_value ());
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002274 }
2275 }
2276
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002277 protected:
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002278 union {
Behdad Esfahbod6f335ed2017-11-14 21:06:07 -08002279 UINT16 format; /* Format identifier */
Behdad Esfahbod095a1252015-02-19 10:29:41 +03002280 ExtensionFormat1<T> format1;
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002281 } u;
2282};
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002283
2284
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04002285/*
2286 * GSUB/GPOS Common
2287 */
2288
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002289struct GSUBGPOS
2290{
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04002291 inline unsigned int get_script_count (void) const
2292 { return (this+scriptList).len; }
2293 inline const Tag& get_script_tag (unsigned int i) const
2294 { return (this+scriptList).get_tag (i); }
Behdad Esfahbode21899b2009-11-04 16:36:14 -05002295 inline unsigned int get_script_tags (unsigned int start_offset,
2296 unsigned int *script_count /* IN/OUT */,
2297 hb_tag_t *script_tags /* OUT */) const
2298 { return (this+scriptList).get_tags (start_offset, script_count, script_tags); }
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04002299 inline const Script& get_script (unsigned int i) const
2300 { return (this+scriptList)[i]; }
2301 inline bool find_script_index (hb_tag_t tag, unsigned int *index) const
2302 { return (this+scriptList).find_index (tag, index); }
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04002303
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04002304 inline unsigned int get_feature_count (void) const
2305 { return (this+featureList).len; }
Jonathan Kewda132932014-04-27 14:05:24 +01002306 inline hb_tag_t get_feature_tag (unsigned int i) const
2307 { return i == Index::NOT_FOUND_INDEX ? HB_TAG_NONE : (this+featureList).get_tag (i); }
Behdad Esfahbode21899b2009-11-04 16:36:14 -05002308 inline unsigned int get_feature_tags (unsigned int start_offset,
2309 unsigned int *feature_count /* IN/OUT */,
2310 hb_tag_t *feature_tags /* OUT */) const
2311 { return (this+featureList).get_tags (start_offset, feature_count, feature_tags); }
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04002312 inline const Feature& get_feature (unsigned int i) const
2313 { return (this+featureList)[i]; }
2314 inline bool find_feature_index (hb_tag_t tag, unsigned int *index) const
2315 { return (this+featureList).find_index (tag, index); }
2316
2317 inline unsigned int get_lookup_count (void) const
2318 { return (this+lookupList).len; }
2319 inline const Lookup& get_lookup (unsigned int i) const
2320 { return (this+lookupList)[i]; }
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04002321
Behdad Esfahbod30c42b62016-09-10 03:32:39 -07002322 inline bool find_variations_index (const int *coords, unsigned int num_coords,
2323 unsigned int *index) const
Behdad Esfahbod59055b52016-09-10 01:24:28 -07002324 { return (version.to_int () >= 0x00010001u ? this+featureVars : Null(FeatureVariations))
Behdad Esfahbod30c42b62016-09-10 03:32:39 -07002325 .find_index (coords, num_coords, index); }
Behdad Esfahbodec87ba92016-09-10 03:53:11 -07002326 inline const Feature& get_feature_variation (unsigned int feature_index,
2327 unsigned int variations_index) const
2328 {
2329 if (FeatureVariations::NOT_FOUND_INDEX != variations_index &&
2330 version.to_int () >= 0x00010001u)
2331 {
Behdad Esfahbod4ebbeb72016-09-10 04:52:34 -07002332 const Feature *feature = (this+featureVars).find_substitute (variations_index,
2333 feature_index);
Behdad Esfahbodec87ba92016-09-10 03:53:11 -07002334 if (feature)
2335 return *feature;
2336 }
2337 return get_feature (feature_index);
2338 }
Behdad Esfahbod59055b52016-09-10 01:24:28 -07002339
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002340 inline bool sanitize (hb_sanitize_context_t *c) const
2341 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002342 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002343 return_trace (version.sanitize (c) &&
2344 likely (version.major == 1) &&
2345 scriptList.sanitize (c, this) &&
2346 featureList.sanitize (c, this) &&
Behdad Esfahbod59055b52016-09-10 01:24:28 -07002347 lookupList.sanitize (c, this) &&
2348 (version.to_int () < 0x00010001u || featureVars.sanitize (c, this)));
Behdad Esfahbodcd3827e2009-08-04 02:09:34 -04002349 }
2350
Behdad Esfahbod212aba62009-05-24 00:50:27 -04002351 protected:
Behdad Esfahbod9a13ed42016-02-22 11:44:45 +09002352 FixedVersion<>version; /* Version of the GSUB/GPOS table--initially set
Behdad Esfahbod76271002014-07-11 14:54:42 -04002353 * to 0x00010000u */
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04002354 OffsetTo<ScriptList>
2355 scriptList; /* ScriptList table */
2356 OffsetTo<FeatureList>
2357 featureList; /* FeatureList table */
2358 OffsetTo<LookupList>
2359 lookupList; /* LookupList table */
Behdad Esfahbod5e156fa2017-01-22 20:28:56 -08002360 LOffsetTo<FeatureVariations>
Behdad Esfahbod59055b52016-09-10 01:24:28 -07002361 featureVars; /* Offset to Feature Variations
2362 table--from beginning of table
2363 * (may be NULL). Introduced
2364 * in version 0x00010001. */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04002365 public:
Behdad Esfahbod59055b52016-09-10 01:24:28 -07002366 DEFINE_SIZE_MIN (10);
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04002367};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002368
Behdad Esfahbod6f20f722009-05-17 20:28:01 -04002369
Behdad Esfahbod7d52e662012-11-16 18:49:54 -08002370} /* namespace OT */
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -04002371
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04002372
Behdad Esfahbod5f5b24f2009-08-02 20:03:12 -04002373#endif /* HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH */