blob: df03226465947451fde8cec974825f1ee137e869 [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 Esfahbodc77ae402018-08-25 22:36:36 -070029#ifndef HB_OT_LAYOUT_GSUBGPOS_HH
30#define HB_OT_LAYOUT_GSUBGPOS_HH
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -040031
Behdad Esfahbodc77ae402018-08-25 22:36:36 -070032#include "hb.hh"
33#include "hb-buffer.hh"
34#include "hb-map.hh"
Behdad Esfahbodc77ae402018-08-25 22:36:36 -070035#include "hb-set.hh"
Behdad Esfahbodb9291002018-08-26 01:15:47 -070036#include "hb-ot-layout-common.hh"
37#include "hb-ot-layout-gdef-table.hh"
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -040038
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -040039
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -040040namespace OT {
41
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -040042
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -070043struct hb_intersects_context_t :
44 hb_dispatch_context_t<hb_intersects_context_t, bool, 0>
45{
46 inline const char *get_name (void) { return "INTERSECTS"; }
47 template <typename T>
48 inline return_t dispatch (const T &obj) { return obj.intersects (this->glyphs); }
49 static return_t default_return_value (void) { return false; }
50 bool stop_sublookup_iteration (return_t r) const { return r; }
51
52 const hb_set_t *glyphs;
53 unsigned int debug_depth;
54
55 hb_intersects_context_t (const hb_set_t *glyphs_) :
56 glyphs (glyphs_),
57 debug_depth (0) {}
58};
59
Behdad Esfahbod77a1a2b2015-10-09 12:20:58 -040060struct hb_closure_context_t :
61 hb_dispatch_context_t<hb_closure_context_t, hb_void_t, HB_DEBUG_CLOSURE>
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -040062{
Behdad Esfahboda1733db2012-11-23 16:40:04 -050063 inline const char *get_name (void) { return "CLOSURE"; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -050064 typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
65 template <typename T>
Behdad Esfahbod9c5a9ee2013-03-09 01:55:04 -050066 inline return_t dispatch (const T &obj) { obj.closure (this); return HB_VOID; }
Behdad Esfahbod130bb3f2012-12-05 16:49:47 -050067 static return_t default_return_value (void) { return HB_VOID; }
Behdad Esfahbod7b912c12013-01-04 01:25:27 -060068 bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -070069 void recurse (unsigned int lookup_index)
Behdad Esfahbod44fc2372012-11-21 23:33:13 -050070 {
Behdad Esfahbod9b346772012-11-23 17:55:40 -050071 if (unlikely (nesting_level_left == 0 || !recurse_func))
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -070072 return;
Behdad Esfahbod44fc2372012-11-21 23:33:13 -050073
74 nesting_level_left--;
75 recurse_func (this, lookup_index);
76 nesting_level_left++;
Behdad Esfahbod44fc2372012-11-21 23:33:13 -050077 }
78
Behdad Esfahbodba0ea562018-06-11 23:24:41 -040079 bool should_visit_lookup (unsigned int lookup_index)
Garret Rieger45186b92018-06-05 17:14:42 -070080 {
81 if (is_lookup_done (lookup_index))
82 return false;
83 done_lookups->set (lookup_index, glyphs->get_population ());
84 return true;
85 }
86
87 bool is_lookup_done (unsigned int lookup_index)
88 {
Behdad Esfahbodc38bd402018-07-24 09:43:27 -070089 /* Have we visited this lookup with the current set of glyphs? */
Garret Rieger45186b92018-06-05 17:14:42 -070090 return done_lookups->get (lookup_index) == glyphs->get_population ();
91 }
92
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -040093 hb_face_t *face;
Behdad Esfahbod6a9be5b2012-04-23 22:23:17 -040094 hb_set_t *glyphs;
Behdad Esfahbod6b11fea2018-07-25 16:01:37 -070095 hb_auto_t<hb_set_t> out[1];
Behdad Esfahbod44fc2372012-11-21 23:33:13 -050096 recurse_func_t recurse_func;
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -040097 unsigned int nesting_level_left;
98 unsigned int debug_depth;
99
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400100 hb_closure_context_t (hb_face_t *face_,
Behdad Esfahbod6a9be5b2012-04-23 22:23:17 -0400101 hb_set_t *glyphs_,
Garret Rieger45186b92018-06-05 17:14:42 -0700102 hb_map_t *done_lookups_,
Behdad Esfahbod5ba45042015-11-02 15:43:08 -0800103 unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400104 face (face_),
105 glyphs (glyphs_),
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200106 recurse_func (nullptr),
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400107 nesting_level_left (nesting_level_left_),
Behdad Esfahboda7e1b4a2018-06-11 22:05:08 -0400108 debug_depth (0),
109 done_lookups (done_lookups_) {}
Behdad Esfahbod9b346772012-11-23 17:55:40 -0500110
Behdad Esfahbodc38bd402018-07-24 09:43:27 -0700111 ~hb_closure_context_t (void)
112 {
113 flush ();
Behdad Esfahbodc38bd402018-07-24 09:43:27 -0700114 }
115
Behdad Esfahbod9b346772012-11-23 17:55:40 -0500116 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
Garret Rieger45186b92018-06-05 17:14:42 -0700117
Behdad Esfahbodc38bd402018-07-24 09:43:27 -0700118 void flush (void)
119 {
120 hb_set_union (glyphs, out);
121 hb_set_clear (out);
122 }
123
Garret Rieger45186b92018-06-05 17:14:42 -0700124 private:
125 hb_map_t *done_lookups;
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400126};
127
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400128
Behdad Esfahbod77a1a2b2015-10-09 12:20:58 -0400129struct hb_would_apply_context_t :
130 hb_dispatch_context_t<hb_would_apply_context_t, bool, HB_DEBUG_WOULD_APPLY>
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400131{
Behdad Esfahboda1733db2012-11-23 16:40:04 -0500132 inline const char *get_name (void) { return "WOULD_APPLY"; }
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500133 template <typename T>
Behdad Esfahbod9c5a9ee2013-03-09 01:55:04 -0500134 inline return_t dispatch (const T &obj) { return obj.would_apply (this); }
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500135 static return_t default_return_value (void) { return false; }
Behdad Esfahbod7b912c12013-01-04 01:25:27 -0600136 bool stop_sublookup_iteration (return_t r) const { return r; }
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500137
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400138 hb_face_t *face;
Behdad Esfahbod472f2292012-08-07 22:25:24 -0400139 const hb_codepoint_t *glyphs;
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400140 unsigned int len;
Behdad Esfahbodd9b204d2012-08-23 16:22:28 -0400141 bool zero_context;
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400142 unsigned int debug_depth;
143
144 hb_would_apply_context_t (hb_face_t *face_,
Behdad Esfahbod472f2292012-08-07 22:25:24 -0400145 const hb_codepoint_t *glyphs_,
146 unsigned int len_,
Behdad Esfahbod2bd9fe32012-09-04 15:15:19 -0400147 bool zero_context_) :
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400148 face (face_),
Behdad Esfahbod472f2292012-08-07 22:25:24 -0400149 glyphs (glyphs_),
150 len (len_),
Behdad Esfahbodd9b204d2012-08-23 16:22:28 -0400151 zero_context (zero_context_),
Behdad Esfahboda1733db2012-11-23 16:40:04 -0500152 debug_depth (0) {}
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400153};
154
155
Behdad Esfahbod77a1a2b2015-10-09 12:20:58 -0400156struct hb_collect_glyphs_context_t :
157 hb_dispatch_context_t<hb_collect_glyphs_context_t, hb_void_t, HB_DEBUG_COLLECT_GLYPHS>
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800158{
Behdad Esfahboda1733db2012-11-23 16:40:04 -0500159 inline const char *get_name (void) { return "COLLECT_GLYPHS"; }
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500160 typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index);
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500161 template <typename T>
Behdad Esfahbod9c5a9ee2013-03-09 01:55:04 -0500162 inline return_t dispatch (const T &obj) { obj.collect_glyphs (this); return HB_VOID; }
Behdad Esfahbod130bb3f2012-12-05 16:49:47 -0500163 static return_t default_return_value (void) { return HB_VOID; }
Behdad Esfahbod7b912c12013-01-04 01:25:27 -0600164 bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700165 void recurse (unsigned int lookup_index)
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500166 {
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500167 if (unlikely (nesting_level_left == 0 || !recurse_func))
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700168 return;
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500169
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200170 /* Note that GPOS sets recurse_func to nullptr already, so it doesn't get
Behdad Esfahbod1bcfa062012-12-04 16:58:09 -0500171 * past the previous check. For GSUB, we only want to collect the output
Behdad Esfahbod76ea5632013-05-04 16:01:20 -0400172 * glyphs in the recursion. If output is not requested, we can go home now.
173 *
174 * Note further, that the above is not exactly correct. A recursed lookup
175 * is allowed to match input that is not matched in the context, but that's
176 * not how most fonts are built. It's possible to relax that and recurse
177 * with all sets here if it proves to be an issue.
178 */
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500179
180 if (output == hb_set_get_empty ())
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700181 return;
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500182
Behdad Esfahbodfde3e4a2014-10-29 11:23:08 -0700183 /* Return if new lookup was recursed to before. */
Behdad Esfahbod8b9d9b72017-10-22 17:48:06 -0400184 if (recursed_lookups->has (lookup_index))
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700185 return;
Behdad Esfahbodfde3e4a2014-10-29 11:23:08 -0700186
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500187 hb_set_t *old_before = before;
188 hb_set_t *old_input = input;
189 hb_set_t *old_after = after;
190 before = input = after = hb_set_get_empty ();
Behdad Esfahbod1bcfa062012-12-04 16:58:09 -0500191
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500192 nesting_level_left--;
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500193 recurse_func (this, lookup_index);
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500194 nesting_level_left++;
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500195
196 before = old_before;
197 input = old_input;
198 after = old_after;
199
Behdad Esfahbod8b9d9b72017-10-22 17:48:06 -0400200 recursed_lookups->add (lookup_index);
Behdad Esfahbodfde3e4a2014-10-29 11:23:08 -0700201
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700202 return;
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500203 }
204
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800205 hb_face_t *face;
Behdad Esfahbod83035932012-12-04 17:08:41 -0500206 hb_set_t *before;
207 hb_set_t *input;
208 hb_set_t *after;
209 hb_set_t *output;
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500210 recurse_func_t recurse_func;
Behdad Esfahbod8b9d9b72017-10-22 17:48:06 -0400211 hb_set_t *recursed_lookups;
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500212 unsigned int nesting_level_left;
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800213 unsigned int debug_depth;
214
215 hb_collect_glyphs_context_t (hb_face_t *face_,
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200216 hb_set_t *glyphs_before, /* OUT. May be nullptr */
217 hb_set_t *glyphs_input, /* OUT. May be nullptr */
218 hb_set_t *glyphs_after, /* OUT. May be nullptr */
219 hb_set_t *glyphs_output, /* OUT. May be nullptr */
Behdad Esfahbod5ba45042015-11-02 15:43:08 -0800220 unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800221 face (face_),
Behdad Esfahbod83035932012-12-04 17:08:41 -0500222 before (glyphs_before ? glyphs_before : hb_set_get_empty ()),
223 input (glyphs_input ? glyphs_input : hb_set_get_empty ()),
224 after (glyphs_after ? glyphs_after : hb_set_get_empty ()),
225 output (glyphs_output ? glyphs_output : hb_set_get_empty ()),
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200226 recurse_func (nullptr),
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700227 recursed_lookups (hb_set_create ()),
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500228 nesting_level_left (nesting_level_left_),
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700229 debug_depth (0) {}
230 ~hb_collect_glyphs_context_t (void) { hb_set_destroy (recursed_lookups); }
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500231
232 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800233};
234
235
236
Behdad Esfahbod8e36ccf2015-02-17 19:15:34 +0300237template <typename set_t>
Behdad Esfahbod77a1a2b2015-10-09 12:20:58 -0400238struct hb_add_coverage_context_t :
239 hb_dispatch_context_t<hb_add_coverage_context_t<set_t>, const Coverage &, HB_DEBUG_GET_COVERAGE>
Behdad Esfahbod2005fa52012-11-22 14:38:10 -0500240{
Behdad Esfahboda1733db2012-11-23 16:40:04 -0500241 inline const char *get_name (void) { return "GET_COVERAGE"; }
Behdad Esfahbod2005fa52012-11-22 14:38:10 -0500242 typedef const Coverage &return_t;
243 template <typename T>
Behdad Esfahbod9c5a9ee2013-03-09 01:55:04 -0500244 inline return_t dispatch (const T &obj) { return obj.get_coverage (); }
Behdad Esfahboda1733db2012-11-23 16:40:04 -0500245 static return_t default_return_value (void) { return Null(Coverage); }
Behdad Esfahbod8e36ccf2015-02-17 19:15:34 +0300246 bool stop_sublookup_iteration (return_t r) const
247 {
248 r.add_coverage (set);
249 return false;
250 }
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500251
Behdad Esfahbod8e36ccf2015-02-17 19:15:34 +0300252 hb_add_coverage_context_t (set_t *set_) :
253 set (set_),
Behdad Esfahboda1733db2012-11-23 16:40:04 -0500254 debug_depth (0) {}
255
Behdad Esfahbod8e36ccf2015-02-17 19:15:34 +0300256 set_t *set;
Behdad Esfahboda1733db2012-11-23 16:40:04 -0500257 unsigned int debug_depth;
Behdad Esfahbod2005fa52012-11-22 14:38:10 -0500258};
259
260
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800261struct hb_ot_apply_context_t :
262 hb_dispatch_context_t<hb_ot_apply_context_t, bool, HB_DEBUG_APPLY>
Behdad Esfahbod1376fb72010-04-29 02:19:21 -0400263{
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500264 struct matcher_t
265 {
266 inline matcher_t (void) :
267 lookup_props (0),
Behdad Esfahbodcfc507c2013-02-14 10:40:12 -0500268 ignore_zwnj (false),
269 ignore_zwj (false),
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500270 mask (-1),
271#define arg1(arg) (arg) /* Remove the macro to see why it's needed! */
272 syllable arg1(0),
273#undef arg1
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200274 match_func (nullptr),
275 match_data (nullptr) {};
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500276
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100277 typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500278
279 inline void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; }
Behdad Esfahbod0b454792013-02-14 10:46:52 -0500280 inline void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500281 inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
282 inline void set_mask (hb_mask_t mask_) { mask = mask_; }
283 inline void set_syllable (uint8_t syllable_) { syllable = syllable_; }
284 inline void set_match_func (match_func_t match_func_,
285 const void *match_data_)
286 { match_func = match_func_; match_data = match_data_; }
287
Behdad Esfahbod2b2a6e82013-02-21 15:07:03 -0500288 enum may_match_t {
289 MATCH_NO,
290 MATCH_YES,
291 MATCH_MAYBE
292 };
293
294 inline may_match_t may_match (const hb_glyph_info_t &info,
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100295 const HBUINT16 *glyph_data) const
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500296 {
Behdad Esfahbod2b2a6e82013-02-21 15:07:03 -0500297 if (!(info.mask & mask) ||
298 (syllable && syllable != info.syllable ()))
299 return MATCH_NO;
300
301 if (match_func)
302 return match_func (info.codepoint, *glyph_data, match_data) ? MATCH_YES : MATCH_NO;
303
304 return MATCH_MAYBE;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500305 }
306
307 enum may_skip_t {
308 SKIP_NO,
309 SKIP_YES,
310 SKIP_MAYBE
311 };
312
313 inline may_skip_t
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800314 may_skip (const hb_ot_apply_context_t *c,
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500315 const hb_glyph_info_t &info) const
316 {
Behdad Esfahbodb98c5db2014-07-16 13:44:01 -0400317 if (!c->check_glyph_property (&info, lookup_props))
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500318 return SKIP_YES;
319
Khaled Hosny06cfe3f2017-05-17 21:32:47 +0300320 if (unlikely (_hb_glyph_info_is_default_ignorable_and_not_hidden (&info) &&
Behdad Esfahbod0b454792013-02-14 10:46:52 -0500321 (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) &&
Behdad Esfahbod4ba796b2015-07-22 17:41:31 +0100322 (ignore_zwj || !_hb_glyph_info_is_zwj (&info))))
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500323 return SKIP_MAYBE;
324
325 return SKIP_NO;
326 }
327
328 protected:
329 unsigned int lookup_props;
330 bool ignore_zwnj;
Behdad Esfahbod0b454792013-02-14 10:46:52 -0500331 bool ignore_zwj;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500332 hb_mask_t mask;
333 uint8_t syllable;
334 match_func_t match_func;
335 const void *match_data;
336 };
337
Behdad Esfahbod69626692015-01-29 13:08:41 +0100338 struct skipping_iterator_t
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500339 {
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800340 inline void init (hb_ot_apply_context_t *c_, bool context_match = false)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500341 {
Behdad Esfahbod514564f2015-01-29 13:48:48 +0100342 c = c_;
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200343 match_glyph_data = nullptr;
344 matcher.set_match_func (nullptr, nullptr);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500345 matcher.set_lookup_props (c->lookup_props);
Behdad Esfahboda8cf7b42013-03-19 05:53:26 -0400346 /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100347 matcher.set_ignore_zwnj (c->table_index == 1 || (context_match && c->auto_zwnj));
Behdad Esfahboda8cf7b42013-03-19 05:53:26 -0400348 /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100349 matcher.set_ignore_zwj (c->table_index == 1 || (context_match || c->auto_zwj));
Behdad Esfahbod514564f2015-01-29 13:48:48 +0100350 matcher.set_mask (context_match ? -1 : c->lookup_mask);
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500351 }
Behdad Esfahbod514564f2015-01-29 13:48:48 +0100352 inline void set_lookup_props (unsigned int lookup_props)
353 {
354 matcher.set_lookup_props (lookup_props);
355 }
Behdad Esfahbod4a6b1ee2015-10-21 11:20:55 -0200356 inline void set_match_func (matcher_t::match_func_t match_func_,
357 const void *match_data_,
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100358 const HBUINT16 glyph_data[])
Behdad Esfahbodc074ebc2013-02-13 11:22:42 -0500359 {
Behdad Esfahbod4a6b1ee2015-10-21 11:20:55 -0200360 matcher.set_match_func (match_func_, match_data_);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500361 match_glyph_data = glyph_data;
Behdad Esfahbodc074ebc2013-02-13 11:22:42 -0500362 }
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500363
Behdad Esfahbodb051be52015-01-29 13:40:39 +0100364 inline void reset (unsigned int start_index_,
365 unsigned int num_items_)
366 {
367 idx = start_index_;
368 num_items = num_items_;
369 end = c->buffer->len;
370 matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
371 }
372
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500373 inline void reject (void) { num_items++; match_glyph_data--; }
Behdad Esfahbod69626692015-01-29 13:08:41 +0100374
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200375 inline matcher_t::may_skip_t
Behdad Esfahbod12757b62018-01-26 18:14:05 -0800376 may_skip (const hb_glyph_info_t &info) const
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200377 {
378 return matcher.may_skip (c, info);
379 }
380
Behdad Esfahbodc074ebc2013-02-13 11:22:42 -0500381 inline bool next (void)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500382 {
Behdad Esfahbod506ffeb2012-01-18 16:07:53 -0500383 assert (num_items > 0);
Behdad Esfahbod37d13ac2015-01-29 11:38:01 +0100384 while (idx + num_items < end)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500385 {
Behdad Esfahboda4a48fe2012-01-17 18:08:41 -0500386 idx++;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500387 const hb_glyph_info_t &info = c->buffer->info[idx];
388
Behdad Esfahbodff93ac82013-02-21 14:51:40 -0500389 matcher_t::may_skip_t skip = matcher.may_skip (c, info);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500390 if (unlikely (skip == matcher_t::SKIP_YES))
391 continue;
392
Behdad Esfahbod2b2a6e82013-02-21 15:07:03 -0500393 matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
Behdad Esfahbod722e8b82013-02-21 15:37:51 -0500394 if (match == matcher_t::MATCH_YES ||
395 (match == matcher_t::MATCH_MAYBE &&
396 skip == matcher_t::SKIP_NO))
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500397 {
398 num_items--;
399 match_glyph_data++;
400 return true;
401 }
402
403 if (skip == matcher_t::SKIP_NO)
Behdad Esfahbod722e8b82013-02-21 15:37:51 -0500404 return false;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500405 }
406 return false;
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500407 }
Behdad Esfahbodc074ebc2013-02-13 11:22:42 -0500408 inline bool prev (void)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500409 {
Behdad Esfahbod506ffeb2012-01-18 16:07:53 -0500410 assert (num_items > 0);
Behdad Esfahbod18a06f82018-07-05 14:03:48 +0430411 while (idx > num_items - 1)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500412 {
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500413 idx--;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500414 const hb_glyph_info_t &info = c->buffer->out_info[idx];
415
Behdad Esfahbodff93ac82013-02-21 14:51:40 -0500416 matcher_t::may_skip_t skip = matcher.may_skip (c, info);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500417 if (unlikely (skip == matcher_t::SKIP_YES))
418 continue;
419
Behdad Esfahbod2b2a6e82013-02-21 15:07:03 -0500420 matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
Behdad Esfahbod722e8b82013-02-21 15:37:51 -0500421 if (match == matcher_t::MATCH_YES ||
422 (match == matcher_t::MATCH_MAYBE &&
423 skip == matcher_t::SKIP_NO))
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500424 {
425 num_items--;
426 match_glyph_data++;
427 return true;
428 }
429
430 if (skip == matcher_t::SKIP_NO)
Behdad Esfahbod722e8b82013-02-21 15:37:51 -0500431 return false;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500432 }
433 return false;
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500434 }
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500435
436 unsigned int idx;
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400437 protected:
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800438 hb_ot_apply_context_t *c;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500439 matcher_t matcher;
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100440 const HBUINT16 *match_glyph_data;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500441
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500442 unsigned int num_items;
Behdad Esfahbod69626692015-01-29 13:08:41 +0100443 unsigned int end;
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500444 };
445
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100446
447 inline const char *get_name (void) { return "APPLY"; }
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800448 typedef return_t (*recurse_func_t) (hb_ot_apply_context_t *c, unsigned int lookup_index);
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100449 template <typename T>
450 inline return_t dispatch (const T &obj) { return obj.apply (this); }
451 static return_t default_return_value (void) { return false; }
452 bool stop_sublookup_iteration (return_t r) const { return r; }
Behdad Esfahbod12757b62018-01-26 18:14:05 -0800453 return_t recurse (unsigned int sub_lookup_index)
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100454 {
Behdad Esfahbodbaf77792017-11-14 21:53:48 -0800455 if (unlikely (nesting_level_left == 0 || !recurse_func || buffer->max_ops-- <= 0))
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100456 return default_return_value ();
457
458 nesting_level_left--;
Behdad Esfahbod12757b62018-01-26 18:14:05 -0800459 bool ret = recurse_func (this, sub_lookup_index);
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100460 nesting_level_left++;
461 return ret;
462 }
463
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100464 skipping_iterator_t iter_input, iter_context;
465
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100466 hb_font_t *font;
467 hb_face_t *face;
468 hb_buffer_t *buffer;
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100469 recurse_func_t recurse_func;
470 const GDEF &gdef;
471 const VariationStore &var_store;
472
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100473 hb_direction_t direction;
474 hb_mask_t lookup_mask;
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100475 unsigned int table_index; /* GSUB/GPOS */
Behdad Esfahbod2c8b3b22015-08-18 14:36:43 +0100476 unsigned int lookup_index;
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100477 unsigned int lookup_props;
478 unsigned int nesting_level_left;
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100479 unsigned int debug_depth;
480
Behdad Esfahbod80de4bc2018-09-10 16:24:52 +0200481 bool has_glyph_classes;
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100482 bool auto_zwnj;
483 bool auto_zwj;
David Corbettc2a75e02018-01-25 14:22:03 -0500484 bool random;
Behdad Esfahbod80de4bc2018-09-10 16:24:52 +0200485
David Corbettc2a75e02018-01-25 14:22:03 -0500486 uint64_t random_state;
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100487
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100488
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800489 hb_ot_apply_context_t (unsigned int table_index_,
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100490 hb_font_t *font_,
491 hb_buffer_t *buffer_) :
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100492 iter_input (), iter_context (),
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100493 font (font_), face (font->face), buffer (buffer_),
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200494 recurse_func (nullptr),
Behdad Esfahbodb9291002018-08-26 01:15:47 -0700495 gdef (_get_gdef (face)),
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100496 var_store (gdef.get_var_store ()),
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100497 direction (buffer_->props.direction),
498 lookup_mask (1),
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100499 table_index (table_index_),
Behdad Esfahbod2c8b3b22015-08-18 14:36:43 +0100500 lookup_index ((unsigned int) -1),
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100501 lookup_props (0),
502 nesting_level_left (HB_MAX_NESTING_LEVEL),
503 debug_depth (0),
Behdad Esfahbod80de4bc2018-09-10 16:24:52 +0200504 has_glyph_classes (gdef.has_glyph_classes ()),
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100505 auto_zwnj (true),
506 auto_zwj (true),
David Corbettc2a75e02018-01-25 14:22:03 -0500507 random (false),
Behdad Esfahbod80de4bc2018-09-10 16:24:52 +0200508 random_state (1) {}
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100509
510 inline void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; }
511 inline void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; }
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100512 inline void set_auto_zwnj (bool auto_zwnj_) { auto_zwnj = auto_zwnj_; }
David Corbettb545e272018-02-23 12:22:32 -0500513 inline void set_random (bool random_) { random = random_; }
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100514 inline void set_recurse_func (recurse_func_t func) { recurse_func = func; }
Behdad Esfahbod2c8b3b22015-08-18 14:36:43 +0100515 inline void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; }
Behdad Esfahbod365576d2015-01-29 13:59:42 +0100516 inline void set_lookup_props (unsigned int lookup_props_)
517 {
518 lookup_props = lookup_props_;
519 iter_input.init (this, false);
520 iter_context.init (this, true);
521 }
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100522
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400523 inline bool
524 match_properties_mark (hb_codepoint_t glyph,
525 unsigned int glyph_props,
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700526 unsigned int match_props) const
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400527 {
528 /* If using mark filtering sets, the high short of
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700529 * match_props has the set index.
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400530 */
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700531 if (match_props & LookupFlag::UseMarkFilteringSet)
532 return gdef.mark_set_covers (match_props >> 16, glyph);
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400533
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700534 /* The second byte of match_props has the meaning
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400535 * "ignore marks of attachment type different than
536 * the attachment type specified."
537 */
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700538 if (match_props & LookupFlag::MarkAttachmentType)
539 return (match_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400540
541 return true;
542 }
543
544 inline bool
Behdad Esfahbodb98c5db2014-07-16 13:44:01 -0400545 check_glyph_property (const hb_glyph_info_t *info,
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700546 unsigned int match_props) const
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400547 {
Behdad Esfahbodb98c5db2014-07-16 13:44:01 -0400548 hb_codepoint_t glyph = info->codepoint;
549 unsigned int glyph_props = _hb_glyph_info_get_glyph_props (info);
550
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400551 /* Not covered, if, for example, glyph class is ligature and
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700552 * match_props includes LookupFlags::IgnoreLigatures
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400553 */
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700554 if (glyph_props & match_props & LookupFlag::IgnoreFlags)
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400555 return false;
556
Behdad Esfahbod5a08ecf2012-11-16 13:34:29 -0800557 if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK))
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700558 return match_properties_mark (glyph, glyph_props, match_props);
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400559
560 return true;
561 }
562
Behdad Esfahboda0161742013-10-18 00:06:30 +0200563 inline void _set_glyph_props (hb_codepoint_t glyph_index,
Behdad Esfahbod71b4c992013-10-28 00:20:59 +0100564 unsigned int class_guess = 0,
Behdad Esfahbod832a6f92014-06-04 16:57:42 -0400565 bool ligature = false,
566 bool component = false) const
Behdad Esfahbod60da7632012-07-16 16:13:32 -0400567 {
Behdad Esfahbod09675a82013-10-18 01:05:58 +0200568 unsigned int add_in = _hb_glyph_info_get_glyph_props (&buffer->cur()) &
569 HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE;
570 add_in |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED;
571 if (ligature)
Behdad Esfahbod832a6f92014-06-04 16:57:42 -0400572 {
Behdad Esfahbod09675a82013-10-18 01:05:58 +0200573 add_in |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED;
Behdad Esfahbod832a6f92014-06-04 16:57:42 -0400574 /* In the only place that the MULTIPLIED bit is used, Uniscribe
575 * seems to only care about the "last" transformation between
576 * Ligature and Multiple substitions. Ie. if you ligate, expand,
577 * and ligate again, it forgives the multiplication and acts as
578 * if only ligation happened. As such, clear MULTIPLIED bit.
579 */
580 add_in &= ~HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
581 }
582 if (component)
583 add_in |= HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
Behdad Esfahbod2fca1422012-07-30 18:46:41 -0400584 if (likely (has_glyph_classes))
Behdad Esfahbod05ad6b52013-10-18 00:45:59 +0200585 _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | gdef.get_glyph_props (glyph_index));
Behdad Esfahbod05bd1b62012-07-30 19:30:01 -0400586 else if (class_guess)
Behdad Esfahbod09675a82013-10-18 01:05:58 +0200587 _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | class_guess);
Behdad Esfahbod60da7632012-07-16 16:13:32 -0400588 }
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500589
Behdad Esfahboda0161742013-10-18 00:06:30 +0200590 inline void replace_glyph (hb_codepoint_t glyph_index) const
Behdad Esfahbod3ec77d62012-06-08 21:44:06 -0400591 {
Behdad Esfahboda0161742013-10-18 00:06:30 +0200592 _set_glyph_props (glyph_index);
Behdad Esfahbod98370e82010-10-27 17:39:01 -0400593 buffer->replace_glyph (glyph_index);
594 }
Behdad Esfahboda0161742013-10-18 00:06:30 +0200595 inline void replace_glyph_inplace (hb_codepoint_t glyph_index) const
Behdad Esfahbod7fbbf862012-07-30 18:36:42 -0400596 {
Behdad Esfahboda0161742013-10-18 00:06:30 +0200597 _set_glyph_props (glyph_index);
Behdad Esfahbod7fbbf862012-07-30 18:36:42 -0400598 buffer->cur().codepoint = glyph_index;
599 }
Behdad Esfahboda0161742013-10-18 00:06:30 +0200600 inline void replace_glyph_with_ligature (hb_codepoint_t glyph_index,
601 unsigned int class_guess) const
602 {
Behdad Esfahbod09675a82013-10-18 01:05:58 +0200603 _set_glyph_props (glyph_index, class_guess, true);
Behdad Esfahboda0161742013-10-18 00:06:30 +0200604 buffer->replace_glyph (glyph_index);
605 }
Behdad Esfahbod832a6f92014-06-04 16:57:42 -0400606 inline void output_glyph_for_component (hb_codepoint_t glyph_index,
607 unsigned int class_guess) const
Behdad Esfahboda0161742013-10-18 00:06:30 +0200608 {
Behdad Esfahbod832a6f92014-06-04 16:57:42 -0400609 _set_glyph_props (glyph_index, class_guess, false, true);
Behdad Esfahboda0161742013-10-18 00:06:30 +0200610 buffer->output_glyph (glyph_index);
611 }
Behdad Esfahbod1376fb72010-04-29 02:19:21 -0400612};
613
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -0400614
Behdad Esfahbod94a23aa2010-05-05 01:13:09 -0400615
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700616typedef bool (*intersects_func_t) (const hb_set_t *glyphs, const HBUINT16 &value, const void *data);
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100617typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const HBUINT16 &value, const void *data);
618typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -0400619
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400620struct ContextClosureFuncs
621{
622 intersects_func_t intersects;
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400623};
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500624struct ContextCollectGlyphsFuncs
625{
626 collect_glyphs_func_t collect;
627};
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400628struct ContextApplyFuncs
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400629{
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -0400630 match_func_t match;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -0400631};
632
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500633
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700634static inline bool intersects_glyph (const hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400635{
636 return glyphs->has (value);
637}
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700638static inline bool intersects_class (const hb_set_t *glyphs, const HBUINT16 &value, const void *data)
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400639{
640 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
641 return class_def.intersects_class (glyphs, value);
642}
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700643static inline bool intersects_coverage (const hb_set_t *glyphs, const HBUINT16 &value, const void *data)
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400644{
645 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
646 return (data+coverage).intersects (glyphs);
647}
648
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700649static inline bool intersects_array (const hb_set_t *glyphs,
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400650 unsigned int count,
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100651 const HBUINT16 values[],
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400652 intersects_func_t intersects_func,
653 const void *intersects_data)
654{
655 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700656 if (likely (!intersects_func (glyphs, values[i], intersects_data)))
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400657 return false;
658 return true;
659}
660
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -0400661
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100662static inline void collect_glyph (hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500663{
664 glyphs->add (value);
665}
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100666static inline void collect_class (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500667{
668 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
Behdad Esfahbod71e6adf2017-12-16 11:07:37 -0500669 class_def.add_class (glyphs, value);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500670}
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100671static inline void collect_coverage (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500672{
673 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
674 (data+coverage).add_coverage (glyphs);
675}
Behdad Esfahbod0beb66e2012-12-05 18:46:04 -0500676static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -0500677 hb_set_t *glyphs,
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500678 unsigned int count,
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100679 const HBUINT16 values[],
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500680 collect_glyphs_func_t collect_func,
681 const void *collect_data)
682{
683 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbodf1b12782012-11-24 01:55:34 -0500684 collect_func (glyphs, values[i], collect_data);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500685}
686
687
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100688static inline bool match_glyph (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data HB_UNUSED)
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400689{
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -0400690 return glyph_id == value;
691}
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100692static inline bool match_class (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data)
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400693{
Behdad Esfahbod2b5a59c2009-08-04 11:38:50 -0400694 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -0400695 return class_def.get_class (glyph_id) == value;
696}
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100697static inline bool match_coverage (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data)
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400698{
Behdad Esfahbod6b54c5d2009-05-18 18:30:25 -0400699 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400700 return (data+coverage).get_coverage (glyph_id) != NOT_COVERED;
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -0400701}
702
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400703static inline bool would_match_input (hb_would_apply_context_t *c,
704 unsigned int count, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100705 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400706 match_func_t match_func,
707 const void *match_data)
708{
709 if (count != c->len)
710 return false;
711
712 for (unsigned int i = 1; i < count; i++)
Behdad Esfahbod472f2292012-08-07 22:25:24 -0400713 if (likely (!match_func (c->glyphs[i], input[i - 1], match_data)))
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400714 return false;
715
716 return true;
717}
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800718static inline bool match_input (hb_ot_apply_context_t *c,
Behdad Esfahbode072c242009-05-18 03:47:31 -0400719 unsigned int count, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100720 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -0400721 match_func_t match_func,
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -0400722 const void *match_data,
Behdad Esfahbod6cc136f2013-10-17 13:55:48 +0200723 unsigned int *end_offset,
Behdad Esfahbod5ba45042015-11-02 15:43:08 -0800724 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200725 bool *p_is_mark_ligature = nullptr,
726 unsigned int *p_total_component_count = nullptr)
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -0400727{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200728 TRACE_APPLY (nullptr);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400729
Behdad Esfahbod5ba45042015-11-02 15:43:08 -0800730 if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return_trace (false);
Behdad Esfahbod6b65a762013-10-14 18:51:39 +0200731
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200732 hb_buffer_t *buffer = c->buffer;
733
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800734 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
Behdad Esfahbodb051be52015-01-29 13:40:39 +0100735 skippy_iter.reset (buffer->idx, count - 1);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500736 skippy_iter.set_match_func (match_func, match_data, input);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400737
Behdad Esfahbod191fa882012-08-28 22:58:55 -0400738 /*
739 * This is perhaps the trickiest part of OpenType... Remarks:
740 *
741 * - If all components of the ligature were marks, we call this a mark ligature.
742 *
743 * - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize
744 * it as a ligature glyph.
745 *
746 * - Ligatures cannot be formed across glyphs attached to different components
747 * of previous ligatures. Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and
748 * LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother.
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200749 * However, it would be wrong to ligate that SHADDA,FATHA sequence.
750 * There are a couple of exceptions to this:
751 *
752 * o If a ligature tries ligating with marks that belong to it itself, go ahead,
753 * assuming that the font designer knows what they are doing (otherwise it can
754 * break Indic stuff when a matra wants to ligate with a conjunct,
755 *
756 * o If two marks want to ligate and they belong to different components of the
757 * same ligature glyph, and said ligature glyph is to be ignored according to
758 * mark-filtering rules, then allow.
ebraminio7c6937e2017-11-20 14:49:22 -0500759 * https://github.com/harfbuzz/harfbuzz/issues/545
Behdad Esfahbod191fa882012-08-28 22:58:55 -0400760 */
761
Behdad Esfahbod101303d2013-10-18 00:42:39 +0200762 bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->cur());
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400763
764 unsigned int total_component_count = 0;
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200765 total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur());
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400766
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200767 unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
768 unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -0400769
Behdad Esfahbod621c49c2017-10-04 15:06:48 +0200770 enum {
771 LIGBASE_NOT_CHECKED,
772 LIGBASE_MAY_NOT_SKIP,
773 LIGBASE_MAY_SKIP
774 } ligbase = LIGBASE_NOT_CHECKED;
775
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200776 match_positions[0] = buffer->idx;
Behdad Esfahbod370f03e2012-01-16 17:03:55 -0500777 for (unsigned int i = 1; i < count; i++)
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400778 {
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100779 if (!skippy_iter.next ()) return_trace (false);
Behdad Esfahbod6cc136f2013-10-17 13:55:48 +0200780
781 match_positions[i] = skippy_iter.idx;
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400782
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200783 unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]);
784 unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400785
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200786 if (first_lig_id && first_lig_comp)
787 {
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400788 /* If first component was attached to a previous ligature component,
789 * all subsequent components should be attached to the same ligature
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200790 * component, otherwise we shouldn't ligate them... */
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400791 if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200792 {
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200793 /* ...unless, we are attached to a base ligature and that base
794 * ligature is ignorable. */
Behdad Esfahbod621c49c2017-10-04 15:06:48 +0200795 if (ligbase == LIGBASE_NOT_CHECKED)
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200796 {
Behdad Esfahbod621c49c2017-10-04 15:06:48 +0200797 bool found = false;
798 const hb_glyph_info_t *out = buffer->out_info;
799 unsigned int j = buffer->out_len;
800 while (j && _hb_glyph_info_get_lig_id (&out[j - 1]) == first_lig_id)
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200801 {
Behdad Esfahbod621c49c2017-10-04 15:06:48 +0200802 if (_hb_glyph_info_get_lig_comp (&out[j - 1]) == 0)
803 {
804 j--;
805 found = true;
806 break;
807 }
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200808 j--;
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200809 }
Behdad Esfahbod621c49c2017-10-04 15:06:48 +0200810
Behdad Esfahbod12757b62018-01-26 18:14:05 -0800811 if (found && skippy_iter.may_skip (out[j]) == hb_ot_apply_context_t::matcher_t::SKIP_YES)
Behdad Esfahbod621c49c2017-10-04 15:06:48 +0200812 ligbase = LIGBASE_MAY_SKIP;
813 else
814 ligbase = LIGBASE_MAY_NOT_SKIP;
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200815 }
816
Behdad Esfahbod621c49c2017-10-04 15:06:48 +0200817 if (ligbase == LIGBASE_MAY_NOT_SKIP)
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200818 return_trace (false);
819 }
820 }
821 else
Behdad Esfahbod621c49c2017-10-04 15:06:48 +0200822 {
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400823 /* If first component was NOT attached to a previous ligature component,
824 * all subsequent components should also NOT be attached to any ligature
825 * component, unless they are attached to the first component itself! */
826 if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id))
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100827 return_trace (false);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400828 }
829
Behdad Esfahbod101303d2013-10-18 00:42:39 +0200830 is_mark_ligature = is_mark_ligature && _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx]);
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200831 total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -0400832 }
833
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200834 *end_offset = skippy_iter.idx - buffer->idx + 1;
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400835
Behdad Esfahbod191fa882012-08-28 22:58:55 -0400836 if (p_is_mark_ligature)
837 *p_is_mark_ligature = is_mark_ligature;
838
839 if (p_total_component_count)
840 *p_total_component_count = total_component_count;
841
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100842 return_trace (true);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400843}
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800844static inline bool ligate_input (hb_ot_apply_context_t *c,
Behdad Esfahbode714fe62013-10-17 13:49:51 +0200845 unsigned int count, /* Including the first glyph */
Behdad Esfahbod5ba45042015-11-02 15:43:08 -0800846 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
Behdad Esfahbode714fe62013-10-17 13:49:51 +0200847 unsigned int match_length,
Behdad Esfahboda177d022012-08-28 23:18:22 -0400848 hb_codepoint_t lig_glyph,
Behdad Esfahboda177d022012-08-28 23:18:22 -0400849 bool is_mark_ligature,
850 unsigned int total_component_count)
851{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200852 TRACE_APPLY (nullptr);
Behdad Esfahbode714fe62013-10-17 13:49:51 +0200853
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200854 hb_buffer_t *buffer = c->buffer;
855
856 buffer->merge_clusters (buffer->idx, buffer->idx + match_length);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500857
Behdad Esfahboda177d022012-08-28 23:18:22 -0400858 /*
859 * - If it *is* a mark ligature, we don't allocate a new ligature id, and leave
860 * the ligature to keep its old ligature id. This will allow it to attach to
861 * a base ligature in GPOS. Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH,
862 * and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA wit a
863 * ligature id and component value of 2. Then if SHADDA,FATHA form a ligature
864 * later, we don't want them to lose their ligature id/component, otherwise
865 * GPOS will fail to correctly position the mark ligature on top of the
866 * LAM,LAM,HEH ligature. See:
867 * https://bugzilla.gnome.org/show_bug.cgi?id=676343
868 *
869 * - If a ligature is formed of components that some of which are also ligatures
870 * themselves, and those ligature components had marks attached to *their*
871 * components, we have to attach the marks to the new ligature component
872 * positions! Now *that*'s tricky! And these marks may be following the
873 * last component of the whole sequence, so we should loop forward looking
874 * for them and update them.
875 *
876 * Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a
877 * 'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature
878 * id and component == 1. Now, during 'liga', the LAM and the LAM-HEH ligature
879 * form a LAM-LAM-HEH ligature. We need to reassign the SHADDA and FATHA to
880 * the new ligature with a component value of 2.
881 *
882 * This in fact happened to a font... See:
883 * https://bugzilla.gnome.org/show_bug.cgi?id=437633
884 */
885
Behdad Esfahbod5a08ecf2012-11-16 13:34:29 -0800886 unsigned int klass = is_mark_ligature ? 0 : HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200887 unsigned int lig_id = is_mark_ligature ? 0 : _hb_allocate_lig_id (buffer);
888 unsigned int last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
889 unsigned int last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
Behdad Esfahboda177d022012-08-28 23:18:22 -0400890 unsigned int components_so_far = last_num_components;
891
892 if (!is_mark_ligature)
Behdad Esfahbod7e08f122013-05-27 14:48:34 -0400893 {
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200894 _hb_glyph_info_set_lig_props_for_ligature (&buffer->cur(), lig_id, total_component_count);
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200895 if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
Behdad Esfahbod3d436d32013-10-28 21:00:37 +0100896 {
Behdad Esfahbod82596692015-11-02 17:44:05 -0800897 _hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER);
Behdad Esfahbod3d436d32013-10-28 21:00:37 +0100898 }
Behdad Esfahbod7e08f122013-05-27 14:48:34 -0400899 }
Behdad Esfahboda0161742013-10-18 00:06:30 +0200900 c->replace_glyph_with_ligature (lig_glyph, klass);
Behdad Esfahboda177d022012-08-28 23:18:22 -0400901
902 for (unsigned int i = 1; i < count; i++)
903 {
Behdad Esfahbod7185b272018-05-31 20:03:00 -0700904 while (buffer->idx < match_positions[i] && buffer->successful)
Behdad Esfahboda177d022012-08-28 23:18:22 -0400905 {
906 if (!is_mark_ligature) {
Behdad Esfahbod2f02fc72015-12-17 15:21:14 +0000907 unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
908 if (this_comp == 0)
Behdad Esfahbod100fbea2015-12-17 15:23:09 +0000909 this_comp = last_num_components;
Behdad Esfahboda177d022012-08-28 23:18:22 -0400910 unsigned int new_lig_comp = components_so_far - last_num_components +
Behdad Esfahbod2f02fc72015-12-17 15:21:14 +0000911 MIN (this_comp, last_num_components);
912 _hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
Behdad Esfahboda177d022012-08-28 23:18:22 -0400913 }
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200914 buffer->next_glyph ();
Behdad Esfahboda177d022012-08-28 23:18:22 -0400915 }
916
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200917 last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
918 last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
Behdad Esfahboda177d022012-08-28 23:18:22 -0400919 components_so_far += last_num_components;
920
921 /* Skip the base glyph */
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200922 buffer->idx++;
Behdad Esfahboda177d022012-08-28 23:18:22 -0400923 }
924
925 if (!is_mark_ligature && last_lig_id) {
926 /* Re-adjust components for any marks following. */
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200927 for (unsigned int i = buffer->idx; i < buffer->len; i++) {
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200928 if (last_lig_id == _hb_glyph_info_get_lig_id (&buffer->info[i])) {
Behdad Esfahbod2f02fc72015-12-17 15:21:14 +0000929 unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->info[i]);
930 if (!this_comp)
931 break;
Behdad Esfahboda177d022012-08-28 23:18:22 -0400932 unsigned int new_lig_comp = components_so_far - last_num_components +
Behdad Esfahbod2f02fc72015-12-17 15:21:14 +0000933 MIN (this_comp, last_num_components);
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200934 _hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
Behdad Esfahboda177d022012-08-28 23:18:22 -0400935 } else
936 break;
937 }
938 }
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100939 return_trace (true);
Behdad Esfahboda177d022012-08-28 23:18:22 -0400940}
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400941
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800942static inline bool match_backtrack (hb_ot_apply_context_t *c,
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400943 unsigned int count,
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100944 const HBUINT16 backtrack[],
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400945 match_func_t match_func,
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +0200946 const void *match_data,
947 unsigned int *match_start)
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400948{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200949 TRACE_APPLY (nullptr);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400950
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800951 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
Behdad Esfahbodb051be52015-01-29 13:40:39 +0100952 skippy_iter.reset (c->buffer->backtrack_len (), count);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500953 skippy_iter.set_match_func (match_func, match_data, backtrack);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400954
Behdad Esfahbod4d3aeb82012-01-16 16:43:26 -0500955 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500956 if (!skippy_iter.prev ())
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100957 return_trace (false);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400958
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +0200959 *match_start = skippy_iter.idx;
960
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100961 return_trace (true);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400962}
963
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800964static inline bool match_lookahead (hb_ot_apply_context_t *c,
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400965 unsigned int count,
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100966 const HBUINT16 lookahead[],
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400967 match_func_t match_func,
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -0400968 const void *match_data,
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +0200969 unsigned int offset,
970 unsigned int *end_index)
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400971{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200972 TRACE_APPLY (nullptr);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400973
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800974 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
Behdad Esfahbodb051be52015-01-29 13:40:39 +0100975 skippy_iter.reset (c->buffer->idx + offset - 1, count);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500976 skippy_iter.set_match_func (match_func, match_data, lookahead);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400977
Behdad Esfahbod370f03e2012-01-16 17:03:55 -0500978 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500979 if (!skippy_iter.next ())
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100980 return_trace (false);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400981
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +0200982 *end_index = skippy_iter.idx + 1;
983
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100984 return_trace (true);
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -0400985}
986
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -0400987
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -0400988
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400989struct LookupRecord
990{
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300991 inline bool sanitize (hb_sanitize_context_t *c) const
992 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500993 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100994 return_trace (c->check_struct (this));
Behdad Esfahbodcd3827e2009-08-04 02:09:34 -0400995 }
996
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100997 HBUINT16 sequenceIndex; /* Index into current glyph
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -0400998 * sequence--first glyph = 0 */
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100999 HBUINT16 lookupListIndex; /* Lookup to apply to that
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001000 * position--zero--based */
Behdad Esfahbod569da922010-05-10 16:38:32 -04001001 public:
1002 DEFINE_SIZE_STATIC (4);
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001003};
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001004
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001005template <typename context_t>
1006static inline void recurse_lookups (context_t *c,
1007 unsigned int lookupCount,
1008 const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001009{
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001010 for (unsigned int i = 0; i < lookupCount; i++)
Behdad Esfahbod86522e42013-07-22 19:07:53 -04001011 c->recurse (lookupRecord[i].lookupListIndex);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001012}
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04001013
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001014static inline bool apply_lookup (hb_ot_apply_context_t *c,
Behdad Esfahbode072c242009-05-18 03:47:31 -04001015 unsigned int count, /* Including the first glyph */
Behdad Esfahbod5ba45042015-11-02 15:43:08 -08001016 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
Behdad Esfahbode072c242009-05-18 03:47:31 -04001017 unsigned int lookupCount,
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001018 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
1019 unsigned int match_length)
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001020{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001021 TRACE_APPLY (nullptr);
Behdad Esfahbod902cc8a2012-11-23 15:06:59 -05001022
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001023 hb_buffer_t *buffer = c->buffer;
jfkthame44f7d6e2017-02-17 03:03:24 +00001024 int end;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001025
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001026 /* All positions are distance from beginning of *output* buffer.
1027 * Adjust. */
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001028 {
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001029 unsigned int bl = buffer->backtrack_len ();
1030 end = bl + match_length;
Behdad Esfahbod8751de52013-07-18 16:29:50 -04001031
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001032 int delta = bl - buffer->idx;
1033 /* Convert positions to new indexing. */
1034 for (unsigned int j = 0; j < count; j++)
1035 match_positions[j] += delta;
Behdad Esfahbod8820bb22013-02-14 07:41:03 -05001036 }
Behdad Esfahbode73a0c22009-05-18 04:15:25 -04001037
Behdad Esfahbod7185b272018-05-31 20:03:00 -07001038 for (unsigned int i = 0; i < lookupCount && buffer->successful; i++)
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001039 {
1040 unsigned int idx = lookupRecord[i].sequenceIndex;
1041 if (idx >= count)
1042 continue;
1043
Behdad Esfahbod9cc1ed42015-11-19 12:39:09 -08001044 /* Don't recurse to ourself at same position.
1045 * Note that this test is too naive, it doesn't catch longer loops. */
1046 if (idx == 0 && lookupRecord[i].lookupListIndex == c->lookup_index)
1047 continue;
1048
Behdad Esfahbode5930722017-11-14 15:47:55 -08001049 if (unlikely (!buffer->move_to (match_positions[idx])))
1050 break;
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001051
Behdad Esfahbodbaf77792017-11-14 21:53:48 -08001052 if (unlikely (buffer->max_ops <= 0))
1053 break;
1054
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001055 unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
1056 if (!c->recurse (lookupRecord[i].lookupListIndex))
1057 continue;
1058
1059 unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len ();
1060 int delta = new_len - orig_len;
1061
1062 if (!delta)
1063 continue;
1064
Behdad Esfahbod9ac9af72017-03-05 13:51:01 -08001065 /* Recursed lookup changed buffer len. Adjust.
1066 *
1067 * TODO:
1068 *
1069 * Right now, if buffer length increased by n, we assume n new glyphs
1070 * were added right after the current position, and if buffer length
1071 * was decreased by n, we assume n match positions after the current
1072 * one where removed. The former (buffer length increased) case is
1073 * fine, but the decrease case can be improved in at least two ways,
1074 * both of which are significant:
1075 *
1076 * - If recursed-to lookup is MultipleSubst and buffer length
1077 * decreased, then it's current match position that was deleted,
1078 * NOT the one after it.
1079 *
1080 * - If buffer length was decreased by n, it does not necessarily
1081 * mean that n match positions where removed, as there might
1082 * have been marks and default-ignorables in the sequence. We
1083 * should instead drop match positions between current-position
1084 * and current-position + n instead.
1085 *
1086 * It should be possible to construct tests for both of these cases.
1087 */
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001088
jfkthame44f7d6e2017-02-17 03:03:24 +00001089 end += delta;
Behdad Esfahbod47e7a182017-03-10 13:23:02 -08001090 if (end <= int (match_positions[idx]))
Behdad Esfahbod359dead2016-05-06 16:19:19 +01001091 {
Behdad Esfahbod4b4a1b92016-12-21 23:10:43 -06001092 /* End might end up being smaller than match_positions[idx] if the recursed
Behdad Esfahbod47e7a182017-03-10 13:23:02 -08001093 * lookup ended up removing many items, more than we have had matched.
Behdad Esfahbod4b4a1b92016-12-21 23:10:43 -06001094 * Just never rewind end back and get out of here.
1095 * https://bugs.chromium.org/p/chromium/issues/detail?id=659496 */
1096 end = match_positions[idx];
Behdad Esfahbod47e7a182017-03-10 13:23:02 -08001097 /* There can't be any further changes. */
Behdad Esfahbod359dead2016-05-06 16:19:19 +01001098 break;
1099 }
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001100
1101 unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */
1102
1103 if (delta > 0)
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001104 {
Behdad Esfahbod5ba45042015-11-02 15:43:08 -08001105 if (unlikely (delta + count > HB_MAX_CONTEXT_LENGTH))
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001106 break;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001107 }
1108 else
1109 {
Behdad Esfahbod47e7a182017-03-10 13:23:02 -08001110 /* NOTE: delta is negative. */
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001111 delta = MAX (delta, (int) next - (int) count);
1112 next -= delta;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001113 }
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001114
1115 /* Shift! */
1116 memmove (match_positions + next + delta, match_positions + next,
1117 (count - next) * sizeof (match_positions[0]));
1118 next += delta;
1119 count += delta;
1120
1121 /* Fill in new entries. */
1122 for (unsigned int j = idx + 1; j < next; j++)
1123 match_positions[j] = match_positions[j - 1] + 1;
1124
1125 /* And fixup the rest. */
1126 for (; next < count; next++)
1127 match_positions[next] += delta;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001128 }
1129
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001130 buffer->move_to (end);
1131
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001132 return_trace (true);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001133}
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001134
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04001135
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001136
1137/* Contextual lookups */
1138
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001139struct ContextClosureLookupContext
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001140{
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001141 ContextClosureFuncs funcs;
1142 const void *intersects_data;
1143};
1144
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001145struct ContextCollectGlyphsLookupContext
1146{
1147 ContextCollectGlyphsFuncs funcs;
1148 const void *collect_data;
1149};
1150
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001151struct ContextApplyLookupContext
1152{
1153 ContextApplyFuncs funcs;
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04001154 const void *match_data;
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001155};
1156
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001157static inline bool context_intersects (const hb_set_t *glyphs,
1158 unsigned int inputCount, /* Including the first glyph (not matched) */
1159 const HBUINT16 input[], /* Array of input values--start with second glyph */
1160 ContextClosureLookupContext &lookup_context)
1161{
1162 return intersects_array (glyphs,
1163 inputCount ? inputCount - 1 : 0, input,
1164 lookup_context.funcs.intersects, lookup_context.intersects_data);
1165}
1166
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001167static inline void context_closure_lookup (hb_closure_context_t *c,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001168 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001169 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001170 unsigned int lookupCount,
1171 const LookupRecord lookupRecord[],
1172 ContextClosureLookupContext &lookup_context)
1173{
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001174 if (context_intersects (c->glyphs,
1175 inputCount, input,
1176 lookup_context))
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001177 recurse_lookups (c,
1178 lookupCount, lookupRecord);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001179}
1180
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001181static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
1182 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001183 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001184 unsigned int lookupCount,
1185 const LookupRecord lookupRecord[],
1186 ContextCollectGlyphsLookupContext &lookup_context)
1187{
Behdad Esfahbod83035932012-12-04 17:08:41 -05001188 collect_array (c, c->input,
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001189 inputCount ? inputCount - 1 : 0, input,
1190 lookup_context.funcs.collect, lookup_context.collect_data);
1191 recurse_lookups (c,
1192 lookupCount, lookupRecord);
1193}
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001194
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001195static inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
1196 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001197 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbod0beb66e2012-12-05 18:46:04 -05001198 unsigned int lookupCount HB_UNUSED,
1199 const LookupRecord lookupRecord[] HB_UNUSED,
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001200 ContextApplyLookupContext &lookup_context)
1201{
1202 return would_match_input (c,
1203 inputCount, input,
1204 lookup_context.funcs.match, lookup_context.match_data);
1205}
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001206static inline bool context_apply_lookup (hb_ot_apply_context_t *c,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001207 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001208 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001209 unsigned int lookupCount,
1210 const LookupRecord lookupRecord[],
1211 ContextApplyLookupContext &lookup_context)
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001212{
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001213 unsigned int match_length = 0;
Behdad Esfahbod5ba45042015-11-02 15:43:08 -08001214 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001215 return match_input (c,
Behdad Esfahbod41697102010-05-05 01:37:58 -04001216 inputCount, input,
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001217 lookup_context.funcs.match, lookup_context.match_data,
1218 &match_length, match_positions)
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001219 && (c->buffer->unsafe_to_break (c->buffer->idx, c->buffer->idx + match_length),
1220 apply_lookup (c,
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001221 inputCount, match_positions,
1222 lookupCount, lookupRecord,
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001223 match_length));
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001224}
1225
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001226struct Rule
1227{
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001228 inline bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const
1229 {
1230 return context_intersects (glyphs,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001231 inputCount, inputZ.arrayZ,
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001232 lookup_context);
1233 }
1234
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001235 inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001236 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001237 TRACE_CLOSURE (this);
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001238 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAtOffset<UnsizedArrayOf<LookupRecord> > (inputZ.arrayZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001239 context_closure_lookup (c,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001240 inputCount, inputZ.arrayZ,
1241 lookupCount, lookupRecord.arrayZ,
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001242 lookup_context);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001243 }
1244
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001245 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const
1246 {
1247 TRACE_COLLECT_GLYPHS (this);
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001248 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAtOffset<UnsizedArrayOf<LookupRecord> > (inputZ.arrayZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001249 context_collect_glyphs_lookup (c,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001250 inputCount, inputZ.arrayZ,
1251 lookupCount, lookupRecord.arrayZ,
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001252 lookup_context);
1253 }
1254
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001255 inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
1256 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001257 TRACE_WOULD_APPLY (this);
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001258 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAtOffset<UnsizedArrayOf<LookupRecord> > (inputZ.arrayZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
1259 return_trace (context_would_apply_lookup (c, inputCount, inputZ.arrayZ, lookupCount, lookupRecord.arrayZ, lookup_context));
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001260 }
1261
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001262 inline bool apply (hb_ot_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 Esfahbodbc485a92018-09-10 23:02:24 +02001265 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAtOffset<UnsizedArrayOf<LookupRecord> > (inputZ.arrayZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
1266 return_trace (context_apply_lookup (c, inputCount, inputZ.arrayZ, lookupCount, lookupRecord.arrayZ, lookup_context));
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001267 }
1268
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001269 public:
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001270 inline bool sanitize (hb_sanitize_context_t *c) const
1271 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001272 TRACE_SANITIZE (this);
Behdad Esfahbod5aad8192017-11-03 17:16:26 -04001273 return_trace (inputCount.sanitize (c) &&
1274 lookupCount.sanitize (c) &&
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001275 c->check_range (inputZ.arrayZ,
Behdad Esfahbod5dfd6e02018-09-10 15:45:32 +02001276 inputZ[0].static_size * (inputCount ? inputCount - 1 : 0) +
Behdad Esfahbod6d7c6e12018-02-07 14:09:56 -06001277 LookupRecord::static_size * lookupCount));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001278 }
1279
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001280 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001281 HBUINT16 inputCount; /* Total number of glyphs in input
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001282 * glyph sequence--includes the first
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001283 * glyph */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001284 HBUINT16 lookupCount; /* Number of LookupRecords */
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001285 UnsizedArrayOf<HBUINT16>
1286 inputZ; /* Array of match inputs--start with
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001287 * second glyph */
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001288/*UnsizedArrayOf<LookupRecord>
1289 lookupRecordX;*/ /* Array of LookupRecords--in
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001290 * design order */
Behdad Esfahbod569da922010-05-10 16:38:32 -04001291 public:
Behdad Esfahbod6d7c6e12018-02-07 14:09:56 -06001292 DEFINE_SIZE_ARRAY (4, inputZ);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001293};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001294
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001295struct RuleSet
1296{
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001297 inline bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const
1298 {
1299 unsigned int num_rules = rule.len;
1300 for (unsigned int i = 0; i < num_rules; i++)
1301 if ((this+rule[i]).intersects (glyphs, lookup_context))
1302 return true;
1303 return false;
1304 }
1305
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001306 inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001307 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001308 TRACE_CLOSURE (this);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001309 unsigned int num_rules = rule.len;
1310 for (unsigned int i = 0; i < num_rules; i++)
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001311 (this+rule[i]).closure (c, lookup_context);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001312 }
1313
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001314 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const
1315 {
1316 TRACE_COLLECT_GLYPHS (this);
1317 unsigned int num_rules = rule.len;
1318 for (unsigned int i = 0; i < num_rules; i++)
1319 (this+rule[i]).collect_glyphs (c, lookup_context);
1320 }
1321
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001322 inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
1323 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001324 TRACE_WOULD_APPLY (this);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001325 unsigned int num_rules = rule.len;
1326 for (unsigned int i = 0; i < num_rules; i++)
1327 {
1328 if ((this+rule[i]).would_apply (c, lookup_context))
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001329 return_trace (true);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001330 }
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001331 return_trace (false);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001332 }
1333
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001334 inline bool apply (hb_ot_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001335 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001336 TRACE_APPLY (this);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001337 unsigned int num_rules = rule.len;
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001338 for (unsigned int i = 0; i < num_rules; i++)
1339 {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001340 if ((this+rule[i]).apply (c, lookup_context))
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001341 return_trace (true);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001342 }
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001343 return_trace (false);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001344 }
1345
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001346 inline bool sanitize (hb_sanitize_context_t *c) const
1347 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001348 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001349 return_trace (rule.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001350 }
1351
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001352 protected:
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001353 OffsetArrayOf<Rule>
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001354 rule; /* Array of Rule tables
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001355 * ordered by preference */
Behdad Esfahboded074222010-05-10 18:08:46 -04001356 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04001357 DEFINE_SIZE_ARRAY (2, rule);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001358};
1359
1360
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001361struct ContextFormat1
1362{
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001363 inline bool intersects (const hb_set_t *glyphs) const
1364 {
1365 struct ContextClosureLookupContext lookup_context = {
1366 {intersects_glyph},
1367 nullptr
1368 };
1369
1370 unsigned int count = ruleSet.len;
1371 for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
1372 {
1373 if (unlikely (iter.get_coverage () >= count))
1374 break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
1375 if (glyphs->has (iter.get_glyph ()) &&
1376 (this+ruleSet[iter.get_coverage ()]).intersects (glyphs, lookup_context))
1377 return true;
1378 }
1379 return false;
1380 }
1381
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001382 inline void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001383 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001384 TRACE_CLOSURE (this);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001385
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001386 struct ContextClosureLookupContext lookup_context = {
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001387 {intersects_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001388 nullptr
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001389 };
1390
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001391 unsigned int count = ruleSet.len;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001392 for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
1393 {
1394 if (unlikely (iter.get_coverage () >= count))
1395 break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
1396 if (c->glyphs->has (iter.get_glyph ()))
1397 (this+ruleSet[iter.get_coverage ()]).closure (c, lookup_context);
1398 }
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001399 }
1400
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001401 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1402 {
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001403 TRACE_COLLECT_GLYPHS (this);
Behdad Esfahbod83035932012-12-04 17:08:41 -05001404 (this+coverage).add_coverage (c->input);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001405
1406 struct ContextCollectGlyphsLookupContext lookup_context = {
1407 {collect_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001408 nullptr
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001409 };
1410
1411 unsigned int count = ruleSet.len;
1412 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001413 (this+ruleSet[i]).collect_glyphs (c, lookup_context);
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001414 }
1415
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001416 inline bool would_apply (hb_would_apply_context_t *c) const
1417 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001418 TRACE_WOULD_APPLY (this);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001419
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05001420 const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001421 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001422 {match_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001423 nullptr
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001424 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001425 return_trace (rule_set.would_apply (c, lookup_context));
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001426 }
1427
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001428 inline const Coverage &get_coverage (void) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001429 { return this+coverage; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001430
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001431 inline bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001432 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001433 TRACE_APPLY (this);
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05001434 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -04001435 if (likely (index == NOT_COVERED))
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001436 return_trace (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04001437
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001438 const RuleSet &rule_set = this+ruleSet[index];
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001439 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001440 {match_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001441 nullptr
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001442 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001443 return_trace (rule_set.apply (c, lookup_context));
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001444 }
1445
Behdad Esfahbod339d3602018-09-03 17:33:34 -07001446 inline bool subset (hb_subset_context_t *c) const
1447 {
1448 TRACE_SUBSET (this);
1449 // TODO(subset)
1450 return_trace (false);
1451 }
1452
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001453 inline bool sanitize (hb_sanitize_context_t *c) const
1454 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001455 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001456 return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001457 }
1458
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001459 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001460 HBUINT16 format; /* Format identifier--format = 1 */
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001461 OffsetTo<Coverage>
1462 coverage; /* Offset to Coverage table--from
1463 * beginning of table */
1464 OffsetArrayOf<RuleSet>
1465 ruleSet; /* Array of RuleSet tables
1466 * ordered by Coverage Index */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04001467 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04001468 DEFINE_SIZE_ARRAY (6, 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 ContextFormat2
1473{
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001474 inline bool intersects (const hb_set_t *glyphs) const
1475 {
1476 if (!(this+coverage).intersects (glyphs))
1477 return false;
1478
1479 const ClassDef &class_def = this+classDef;
1480
1481 struct ContextClosureLookupContext lookup_context = {
1482 {intersects_class},
1483 &class_def
1484 };
1485
1486 unsigned int count = ruleSet.len;
1487 for (unsigned int i = 0; i < count; i++)
1488 if (class_def.intersects_class (glyphs, i) &&
1489 (this+ruleSet[i]).intersects (glyphs, lookup_context))
1490 return true;
1491
1492 return false;
1493 }
1494
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001495 inline void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001496 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001497 TRACE_CLOSURE (this);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001498 if (!(this+coverage).intersects (c->glyphs))
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001499 return;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001500
1501 const ClassDef &class_def = this+classDef;
1502
1503 struct ContextClosureLookupContext lookup_context = {
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001504 {intersects_class},
Behdad Esfahbod11fba792013-01-02 23:36:37 -06001505 &class_def
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001506 };
1507
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001508 unsigned int count = ruleSet.len;
1509 for (unsigned int i = 0; i < count; i++)
1510 if (class_def.intersects_class (c->glyphs, i)) {
1511 const RuleSet &rule_set = this+ruleSet[i];
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001512 rule_set.closure (c, lookup_context);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001513 }
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001514 }
1515
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001516 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1517 {
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001518 TRACE_COLLECT_GLYPHS (this);
Behdad Esfahbod83035932012-12-04 17:08:41 -05001519 (this+coverage).add_coverage (c->input);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001520
Behdad Esfahbod11fba792013-01-02 23:36:37 -06001521 const ClassDef &class_def = this+classDef;
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001522 struct ContextCollectGlyphsLookupContext lookup_context = {
1523 {collect_class},
Behdad Esfahbod11fba792013-01-02 23:36:37 -06001524 &class_def
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001525 };
1526
1527 unsigned int count = ruleSet.len;
1528 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001529 (this+ruleSet[i]).collect_glyphs (c, lookup_context);
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001530 }
1531
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001532 inline bool would_apply (hb_would_apply_context_t *c) const
1533 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001534 TRACE_WOULD_APPLY (this);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001535
1536 const ClassDef &class_def = this+classDef;
Behdad Esfahbod2dc11412012-11-24 19:16:34 -05001537 unsigned int index = class_def.get_class (c->glyphs[0]);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001538 const RuleSet &rule_set = this+ruleSet[index];
1539 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001540 {match_class},
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001541 &class_def
1542 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001543 return_trace (rule_set.would_apply (c, lookup_context));
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001544 }
1545
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001546 inline const Coverage &get_coverage (void) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001547 { return this+coverage; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001548
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001549 inline bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001550 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001551 TRACE_APPLY (this);
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05001552 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001553 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04001554
1555 const ClassDef &class_def = this+classDef;
Behdad Esfahbod2dc11412012-11-24 19:16:34 -05001556 index = class_def.get_class (c->buffer->cur().codepoint);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001557 const RuleSet &rule_set = this+ruleSet[index];
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001558 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001559 {match_class},
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04001560 &class_def
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001561 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001562 return_trace (rule_set.apply (c, lookup_context));
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001563 }
1564
Behdad Esfahbod339d3602018-09-03 17:33:34 -07001565 inline bool subset (hb_subset_context_t *c) const
1566 {
1567 TRACE_SUBSET (this);
1568 // TODO(subset)
1569 return_trace (false);
1570 }
1571
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001572 inline bool sanitize (hb_sanitize_context_t *c) const
1573 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001574 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001575 return_trace (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001576 }
1577
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001578 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001579 HBUINT16 format; /* Format identifier--format = 2 */
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001580 OffsetTo<Coverage>
1581 coverage; /* Offset to Coverage table--from
1582 * beginning of table */
1583 OffsetTo<ClassDef>
1584 classDef; /* Offset to glyph ClassDef table--from
1585 * beginning of table */
1586 OffsetArrayOf<RuleSet>
1587 ruleSet; /* Array of RuleSet tables
1588 * ordered by class */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04001589 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04001590 DEFINE_SIZE_ARRAY (8, ruleSet);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001591};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001592
1593
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001594struct ContextFormat3
1595{
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001596 inline bool intersects (const hb_set_t *glyphs) const
1597 {
1598 if (!(this+coverageZ[0]).intersects (glyphs))
1599 return false;
1600
1601 struct ContextClosureLookupContext lookup_context = {
1602 {intersects_coverage},
1603 this
1604 };
1605 return context_intersects (glyphs,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001606 glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001607 lookup_context);
1608 }
1609
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001610 inline void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001611 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001612 TRACE_CLOSURE (this);
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001613 if (!(this+coverageZ[0]).intersects (c->glyphs))
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001614 return;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001615
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001616 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ.arrayZ, coverageZ[0].static_size * glyphCount);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001617 struct ContextClosureLookupContext lookup_context = {
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001618 {intersects_coverage},
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001619 this
1620 };
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001621 context_closure_lookup (c,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001622 glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001623 lookupCount, lookupRecord,
1624 lookup_context);
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001625 }
1626
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001627 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1628 {
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001629 TRACE_COLLECT_GLYPHS (this);
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001630 (this+coverageZ[0]).add_coverage (c->input);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001631
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001632 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ.arrayZ, coverageZ[0].static_size * glyphCount);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001633 struct ContextCollectGlyphsLookupContext lookup_context = {
1634 {collect_coverage},
Behdad Esfahbode75943d2012-11-30 08:38:24 +02001635 this
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001636 };
1637
1638 context_collect_glyphs_lookup (c,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001639 glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001640 lookupCount, lookupRecord,
1641 lookup_context);
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001642 }
1643
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001644 inline bool would_apply (hb_would_apply_context_t *c) const
1645 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001646 TRACE_WOULD_APPLY (this);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001647
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001648 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ.arrayZ, coverageZ[0].static_size * glyphCount);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001649 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001650 {match_coverage},
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001651 this
1652 };
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001653 return_trace (context_would_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, lookup_context));
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001654 }
1655
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001656 inline const Coverage &get_coverage (void) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001657 { return this+coverageZ[0]; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001658
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001659 inline bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001660 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001661 TRACE_APPLY (this);
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001662 unsigned int index = (this+coverageZ[0]).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001663 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04001664
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001665 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ.arrayZ, coverageZ[0].static_size * glyphCount);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001666 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001667 {match_coverage},
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04001668 this
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001669 };
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001670 return_trace (context_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, lookup_context));
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001671 }
1672
Behdad Esfahbod339d3602018-09-03 17:33:34 -07001673 inline bool subset (hb_subset_context_t *c) const
1674 {
1675 TRACE_SUBSET (this);
1676 // TODO(subset)
1677 return_trace (false);
1678 }
1679
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001680 inline bool sanitize (hb_sanitize_context_t *c) const
1681 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001682 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001683 if (!c->check_struct (this)) return_trace (false);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001684 unsigned int count = glyphCount;
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001685 if (!count) return_trace (false); /* We want to access coverageZ[0] freely. */
Behdad Esfahbod9507b052018-09-10 23:18:07 +02001686 if (!c->check_array (coverageZ.arrayZ, count)) return_trace (false);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001687 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001688 if (!coverageZ[i].sanitize (c, this)) return_trace (false);
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001689 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ.arrayZ, coverageZ[0].static_size * count);
Behdad Esfahbod9507b052018-09-10 23:18:07 +02001690 return_trace (c->check_array (lookupRecord, lookupCount));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001691 }
1692
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001693 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001694 HBUINT16 format; /* Format identifier--format = 3 */
1695 HBUINT16 glyphCount; /* Number of glyphs in the input glyph
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001696 * sequence */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001697 HBUINT16 lookupCount; /* Number of LookupRecords */
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001698 UnsizedArrayOf<OffsetTo<Coverage> >
1699 coverageZ; /* Array of offsets to Coverage
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04001700 * table in glyph sequence order */
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001701/*UnsizedArrayOf<LookupRecord>
1702 lookupRecordX;*/ /* Array of LookupRecords--in
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001703 * design order */
Behdad Esfahbod569da922010-05-10 16:38:32 -04001704 public:
Behdad Esfahbod6d7c6e12018-02-07 14:09:56 -06001705 DEFINE_SIZE_ARRAY (6, coverageZ);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001706};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001707
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001708struct Context
1709{
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001710 template <typename context_t>
Behdad Esfahbod9c5a9ee2013-03-09 01:55:04 -05001711 inline typename context_t::return_t dispatch (context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001712 {
Behdad Esfahbod00f6a8e2014-12-12 20:36:49 -08001713 TRACE_DISPATCH (this, u.format);
Behdad Esfahbodf396fbb2015-10-09 12:25:55 -04001714 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001715 switch (u.format) {
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001716 case 1: return_trace (c->dispatch (u.format1));
1717 case 2: return_trace (c->dispatch (u.format2));
1718 case 3: return_trace (c->dispatch (u.format3));
1719 default:return_trace (c->default_return_value ());
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001720 }
1721 }
1722
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001723 protected:
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001724 union {
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001725 HBUINT16 format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -04001726 ContextFormat1 format1;
1727 ContextFormat2 format2;
1728 ContextFormat3 format3;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001729 } u;
1730};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001731
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001732
1733/* Chaining Contextual lookups */
1734
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001735struct ChainContextClosureLookupContext
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001736{
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001737 ContextClosureFuncs funcs;
1738 const void *intersects_data[3];
1739};
1740
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001741struct ChainContextCollectGlyphsLookupContext
1742{
1743 ContextCollectGlyphsFuncs funcs;
1744 const void *collect_data[3];
1745};
1746
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001747struct ChainContextApplyLookupContext
1748{
1749 ContextApplyFuncs funcs;
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04001750 const void *match_data[3];
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001751};
1752
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001753static inline bool chain_context_intersects (const hb_set_t *glyphs,
1754 unsigned int backtrackCount,
1755 const HBUINT16 backtrack[],
1756 unsigned int inputCount, /* Including the first glyph (not matched) */
1757 const HBUINT16 input[], /* Array of input values--start with second glyph */
1758 unsigned int lookaheadCount,
1759 const HBUINT16 lookahead[],
1760 ChainContextClosureLookupContext &lookup_context)
1761{
1762 return intersects_array (glyphs,
1763 backtrackCount, backtrack,
1764 lookup_context.funcs.intersects, lookup_context.intersects_data[0])
1765 && intersects_array (glyphs,
1766 inputCount ? inputCount - 1 : 0, input,
1767 lookup_context.funcs.intersects, lookup_context.intersects_data[1])
1768 && intersects_array (glyphs,
1769 lookaheadCount, lookahead,
1770 lookup_context.funcs.intersects, lookup_context.intersects_data[2]);
1771}
1772
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001773static inline void chain_context_closure_lookup (hb_closure_context_t *c,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001774 unsigned int backtrackCount,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001775 const HBUINT16 backtrack[],
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001776 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001777 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001778 unsigned int lookaheadCount,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001779 const HBUINT16 lookahead[],
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001780 unsigned int lookupCount,
1781 const LookupRecord lookupRecord[],
1782 ChainContextClosureLookupContext &lookup_context)
1783{
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001784 if (chain_context_intersects (c->glyphs,
1785 backtrackCount, backtrack,
1786 inputCount, input,
1787 lookaheadCount, lookahead,
1788 lookup_context))
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001789 recurse_lookups (c,
1790 lookupCount, lookupRecord);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001791}
1792
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001793static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
1794 unsigned int backtrackCount,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001795 const HBUINT16 backtrack[],
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001796 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001797 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001798 unsigned int lookaheadCount,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001799 const HBUINT16 lookahead[],
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001800 unsigned int lookupCount,
1801 const LookupRecord lookupRecord[],
1802 ChainContextCollectGlyphsLookupContext &lookup_context)
1803{
Behdad Esfahbod83035932012-12-04 17:08:41 -05001804 collect_array (c, c->before,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001805 backtrackCount, backtrack,
1806 lookup_context.funcs.collect, lookup_context.collect_data[0]);
Behdad Esfahbod83035932012-12-04 17:08:41 -05001807 collect_array (c, c->input,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001808 inputCount ? inputCount - 1 : 0, input,
1809 lookup_context.funcs.collect, lookup_context.collect_data[1]);
Behdad Esfahbod83035932012-12-04 17:08:41 -05001810 collect_array (c, c->after,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001811 lookaheadCount, lookahead,
1812 lookup_context.funcs.collect, lookup_context.collect_data[2]);
1813 recurse_lookups (c,
1814 lookupCount, lookupRecord);
1815}
1816
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001817static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c,
1818 unsigned int backtrackCount,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001819 const HBUINT16 backtrack[] HB_UNUSED,
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001820 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001821 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001822 unsigned int lookaheadCount,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001823 const HBUINT16 lookahead[] HB_UNUSED,
Behdad Esfahbod0beb66e2012-12-05 18:46:04 -05001824 unsigned int lookupCount HB_UNUSED,
1825 const LookupRecord lookupRecord[] HB_UNUSED,
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001826 ChainContextApplyLookupContext &lookup_context)
1827{
Behdad Esfahbodd9b204d2012-08-23 16:22:28 -04001828 return (c->zero_context ? !backtrackCount && !lookaheadCount : true)
Behdad Esfahbod1f2bb172012-08-23 16:10:37 -04001829 && would_match_input (c,
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001830 inputCount, input,
1831 lookup_context.funcs.match, lookup_context.match_data[1]);
1832}
1833
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001834static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001835 unsigned int backtrackCount,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001836 const HBUINT16 backtrack[],
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001837 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001838 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001839 unsigned int lookaheadCount,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001840 const HBUINT16 lookahead[],
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001841 unsigned int lookupCount,
1842 const LookupRecord lookupRecord[],
1843 ChainContextApplyLookupContext &lookup_context)
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04001844{
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001845 unsigned int start_index = 0, match_length = 0, end_index = 0;
Behdad Esfahbod5ba45042015-11-02 15:43:08 -08001846 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
Behdad Esfahbodf19e0b02012-06-09 02:26:57 -04001847 return match_input (c,
Behdad Esfahbod41697102010-05-05 01:37:58 -04001848 inputCount, input,
1849 lookup_context.funcs.match, lookup_context.match_data[1],
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001850 &match_length, match_positions)
Behdad Esfahbodf19e0b02012-06-09 02:26:57 -04001851 && match_backtrack (c,
1852 backtrackCount, backtrack,
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001853 lookup_context.funcs.match, lookup_context.match_data[0],
1854 &start_index)
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001855 && match_lookahead (c,
Behdad Esfahbod41697102010-05-05 01:37:58 -04001856 lookaheadCount, lookahead,
1857 lookup_context.funcs.match, lookup_context.match_data[2],
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001858 match_length, &end_index)
1859 && (c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index),
1860 apply_lookup (c,
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001861 inputCount, match_positions,
1862 lookupCount, lookupRecord,
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001863 match_length));
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04001864}
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001865
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001866struct ChainRule
1867{
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001868 inline bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
1869 {
1870 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
1871 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
1872 return chain_context_intersects (glyphs,
1873 backtrack.len, backtrack.arrayZ,
1874 input.len, input.arrayZ,
1875 lookahead.len, lookahead.arrayZ,
1876 lookup_context);
1877 }
1878
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001879 inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001880 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001881 TRACE_CLOSURE (this);
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001882 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
1883 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001884 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001885 chain_context_closure_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07001886 backtrack.len, backtrack.arrayZ,
1887 input.len, input.arrayZ,
1888 lookahead.len, lookahead.arrayZ,
1889 lookup.len, lookup.arrayZ,
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001890 lookup_context);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001891 }
1892
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001893 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
1894 {
1895 TRACE_COLLECT_GLYPHS (this);
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001896 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
1897 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001898 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1899 chain_context_collect_glyphs_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07001900 backtrack.len, backtrack.arrayZ,
1901 input.len, input.arrayZ,
1902 lookahead.len, lookahead.arrayZ,
1903 lookup.len, lookup.arrayZ,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001904 lookup_context);
1905 }
1906
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001907 inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
1908 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001909 TRACE_WOULD_APPLY (this);
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001910 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
1911 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001912 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001913 return_trace (chain_context_would_apply_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07001914 backtrack.len, backtrack.arrayZ,
1915 input.len, input.arrayZ,
1916 lookahead.len, lookahead.arrayZ, lookup.len,
1917 lookup.arrayZ, lookup_context));
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001918 }
1919
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001920 inline bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001921 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001922 TRACE_APPLY (this);
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001923 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
1924 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
Behdad Esfahbode961c862010-04-21 15:56:11 -04001925 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001926 return_trace (chain_context_apply_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07001927 backtrack.len, backtrack.arrayZ,
1928 input.len, input.arrayZ,
1929 lookahead.len, lookahead.arrayZ, lookup.len,
1930 lookup.arrayZ, lookup_context));
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04001931 }
1932
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001933 inline bool sanitize (hb_sanitize_context_t *c) const
1934 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001935 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001936 if (!backtrack.sanitize (c)) return_trace (false);
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001937 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001938 if (!input.sanitize (c)) return_trace (false);
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001939 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001940 if (!lookahead.sanitize (c)) return_trace (false);
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001941 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001942 return_trace (lookup.sanitize (c));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001943 }
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001944
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001945 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001946 ArrayOf<HBUINT16>
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04001947 backtrack; /* Array of backtracking values
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001948 * (to be matched before the input
1949 * sequence) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001950 HeadlessArrayOf<HBUINT16>
Behdad Esfahbode8cbaaf2009-05-18 02:03:58 -04001951 inputX; /* Array of input values (start with
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001952 * second glyph) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001953 ArrayOf<HBUINT16>
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04001954 lookaheadX; /* Array of lookahead values's (to be
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001955 * matched after the input sequence) */
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04001956 ArrayOf<LookupRecord>
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04001957 lookupX; /* Array of LookupRecords--in
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001958 * design order) */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04001959 public:
Behdad Esfahbodbea34c72010-05-10 17:28:16 -04001960 DEFINE_SIZE_MIN (8);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001961};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001962
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001963struct ChainRuleSet
1964{
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001965 inline bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
1966 {
1967 unsigned int num_rules = rule.len;
1968 for (unsigned int i = 0; i < num_rules; i++)
1969 if ((this+rule[i]).intersects (glyphs, lookup_context))
1970 return true;
1971 return false;
1972 }
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001973 inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001974 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001975 TRACE_CLOSURE (this);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001976 unsigned int num_rules = rule.len;
1977 for (unsigned int i = 0; i < num_rules; i++)
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001978 (this+rule[i]).closure (c, lookup_context);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001979 }
1980
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001981 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
1982 {
1983 TRACE_COLLECT_GLYPHS (this);
1984 unsigned int num_rules = rule.len;
1985 for (unsigned int i = 0; i < num_rules; i++)
1986 (this+rule[i]).collect_glyphs (c, lookup_context);
1987 }
1988
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001989 inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
1990 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001991 TRACE_WOULD_APPLY (this);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001992 unsigned int num_rules = rule.len;
1993 for (unsigned int i = 0; i < num_rules; i++)
1994 if ((this+rule[i]).would_apply (c, lookup_context))
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001995 return_trace (true);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001996
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001997 return_trace (false);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001998 }
1999
Behdad Esfahbodfd034492018-01-17 16:46:51 -08002000 inline bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002001 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002002 TRACE_APPLY (this);
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04002003 unsigned int num_rules = rule.len;
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002004 for (unsigned int i = 0; i < num_rules; i++)
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04002005 if ((this+rule[i]).apply (c, lookup_context))
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002006 return_trace (true);
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04002007
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002008 return_trace (false);
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04002009 }
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002010
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002011 inline bool sanitize (hb_sanitize_context_t *c) const
2012 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002013 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002014 return_trace (rule.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002015 }
2016
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002017 protected:
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04002018 OffsetArrayOf<ChainRule>
2019 rule; /* Array of ChainRule tables
2020 * ordered by preference */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04002021 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04002022 DEFINE_SIZE_ARRAY (2, rule);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002023};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002024
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002025struct ChainContextFormat1
2026{
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002027 inline bool intersects (const hb_set_t *glyphs) const
2028 {
2029 struct ChainContextClosureLookupContext lookup_context = {
2030 {intersects_glyph},
2031 {nullptr, nullptr, nullptr}
2032 };
2033
2034 unsigned int count = ruleSet.len;
2035 for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
2036 {
2037 if (unlikely (iter.get_coverage () >= count))
2038 break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
2039 if (glyphs->has (iter.get_glyph ()) &&
2040 (this+ruleSet[iter.get_coverage ()]).intersects (glyphs, lookup_context))
2041 return true;
2042 }
2043 return false;
2044 }
2045
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002046 inline void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002047 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002048 TRACE_CLOSURE (this);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002049
2050 struct ChainContextClosureLookupContext lookup_context = {
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002051 {intersects_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02002052 {nullptr, nullptr, nullptr}
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002053 };
2054
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002055 unsigned int count = ruleSet.len;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002056 for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
2057 {
2058 if (unlikely (iter.get_coverage () >= count))
2059 break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
2060 if (c->glyphs->has (iter.get_glyph ()))
2061 (this+ruleSet[iter.get_coverage ()]).closure (c, lookup_context);
2062 }
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002063 }
2064
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002065 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
2066 {
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002067 TRACE_COLLECT_GLYPHS (this);
Behdad Esfahbod83035932012-12-04 17:08:41 -05002068 (this+coverage).add_coverage (c->input);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002069
2070 struct ChainContextCollectGlyphsLookupContext lookup_context = {
2071 {collect_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02002072 {nullptr, nullptr, nullptr}
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002073 };
2074
2075 unsigned int count = ruleSet.len;
2076 for (unsigned int i = 0; i < count; i++)
2077 (this+ruleSet[i]).collect_glyphs (c, lookup_context);
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002078 }
2079
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002080 inline bool would_apply (hb_would_apply_context_t *c) const
2081 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002082 TRACE_WOULD_APPLY (this);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002083
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05002084 const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002085 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002086 {match_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02002087 {nullptr, nullptr, nullptr}
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002088 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002089 return_trace (rule_set.would_apply (c, lookup_context));
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002090 }
2091
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002092 inline const Coverage &get_coverage (void) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002093 { return this+coverage; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002094
Behdad Esfahbodfd034492018-01-17 16:46:51 -08002095 inline bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002096 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002097 TRACE_APPLY (this);
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05002098 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002099 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002100
2101 const ChainRuleSet &rule_set = this+ruleSet[index];
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002102 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002103 {match_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02002104 {nullptr, nullptr, nullptr}
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002105 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002106 return_trace (rule_set.apply (c, lookup_context));
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002107 }
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002108
Behdad Esfahbod339d3602018-09-03 17:33:34 -07002109 inline bool subset (hb_subset_context_t *c) const
2110 {
2111 TRACE_SUBSET (this);
2112 // TODO(subset)
2113 return_trace (false);
2114 }
2115
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002116 inline bool sanitize (hb_sanitize_context_t *c) const
2117 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002118 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002119 return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002120 }
2121
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002122 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002123 HBUINT16 format; /* Format identifier--format = 1 */
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04002124 OffsetTo<Coverage>
2125 coverage; /* Offset to Coverage table--from
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002126 * beginning of table */
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002127 OffsetArrayOf<ChainRuleSet>
2128 ruleSet; /* Array of ChainRuleSet tables
2129 * ordered by Coverage Index */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04002130 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04002131 DEFINE_SIZE_ARRAY (6, ruleSet);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002132};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002133
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002134struct ChainContextFormat2
2135{
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002136 inline bool intersects (const hb_set_t *glyphs) const
2137 {
2138 if (!(this+coverage).intersects (glyphs))
2139 return false;
2140
2141 const ClassDef &backtrack_class_def = this+backtrackClassDef;
2142 const ClassDef &input_class_def = this+inputClassDef;
2143 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2144
2145 struct ChainContextClosureLookupContext lookup_context = {
2146 {intersects_class},
2147 {&backtrack_class_def,
2148 &input_class_def,
2149 &lookahead_class_def}
2150 };
2151
2152 unsigned int count = ruleSet.len;
2153 for (unsigned int i = 0; i < count; i++)
2154 if (input_class_def.intersects_class (glyphs, i) &&
2155 (this+ruleSet[i]).intersects (glyphs, lookup_context))
2156 return true;
2157
2158 return false;
2159 }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002160 inline void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002161 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002162 TRACE_CLOSURE (this);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002163 if (!(this+coverage).intersects (c->glyphs))
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002164 return;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002165
2166 const ClassDef &backtrack_class_def = this+backtrackClassDef;
2167 const ClassDef &input_class_def = this+inputClassDef;
2168 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2169
2170 struct ChainContextClosureLookupContext lookup_context = {
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002171 {intersects_class},
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002172 {&backtrack_class_def,
2173 &input_class_def,
2174 &lookahead_class_def}
2175 };
2176
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002177 unsigned int count = ruleSet.len;
2178 for (unsigned int i = 0; i < count; i++)
2179 if (input_class_def.intersects_class (c->glyphs, i)) {
2180 const ChainRuleSet &rule_set = this+ruleSet[i];
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002181 rule_set.closure (c, lookup_context);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002182 }
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002183 }
2184
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002185 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
2186 {
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002187 TRACE_COLLECT_GLYPHS (this);
Behdad Esfahbod83035932012-12-04 17:08:41 -05002188 (this+coverage).add_coverage (c->input);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002189
Behdad Esfahbod11fba792013-01-02 23:36:37 -06002190 const ClassDef &backtrack_class_def = this+backtrackClassDef;
2191 const ClassDef &input_class_def = this+inputClassDef;
2192 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2193
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002194 struct ChainContextCollectGlyphsLookupContext lookup_context = {
2195 {collect_class},
Behdad Esfahbod11fba792013-01-02 23:36:37 -06002196 {&backtrack_class_def,
2197 &input_class_def,
2198 &lookahead_class_def}
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002199 };
2200
2201 unsigned int count = ruleSet.len;
2202 for (unsigned int i = 0; i < count; i++)
2203 (this+ruleSet[i]).collect_glyphs (c, lookup_context);
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002204 }
2205
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002206 inline bool would_apply (hb_would_apply_context_t *c) const
2207 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002208 TRACE_WOULD_APPLY (this);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002209
Behdad Esfahbod11fba792013-01-02 23:36:37 -06002210 const ClassDef &backtrack_class_def = this+backtrackClassDef;
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002211 const ClassDef &input_class_def = this+inputClassDef;
Behdad Esfahbod11fba792013-01-02 23:36:37 -06002212 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002213
Behdad Esfahbod2dc11412012-11-24 19:16:34 -05002214 unsigned int index = input_class_def.get_class (c->glyphs[0]);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002215 const ChainRuleSet &rule_set = this+ruleSet[index];
2216 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002217 {match_class},
Behdad Esfahbod11fba792013-01-02 23:36:37 -06002218 {&backtrack_class_def,
2219 &input_class_def,
2220 &lookahead_class_def}
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002221 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002222 return_trace (rule_set.would_apply (c, lookup_context));
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002223 }
2224
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002225 inline const Coverage &get_coverage (void) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002226 { return this+coverage; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002227
Behdad Esfahbodfd034492018-01-17 16:46:51 -08002228 inline bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002229 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002230 TRACE_APPLY (this);
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05002231 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002232 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002233
2234 const ClassDef &backtrack_class_def = this+backtrackClassDef;
2235 const ClassDef &input_class_def = this+inputClassDef;
2236 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2237
Behdad Esfahbod2dc11412012-11-24 19:16:34 -05002238 index = input_class_def.get_class (c->buffer->cur().codepoint);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002239 const ChainRuleSet &rule_set = this+ruleSet[index];
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002240 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002241 {match_class},
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04002242 {&backtrack_class_def,
2243 &input_class_def,
2244 &lookahead_class_def}
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002245 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002246 return_trace (rule_set.apply (c, lookup_context));
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002247 }
2248
Behdad Esfahbod339d3602018-09-03 17:33:34 -07002249 inline bool subset (hb_subset_context_t *c) const
2250 {
2251 TRACE_SUBSET (this);
2252 // TODO(subset)
2253 return_trace (false);
2254 }
2255
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002256 inline bool sanitize (hb_sanitize_context_t *c) const
2257 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002258 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002259 return_trace (coverage.sanitize (c, this) &&
2260 backtrackClassDef.sanitize (c, this) &&
2261 inputClassDef.sanitize (c, this) &&
2262 lookaheadClassDef.sanitize (c, this) &&
2263 ruleSet.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002264 }
2265
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002266 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002267 HBUINT16 format; /* Format identifier--format = 2 */
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002268 OffsetTo<Coverage>
2269 coverage; /* Offset to Coverage table--from
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002270 * beginning of table */
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002271 OffsetTo<ClassDef>
2272 backtrackClassDef; /* Offset to glyph ClassDef table
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002273 * containing backtrack sequence
2274 * data--from beginning of table */
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002275 OffsetTo<ClassDef>
2276 inputClassDef; /* Offset to glyph ClassDef
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002277 * table containing input sequence
2278 * data--from beginning of table */
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002279 OffsetTo<ClassDef>
2280 lookaheadClassDef; /* Offset to glyph ClassDef table
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002281 * containing lookahead sequence
2282 * data--from beginning of table */
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002283 OffsetArrayOf<ChainRuleSet>
2284 ruleSet; /* Array of ChainRuleSet tables
2285 * ordered by class */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04002286 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04002287 DEFINE_SIZE_ARRAY (12, ruleSet);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002288};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002289
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002290struct ChainContextFormat3
2291{
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002292 inline bool intersects (const hb_set_t *glyphs) const
2293 {
2294 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2295
2296 if (!(this+input[0]).intersects (glyphs))
2297 return false;
2298
2299 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2300 struct ChainContextClosureLookupContext lookup_context = {
2301 {intersects_coverage},
2302 {this, this, this}
2303 };
2304 return chain_context_intersects (glyphs,
2305 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2306 input.len, (const HBUINT16 *) input.arrayZ + 1,
2307 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2308 lookup_context);
2309 }
2310
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002311 inline void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002312 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002313 TRACE_CLOSURE (this);
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002314 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2315
2316 if (!(this+input[0]).intersects (c->glyphs))
2317 return;
2318
2319 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2320 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2321 struct ChainContextClosureLookupContext lookup_context = {
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002322 {intersects_coverage},
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002323 {this, this, this}
2324 };
2325 chain_context_closure_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002326 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2327 input.len, (const HBUINT16 *) input.arrayZ + 1,
2328 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2329 lookup.len, lookup.arrayZ,
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002330 lookup_context);
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002331 }
2332
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002333 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
2334 {
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002335 TRACE_COLLECT_GLYPHS (this);
2336 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2337
Behdad Esfahbod83035932012-12-04 17:08:41 -05002338 (this+input[0]).add_coverage (c->input);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002339
2340 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2341 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2342 struct ChainContextCollectGlyphsLookupContext lookup_context = {
2343 {collect_coverage},
2344 {this, this, this}
2345 };
2346 chain_context_collect_glyphs_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002347 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2348 input.len, (const HBUINT16 *) input.arrayZ + 1,
2349 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2350 lookup.len, lookup.arrayZ,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002351 lookup_context);
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002352 }
2353
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002354 inline bool would_apply (hb_would_apply_context_t *c) const
2355 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002356 TRACE_WOULD_APPLY (this);
Behdad Esfahbode6f74792012-07-28 18:34:58 -04002357
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002358 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002359 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2360 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2361 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002362 {match_coverage},
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002363 {this, this, this}
2364 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002365 return_trace (chain_context_would_apply_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002366 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2367 input.len, (const HBUINT16 *) input.arrayZ + 1,
2368 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2369 lookup.len, lookup.arrayZ, lookup_context));
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002370 }
2371
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002372 inline const Coverage &get_coverage (void) const
2373 {
2374 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2375 return this+input[0];
2376 }
2377
Behdad Esfahbodfd034492018-01-17 16:46:51 -08002378 inline bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002379 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002380 TRACE_APPLY (this);
Behdad Esfahbode961c862010-04-21 15:56:11 -04002381 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04002382
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05002383 unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002384 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002385
Behdad Esfahbode961c862010-04-21 15:56:11 -04002386 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2387 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002388 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002389 {match_coverage},
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04002390 {this, this, this}
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04002391 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002392 return_trace (chain_context_apply_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002393 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2394 input.len, (const HBUINT16 *) input.arrayZ + 1,
2395 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2396 lookup.len, lookup.arrayZ, lookup_context));
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002397 }
2398
Behdad Esfahbod339d3602018-09-03 17:33:34 -07002399 inline bool subset (hb_subset_context_t *c) const
2400 {
2401 TRACE_SUBSET (this);
2402 // TODO(subset)
2403 return_trace (false);
2404 }
2405
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002406 inline bool sanitize (hb_sanitize_context_t *c) const
2407 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002408 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002409 if (!backtrack.sanitize (c, this)) return_trace (false);
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002410 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002411 if (!input.sanitize (c, this)) return_trace (false);
2412 if (!input.len) return_trace (false); /* To be consistent with Context. */
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002413 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002414 if (!lookahead.sanitize (c, this)) return_trace (false);
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002415 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002416 return_trace (lookup.sanitize (c));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002417 }
2418
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002419 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002420 HBUINT16 format; /* Format identifier--format = 3 */
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04002421 OffsetArrayOf<Coverage>
Behdad Esfahbod13ed4402009-05-18 02:14:37 -04002422 backtrack; /* Array of coverage tables
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002423 * in backtracking sequence, in glyph
2424 * sequence order */
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04002425 OffsetArrayOf<Coverage>
Behdad Esfahbod13ed4402009-05-18 02:14:37 -04002426 inputX ; /* Array of coverage
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002427 * tables in input sequence, in glyph
2428 * sequence order */
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04002429 OffsetArrayOf<Coverage>
Behdad Esfahbod13ed4402009-05-18 02:14:37 -04002430 lookaheadX; /* Array of coverage tables
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002431 * in lookahead sequence, in glyph
2432 * sequence order */
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04002433 ArrayOf<LookupRecord>
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04002434 lookupX; /* Array of LookupRecords--in
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04002435 * design order) */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04002436 public:
Behdad Esfahbodbea34c72010-05-10 17:28:16 -04002437 DEFINE_SIZE_MIN (10);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002438};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002439
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002440struct ChainContext
2441{
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002442 template <typename context_t>
Behdad Esfahbod9c5a9ee2013-03-09 01:55:04 -05002443 inline typename context_t::return_t dispatch (context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002444 {
Behdad Esfahbod00f6a8e2014-12-12 20:36:49 -08002445 TRACE_DISPATCH (this, u.format);
Behdad Esfahbodf396fbb2015-10-09 12:25:55 -04002446 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002447 switch (u.format) {
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002448 case 1: return_trace (c->dispatch (u.format1));
2449 case 2: return_trace (c->dispatch (u.format2));
2450 case 3: return_trace (c->dispatch (u.format3));
2451 default:return_trace (c->default_return_value ());
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002452 }
2453 }
2454
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002455 protected:
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002456 union {
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002457 HBUINT16 format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -04002458 ChainContextFormat1 format1;
2459 ChainContextFormat2 format2;
2460 ChainContextFormat3 format3;
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002461 } u;
2462};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002463
2464
Behdad Esfahbod095a1252015-02-19 10:29:41 +03002465template <typename T>
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002466struct ExtensionFormat1
2467{
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002468 inline unsigned int get_type (void) const { return extensionLookupType; }
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002469
Behdad Esfahbod095a1252015-02-19 10:29:41 +03002470 template <typename X>
2471 inline const X& get_subtable (void) const
2472 {
2473 unsigned int offset = extensionOffset;
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07002474 if (unlikely (!offset)) return Null(typename T::SubTable);
2475 return StructAtOffset<typename T::SubTable> (this, offset);
Behdad Esfahbod095a1252015-02-19 10:29:41 +03002476 }
2477
2478 template <typename context_t>
2479 inline typename context_t::return_t dispatch (context_t *c) const
2480 {
2481 TRACE_DISPATCH (this, format);
Behdad Esfahbodf396fbb2015-10-09 12:25:55 -04002482 if (unlikely (!c->may_dispatch (this, this))) return_trace (c->no_dispatch_return_value ());
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07002483 return_trace (get_subtable<typename T::SubTable> ().dispatch (c, get_type ()));
Behdad Esfahbod095a1252015-02-19 10:29:41 +03002484 }
2485
2486 /* This is called from may_dispatch() above with hb_sanitize_context_t. */
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002487 inline bool sanitize (hb_sanitize_context_t *c) const
2488 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002489 TRACE_SANITIZE (this);
Behdad Esfahbod949f6af2018-01-15 20:44:10 -05002490 return_trace (c->check_struct (this) &&
2491 extensionOffset != 0 &&
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07002492 extensionLookupType != T::SubTable::Extension);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002493 }
2494
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002495 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002496 HBUINT16 format; /* Format identifier. Set to 1. */
2497 HBUINT16 extensionLookupType; /* Lookup type of subtable referenced
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002498 * by ExtensionOffset (i.e. the
2499 * extension subtable). */
Behdad Esfahbodbcb6f1a2018-01-15 20:34:05 -05002500 HBUINT32 extensionOffset; /* Offset to the extension subtable,
Behdad Esfahbod81f2af42010-04-22 00:58:49 -04002501 * of lookup type subtable. */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04002502 public:
2503 DEFINE_SIZE_STATIC (8);
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002504};
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002505
Behdad Esfahbod653eeb22012-11-23 16:57:36 -05002506template <typename T>
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002507struct Extension
2508{
2509 inline unsigned int get_type (void) const
2510 {
2511 switch (u.format) {
Behdad Esfahboddacebca2010-05-10 19:45:41 -04002512 case 1: return u.format1.get_type ();
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002513 default:return 0;
2514 }
2515 }
Behdad Esfahbod7dddd4e2012-11-23 17:04:55 -05002516 template <typename X>
2517 inline const X& get_subtable (void) const
2518 {
Behdad Esfahbod095a1252015-02-19 10:29:41 +03002519 switch (u.format) {
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07002520 case 1: return u.format1.template get_subtable<typename T::SubTable> ();
2521 default:return Null(typename T::SubTable);
Behdad Esfahbod095a1252015-02-19 10:29:41 +03002522 }
Behdad Esfahbod7dddd4e2012-11-23 17:04:55 -05002523 }
2524
Behdad Esfahbod653eeb22012-11-23 16:57:36 -05002525 template <typename context_t>
Behdad Esfahbod9c5a9ee2013-03-09 01:55:04 -05002526 inline typename context_t::return_t dispatch (context_t *c) const
Behdad Esfahbod653eeb22012-11-23 16:57:36 -05002527 {
Behdad Esfahbod095a1252015-02-19 10:29:41 +03002528 TRACE_DISPATCH (this, u.format);
Behdad Esfahbodf396fbb2015-10-09 12:25:55 -04002529 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002530 switch (u.format) {
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002531 case 1: return_trace (u.format1.dispatch (c));
2532 default:return_trace (c->default_return_value ());
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002533 }
2534 }
2535
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002536 protected:
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002537 union {
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002538 HBUINT16 format; /* Format identifier */
Behdad Esfahbod095a1252015-02-19 10:29:41 +03002539 ExtensionFormat1<T> format1;
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002540 } u;
2541};
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002542
2543
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04002544/*
2545 * GSUB/GPOS Common
2546 */
2547
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002548struct GSUBGPOS
2549{
Behdad Esfahbodb912fbe2018-08-06 06:30:12 -07002550 inline bool has_data (void) const { return version.to_int () != 0; }
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04002551 inline unsigned int get_script_count (void) const
2552 { return (this+scriptList).len; }
2553 inline const Tag& get_script_tag (unsigned int i) const
2554 { return (this+scriptList).get_tag (i); }
Behdad Esfahbode21899b2009-11-04 16:36:14 -05002555 inline unsigned int get_script_tags (unsigned int start_offset,
2556 unsigned int *script_count /* IN/OUT */,
2557 hb_tag_t *script_tags /* OUT */) const
2558 { return (this+scriptList).get_tags (start_offset, script_count, script_tags); }
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04002559 inline const Script& get_script (unsigned int i) const
2560 { return (this+scriptList)[i]; }
2561 inline bool find_script_index (hb_tag_t tag, unsigned int *index) const
2562 { return (this+scriptList).find_index (tag, index); }
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04002563
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04002564 inline unsigned int get_feature_count (void) const
2565 { return (this+featureList).len; }
Jonathan Kewda132932014-04-27 14:05:24 +01002566 inline hb_tag_t get_feature_tag (unsigned int i) const
2567 { return i == Index::NOT_FOUND_INDEX ? HB_TAG_NONE : (this+featureList).get_tag (i); }
Behdad Esfahbode21899b2009-11-04 16:36:14 -05002568 inline unsigned int get_feature_tags (unsigned int start_offset,
2569 unsigned int *feature_count /* IN/OUT */,
2570 hb_tag_t *feature_tags /* OUT */) const
2571 { return (this+featureList).get_tags (start_offset, feature_count, feature_tags); }
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04002572 inline const Feature& get_feature (unsigned int i) const
2573 { return (this+featureList)[i]; }
2574 inline bool find_feature_index (hb_tag_t tag, unsigned int *index) const
2575 { return (this+featureList).find_index (tag, index); }
2576
2577 inline unsigned int get_lookup_count (void) const
2578 { return (this+lookupList).len; }
2579 inline const Lookup& get_lookup (unsigned int i) const
2580 { return (this+lookupList)[i]; }
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04002581
Behdad Esfahbod30c42b62016-09-10 03:32:39 -07002582 inline bool find_variations_index (const int *coords, unsigned int num_coords,
2583 unsigned int *index) const
Behdad Esfahbod59055b52016-09-10 01:24:28 -07002584 { return (version.to_int () >= 0x00010001u ? this+featureVars : Null(FeatureVariations))
Behdad Esfahbod30c42b62016-09-10 03:32:39 -07002585 .find_index (coords, num_coords, index); }
Behdad Esfahbodec87ba92016-09-10 03:53:11 -07002586 inline const Feature& get_feature_variation (unsigned int feature_index,
2587 unsigned int variations_index) const
2588 {
2589 if (FeatureVariations::NOT_FOUND_INDEX != variations_index &&
2590 version.to_int () >= 0x00010001u)
2591 {
Behdad Esfahbod4ebbeb72016-09-10 04:52:34 -07002592 const Feature *feature = (this+featureVars).find_substitute (variations_index,
2593 feature_index);
Behdad Esfahbodec87ba92016-09-10 03:53:11 -07002594 if (feature)
2595 return *feature;
2596 }
2597 return get_feature (feature_index);
2598 }
Behdad Esfahbod59055b52016-09-10 01:24:28 -07002599
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07002600 template <typename TLookup>
Behdad Esfahbodbfa72a92018-09-01 18:34:50 -07002601 inline bool subset (hb_subset_context_t *c) const
2602 {
2603 TRACE_SUBSET (this);
2604 struct GSUBGPOS *out = c->serializer->embed (*this);
2605 if (unlikely (!out)) return_trace (false);
Behdad Esfahbod49c44b52018-09-03 16:37:17 -07002606 out->scriptList.serialize_subset (c, this+scriptList, out);
2607 out->featureList.serialize_subset (c, this+featureList, out);
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07002608
2609 typedef OffsetListOf<TLookup> TLookupList;
2610 /* TODO Use intersects() to count how many subtables survive? */
2611 CastR<OffsetTo<TLookupList> > (out->lookupList)
2612 .serialize_subset (c,
2613 this+CastR<const OffsetTo<TLookupList> > (lookupList),
2614 out);
2615
Behdad Esfahbodbfa72a92018-09-01 18:34:50 -07002616 if (version.to_int () >= 0x00010001u)
Behdad Esfahbod49c44b52018-09-03 16:37:17 -07002617 out->featureVars.serialize_subset (c, this+featureVars, out);
Behdad Esfahbodbfa72a92018-09-01 18:34:50 -07002618 return_trace (true);
2619 }
2620
2621 inline unsigned int get_size (void) const
2622 {
2623 return min_size +
2624 (version.to_int () >= 0x00010001u ? featureVars.static_size : 0);
2625 }
2626
Behdad Esfahbod6d618522018-09-03 16:41:28 -07002627 template <typename TLookup>
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002628 inline bool sanitize (hb_sanitize_context_t *c) const
2629 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002630 TRACE_SANITIZE (this);
Behdad Esfahbod6d618522018-09-03 16:41:28 -07002631 typedef OffsetListOf<TLookup> TLookupList;
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002632 return_trace (version.sanitize (c) &&
2633 likely (version.major == 1) &&
2634 scriptList.sanitize (c, this) &&
2635 featureList.sanitize (c, this) &&
Behdad Esfahbod6d618522018-09-03 16:41:28 -07002636 CastR<OffsetTo<TLookupList> > (lookupList).sanitize (c, this) &&
Behdad Esfahbod59055b52016-09-10 01:24:28 -07002637 (version.to_int () < 0x00010001u || featureVars.sanitize (c, this)));
Behdad Esfahbodcd3827e2009-08-04 02:09:34 -04002638 }
2639
Behdad Esfahbod963413f2018-08-26 00:47:55 -07002640 template <typename T>
2641 struct accelerator_t
2642 {
2643 inline void init (hb_face_t *face)
2644 {
2645 this->blob = hb_sanitize_context_t().reference_table<T> (face);
Behdad Esfahbod453e0c62018-08-26 01:30:52 -07002646 table = this->blob->template as<T> ();
Behdad Esfahbod963413f2018-08-26 00:47:55 -07002647
Behdad Esfahbodb9291002018-08-26 01:15:47 -07002648 this->lookup_count = table->get_lookup_count ();
Behdad Esfahbod963413f2018-08-26 00:47:55 -07002649
2650 this->accels = (hb_ot_layout_lookup_accelerator_t *) calloc (this->lookup_count, sizeof (hb_ot_layout_lookup_accelerator_t));
2651 if (unlikely (!this->accels))
2652 this->lookup_count = 0;
2653
2654 for (unsigned int i = 0; i < this->lookup_count; i++)
Behdad Esfahbodb9291002018-08-26 01:15:47 -07002655 this->accels[i].init (table->get_lookup (i));
Behdad Esfahbod963413f2018-08-26 00:47:55 -07002656 }
2657
2658 inline void fini (void)
2659 {
Behdad Esfahbodb9291002018-08-26 01:15:47 -07002660 for (unsigned int i = 0; i < this->lookup_count; i++)
2661 this->accels[i].fini ();
2662 free (this->accels);
Behdad Esfahbod963413f2018-08-26 00:47:55 -07002663 hb_blob_destroy (this->blob);
Behdad Esfahbod963413f2018-08-26 00:47:55 -07002664 }
2665
Behdad Esfahbodb9291002018-08-26 01:15:47 -07002666 hb_blob_t *blob;
2667 const T *table;
2668 unsigned int lookup_count;
2669 hb_ot_layout_lookup_accelerator_t *accels;
Behdad Esfahbod963413f2018-08-26 00:47:55 -07002670 };
2671
Behdad Esfahbod212aba62009-05-24 00:50:27 -04002672 protected:
Behdad Esfahbod9a13ed42016-02-22 11:44:45 +09002673 FixedVersion<>version; /* Version of the GSUB/GPOS table--initially set
Behdad Esfahbod76271002014-07-11 14:54:42 -04002674 * to 0x00010000u */
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04002675 OffsetTo<ScriptList>
2676 scriptList; /* ScriptList table */
2677 OffsetTo<FeatureList>
2678 featureList; /* FeatureList table */
2679 OffsetTo<LookupList>
2680 lookupList; /* LookupList table */
Behdad Esfahbod5e156fa2017-01-22 20:28:56 -08002681 LOffsetTo<FeatureVariations>
Behdad Esfahbod59055b52016-09-10 01:24:28 -07002682 featureVars; /* Offset to Feature Variations
2683 table--from beginning of table
2684 * (may be NULL). Introduced
2685 * in version 0x00010001. */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04002686 public:
Behdad Esfahbod59055b52016-09-10 01:24:28 -07002687 DEFINE_SIZE_MIN (10);
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04002688};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002689
Behdad Esfahbod6f20f722009-05-17 20:28:01 -04002690
Behdad Esfahbod7d52e662012-11-16 18:49:54 -08002691} /* namespace OT */
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -04002692
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04002693
Behdad Esfahbodc77ae402018-08-25 22:36:36 -07002694#endif /* HB_OT_LAYOUT_GSUBGPOS_HH */