blob: c8f0ff10749338f174ca66c38bc009e98816a25c [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 Esfahbod71c9f842018-09-10 22:37:19 +020036#include "hb-ot-map.hh"
Behdad Esfahbodb9291002018-08-26 01:15:47 -070037#include "hb-ot-layout-common.hh"
38#include "hb-ot-layout-gdef-table.hh"
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -040039
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -040040
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -040041namespace OT {
42
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -040043
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -070044struct hb_intersects_context_t :
Behdad Esfahbod8d0a90a2020-06-18 16:53:54 -070045 hb_dispatch_context_t<hb_intersects_context_t, bool>
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -070046{
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -070047 template <typename T>
Behdad Esfahbodc14efb82019-05-05 09:54:58 -070048 return_t dispatch (const T &obj) { return obj.intersects (this->glyphs); }
Ebrahim Byagowie4120082018-12-17 21:31:01 +033049 static return_t default_return_value () { return false; }
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -070050 bool stop_sublookup_iteration (return_t r) const { return r; }
51
52 const hb_set_t *glyphs;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -070053
54 hb_intersects_context_t (const hb_set_t *glyphs_) :
Behdad Esfahbod70d66962020-06-18 17:09:39 -070055 glyphs (glyphs_) {}
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -070056};
57
Qunxin Liub4fc5932020-12-09 10:44:18 -080058struct hb_have_non_1to1_context_t :
59 hb_dispatch_context_t<hb_have_non_1to1_context_t, bool>
60{
61 template <typename T>
62 return_t dispatch (const T &obj) { return obj.may_have_non_1to1 (); }
63 static return_t default_return_value () { return false; }
64 bool stop_sublookup_iteration (return_t r) const { return r; }
65};
66
Behdad Esfahbod77a1a2b2015-10-09 12:20:58 -040067struct hb_closure_context_t :
Behdad Esfahbod25aec022020-06-18 16:58:01 -070068 hb_dispatch_context_t<hb_closure_context_t>
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -040069{
Behdad Esfahbod44fc2372012-11-21 23:33:13 -050070 typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
71 template <typename T>
Behdad Esfahbod7df3ecf2019-05-10 20:43:26 -070072 return_t dispatch (const T &obj) { obj.closure (this); return hb_empty_t (); }
73 static return_t default_return_value () { return hb_empty_t (); }
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -070074 void recurse (unsigned int lookup_index)
Behdad Esfahbod44fc2372012-11-21 23:33:13 -050075 {
Behdad Esfahbod9b346772012-11-23 17:55:40 -050076 if (unlikely (nesting_level_left == 0 || !recurse_func))
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -070077 return;
Behdad Esfahbod44fc2372012-11-21 23:33:13 -050078
79 nesting_level_left--;
80 recurse_func (this, lookup_index);
81 nesting_level_left++;
Behdad Esfahbod44fc2372012-11-21 23:33:13 -050082 }
83
Garret Rieger4ad686b2020-03-25 23:32:28 -070084 bool lookup_limit_exceeded ()
Ebrahim Byagowi1a482782020-03-26 11:15:09 +043085 { return lookup_count > HB_MAX_LOOKUP_INDICES; }
Garret Rieger4ad686b2020-03-25 23:32:28 -070086
Behdad Esfahbodba0ea562018-06-11 23:24:41 -040087 bool should_visit_lookup (unsigned int lookup_index)
Garret Rieger45186b92018-06-05 17:14:42 -070088 {
Garret Rieger834a2242020-03-12 03:02:36 -070089 if (lookup_count++ > HB_MAX_LOOKUP_INDICES)
90 return false;
91
Garret Rieger45186b92018-06-05 17:14:42 -070092 if (is_lookup_done (lookup_index))
93 return false;
Garret Rieger834a2242020-03-12 03:02:36 -070094
Garret Rieger45186b92018-06-05 17:14:42 -070095 done_lookups->set (lookup_index, glyphs->get_population ());
96 return true;
97 }
98
99 bool is_lookup_done (unsigned int lookup_index)
100 {
Behdad Esfahbodd7e2a512021-02-11 10:55:03 -0700101 if (unlikely (done_lookups->in_error ()))
Garret Rieger1e4fe102020-08-12 13:06:37 -0700102 return true;
103
Behdad Esfahbodc38bd402018-07-24 09:43:27 -0700104 /* Have we visited this lookup with the current set of glyphs? */
Garret Rieger45186b92018-06-05 17:14:42 -0700105 return done_lookups->get (lookup_index) == glyphs->get_population ();
106 }
107
Qunxin Liub4fc5932020-12-09 10:44:18 -0800108 hb_set_t* parent_active_glyphs ()
109 {
110 return active_glyphs_stack.tail ();
111 }
112
113 void push_cur_active_glyphs (hb_set_t* cur_active_glyph_set)
114 {
115 active_glyphs_stack.push (cur_active_glyph_set);
116 }
117
118 bool pop_cur_done_glyphs ()
119 {
120 if (active_glyphs_stack.length < 1)
121 return false;
122
123 active_glyphs_stack.pop ();
124 return true;
125 }
126
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400127 hb_face_t *face;
Behdad Esfahbod6a9be5b2012-04-23 22:23:17 -0400128 hb_set_t *glyphs;
Behdad Esfahbodede1a712019-01-09 10:45:53 -0800129 hb_set_t output[1];
Qunxin Liub4fc5932020-12-09 10:44:18 -0800130 hb_vector_t<hb_set_t *> active_glyphs_stack;
Behdad Esfahbod44fc2372012-11-21 23:33:13 -0500131 recurse_func_t recurse_func;
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400132 unsigned int nesting_level_left;
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400133
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400134 hb_closure_context_t (hb_face_t *face_,
Behdad Esfahbod6a9be5b2012-04-23 22:23:17 -0400135 hb_set_t *glyphs_,
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330136 hb_map_t *done_lookups_,
137 unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400138 face (face_),
139 glyphs (glyphs_),
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200140 recurse_func (nullptr),
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400141 nesting_level_left (nesting_level_left_),
Garret Rieger834a2242020-03-12 03:02:36 -0700142 done_lookups (done_lookups_),
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +0430143 lookup_count (0)
Qunxin Liub4fc5932020-12-09 10:44:18 -0800144 {
145 push_cur_active_glyphs (glyphs_);
146 }
Behdad Esfahbod9b346772012-11-23 17:55:40 -0500147
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330148 ~hb_closure_context_t () { flush (); }
Behdad Esfahbodc38bd402018-07-24 09:43:27 -0700149
Behdad Esfahbod9b346772012-11-23 17:55:40 -0500150 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
Garret Rieger45186b92018-06-05 17:14:42 -0700151
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330152 void flush ()
Behdad Esfahbodc38bd402018-07-24 09:43:27 -0700153 {
Michiharu Arizaff5223b2020-02-23 15:53:21 -0800154 hb_set_del_range (output, face->get_num_glyphs (), hb_set_get_max (output)); /* Remove invalid glyphs. */
Behdad Esfahbodede1a712019-01-09 10:45:53 -0800155 hb_set_union (glyphs, output);
156 hb_set_clear (output);
Qunxin Liub4fc5932020-12-09 10:44:18 -0800157 active_glyphs_stack.pop ();
158 active_glyphs_stack.fini ();
Behdad Esfahbodc38bd402018-07-24 09:43:27 -0700159 }
160
Garret Rieger45186b92018-06-05 17:14:42 -0700161 private:
162 hb_map_t *done_lookups;
Garret Rieger834a2242020-03-12 03:02:36 -0700163 unsigned int lookup_count;
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400164};
165
Qunxin Liu0b39c482019-10-22 16:00:43 -0700166struct hb_closure_lookups_context_t :
Behdad Esfahbod25aec022020-06-18 16:58:01 -0700167 hb_dispatch_context_t<hb_closure_lookups_context_t>
Qunxin Liu0b39c482019-10-22 16:00:43 -0700168{
Qunxin Liu0b39c482019-10-22 16:00:43 -0700169 typedef return_t (*recurse_func_t) (hb_closure_lookups_context_t *c, unsigned lookup_index);
170 template <typename T>
171 return_t dispatch (const T &obj) { obj.closure_lookups (this); return hb_empty_t (); }
172 static return_t default_return_value () { return hb_empty_t (); }
173 void recurse (unsigned lookup_index)
174 {
175 if (unlikely (nesting_level_left == 0 || !recurse_func))
176 return;
177
178 /* Return if new lookup was recursed to before. */
179 if (is_lookup_visited (lookup_index))
180 return;
181
Qunxin Liu0b39c482019-10-22 16:00:43 -0700182 nesting_level_left--;
183 recurse_func (this, lookup_index);
184 nesting_level_left++;
185 }
186
187 void set_lookup_visited (unsigned lookup_index)
188 { visited_lookups->add (lookup_index); }
189
190 void set_lookup_inactive (unsigned lookup_index)
191 { inactive_lookups->add (lookup_index); }
192
Garret Rieger4ad686b2020-03-25 23:32:28 -0700193 bool lookup_limit_exceeded ()
Ebrahim Byagowi1a482782020-03-26 11:15:09 +0430194 { return lookup_count > HB_MAX_LOOKUP_INDICES; }
Garret Rieger4ad686b2020-03-25 23:32:28 -0700195
Qunxin Liu0b39c482019-10-22 16:00:43 -0700196 bool is_lookup_visited (unsigned lookup_index)
Garret Rieger834a2242020-03-12 03:02:36 -0700197 {
Behdad Esfahbodd7e2a512021-02-11 10:55:03 -0700198 if (unlikely (lookup_count++ > HB_MAX_LOOKUP_INDICES))
Garret Rieger834a2242020-03-12 03:02:36 -0700199 return true;
200
Behdad Esfahbodd7e2a512021-02-11 10:55:03 -0700201 if (unlikely (visited_lookups->in_error ()))
Garret Rieger95622392020-08-12 13:01:22 -0700202 return true;
203
Garret Rieger834a2242020-03-12 03:02:36 -0700204 return visited_lookups->has (lookup_index);
205 }
Qunxin Liu0b39c482019-10-22 16:00:43 -0700206
207 hb_face_t *face;
208 const hb_set_t *glyphs;
209 recurse_func_t recurse_func;
210 unsigned int nesting_level_left;
Qunxin Liu0b39c482019-10-22 16:00:43 -0700211
212 hb_closure_lookups_context_t (hb_face_t *face_,
213 const hb_set_t *glyphs_,
214 hb_set_t *visited_lookups_,
215 hb_set_t *inactive_lookups_,
216 unsigned nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
217 face (face_),
218 glyphs (glyphs_),
219 recurse_func (nullptr),
220 nesting_level_left (nesting_level_left_),
Qunxin Liu0b39c482019-10-22 16:00:43 -0700221 visited_lookups (visited_lookups_),
Garret Rieger834a2242020-03-12 03:02:36 -0700222 inactive_lookups (inactive_lookups_),
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +0430223 lookup_count (0) {}
Qunxin Liu0b39c482019-10-22 16:00:43 -0700224
225 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
226
227 private:
228 hb_set_t *visited_lookups;
229 hb_set_t *inactive_lookups;
Garret Rieger834a2242020-03-12 03:02:36 -0700230 unsigned int lookup_count;
Qunxin Liu0b39c482019-10-22 16:00:43 -0700231};
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400232
Behdad Esfahbod77a1a2b2015-10-09 12:20:58 -0400233struct hb_would_apply_context_t :
Behdad Esfahbod8d0a90a2020-06-18 16:53:54 -0700234 hb_dispatch_context_t<hb_would_apply_context_t, bool>
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400235{
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500236 template <typename T>
Behdad Esfahbodc14efb82019-05-05 09:54:58 -0700237 return_t dispatch (const T &obj) { return obj.would_apply (this); }
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330238 static return_t default_return_value () { return false; }
Behdad Esfahbod7b912c12013-01-04 01:25:27 -0600239 bool stop_sublookup_iteration (return_t r) const { return r; }
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500240
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400241 hb_face_t *face;
Behdad Esfahbod472f2292012-08-07 22:25:24 -0400242 const hb_codepoint_t *glyphs;
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400243 unsigned int len;
Behdad Esfahbodd9b204d2012-08-23 16:22:28 -0400244 bool zero_context;
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400245
246 hb_would_apply_context_t (hb_face_t *face_,
Behdad Esfahbod472f2292012-08-07 22:25:24 -0400247 const hb_codepoint_t *glyphs_,
248 unsigned int len_,
Behdad Esfahbod2bd9fe32012-09-04 15:15:19 -0400249 bool zero_context_) :
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400250 face (face_),
Behdad Esfahbod472f2292012-08-07 22:25:24 -0400251 glyphs (glyphs_),
252 len (len_),
Behdad Esfahbod70d66962020-06-18 17:09:39 -0700253 zero_context (zero_context_) {}
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400254};
255
Behdad Esfahbod77a1a2b2015-10-09 12:20:58 -0400256struct hb_collect_glyphs_context_t :
Behdad Esfahbod25aec022020-06-18 16:58:01 -0700257 hb_dispatch_context_t<hb_collect_glyphs_context_t>
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800258{
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500259 typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index);
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500260 template <typename T>
Behdad Esfahbod7df3ecf2019-05-10 20:43:26 -0700261 return_t dispatch (const T &obj) { obj.collect_glyphs (this); return hb_empty_t (); }
262 static return_t default_return_value () { return hb_empty_t (); }
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700263 void recurse (unsigned int lookup_index)
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500264 {
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500265 if (unlikely (nesting_level_left == 0 || !recurse_func))
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700266 return;
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500267
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200268 /* Note that GPOS sets recurse_func to nullptr already, so it doesn't get
Behdad Esfahbod1bcfa062012-12-04 16:58:09 -0500269 * past the previous check. For GSUB, we only want to collect the output
Behdad Esfahbod76ea5632013-05-04 16:01:20 -0400270 * glyphs in the recursion. If output is not requested, we can go home now.
271 *
272 * Note further, that the above is not exactly correct. A recursed lookup
273 * is allowed to match input that is not matched in the context, but that's
274 * not how most fonts are built. It's possible to relax that and recurse
275 * with all sets here if it proves to be an issue.
276 */
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500277
278 if (output == hb_set_get_empty ())
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700279 return;
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500280
Behdad Esfahbodfde3e4a2014-10-29 11:23:08 -0700281 /* Return if new lookup was recursed to before. */
Behdad Esfahbod8b9d9b72017-10-22 17:48:06 -0400282 if (recursed_lookups->has (lookup_index))
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700283 return;
Behdad Esfahbodfde3e4a2014-10-29 11:23:08 -0700284
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500285 hb_set_t *old_before = before;
286 hb_set_t *old_input = input;
287 hb_set_t *old_after = after;
288 before = input = after = hb_set_get_empty ();
Behdad Esfahbod1bcfa062012-12-04 16:58:09 -0500289
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500290 nesting_level_left--;
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500291 recurse_func (this, lookup_index);
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500292 nesting_level_left++;
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500293
294 before = old_before;
295 input = old_input;
296 after = old_after;
297
Behdad Esfahbod8b9d9b72017-10-22 17:48:06 -0400298 recursed_lookups->add (lookup_index);
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500299 }
300
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800301 hb_face_t *face;
Behdad Esfahbod83035932012-12-04 17:08:41 -0500302 hb_set_t *before;
303 hb_set_t *input;
304 hb_set_t *after;
305 hb_set_t *output;
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500306 recurse_func_t recurse_func;
Behdad Esfahbod8b9d9b72017-10-22 17:48:06 -0400307 hb_set_t *recursed_lookups;
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500308 unsigned int nesting_level_left;
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800309
310 hb_collect_glyphs_context_t (hb_face_t *face_,
Ebrahim Byagowi63109432018-10-13 14:00:05 +0330311 hb_set_t *glyphs_before, /* OUT. May be NULL */
312 hb_set_t *glyphs_input, /* OUT. May be NULL */
313 hb_set_t *glyphs_after, /* OUT. May be NULL */
314 hb_set_t *glyphs_output, /* OUT. May be NULL */
Behdad Esfahbod5ba45042015-11-02 15:43:08 -0800315 unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800316 face (face_),
Behdad Esfahbod83035932012-12-04 17:08:41 -0500317 before (glyphs_before ? glyphs_before : hb_set_get_empty ()),
318 input (glyphs_input ? glyphs_input : hb_set_get_empty ()),
319 after (glyphs_after ? glyphs_after : hb_set_get_empty ()),
320 output (glyphs_output ? glyphs_output : hb_set_get_empty ()),
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200321 recurse_func (nullptr),
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700322 recursed_lookups (hb_set_create ()),
Behdad Esfahbod70d66962020-06-18 17:09:39 -0700323 nesting_level_left (nesting_level_left_) {}
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330324 ~hb_collect_glyphs_context_t () { hb_set_destroy (recursed_lookups); }
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500325
326 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800327};
328
329
330
Behdad Esfahbod8e36ccf2015-02-17 19:15:34 +0300331template <typename set_t>
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -0700332struct hb_collect_coverage_context_t :
Behdad Esfahbod8d0a90a2020-06-18 16:53:54 -0700333 hb_dispatch_context_t<hb_collect_coverage_context_t<set_t>, const Coverage &>
Behdad Esfahbod2005fa52012-11-22 14:38:10 -0500334{
Behdad Esfahboddc492d72020-06-18 17:03:05 -0700335 typedef const Coverage &return_t; // Stoopid that we have to dupe this here.
Behdad Esfahbod2005fa52012-11-22 14:38:10 -0500336 template <typename T>
Behdad Esfahbodc14efb82019-05-05 09:54:58 -0700337 return_t dispatch (const T &obj) { return obj.get_coverage (); }
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +0430338 static return_t default_return_value () { return Null (Coverage); }
Behdad Esfahbod8e36ccf2015-02-17 19:15:34 +0300339 bool stop_sublookup_iteration (return_t r) const
340 {
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -0700341 r.collect_coverage (set);
Behdad Esfahbod8e36ccf2015-02-17 19:15:34 +0300342 return false;
343 }
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500344
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -0700345 hb_collect_coverage_context_t (set_t *set_) :
Behdad Esfahbod70d66962020-06-18 17:09:39 -0700346 set (set_) {}
Behdad Esfahboda1733db2012-11-23 16:40:04 -0500347
Behdad Esfahbod8e36ccf2015-02-17 19:15:34 +0300348 set_t *set;
Behdad Esfahbod2005fa52012-11-22 14:38:10 -0500349};
350
351
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800352struct hb_ot_apply_context_t :
353 hb_dispatch_context_t<hb_ot_apply_context_t, bool, HB_DEBUG_APPLY>
Behdad Esfahbod1376fb72010-04-29 02:19:21 -0400354{
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500355 struct matcher_t
356 {
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330357 matcher_t () :
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500358 lookup_props (0),
Behdad Esfahbodcfc507c2013-02-14 10:40:12 -0500359 ignore_zwnj (false),
360 ignore_zwj (false),
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500361 mask (-1),
362#define arg1(arg) (arg) /* Remove the macro to see why it's needed! */
363 syllable arg1(0),
364#undef arg1
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200365 match_func (nullptr),
Ebrahim Byagowif7a08cd2018-10-30 11:29:09 +0330366 match_data (nullptr) {}
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500367
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100368 typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500369
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330370 void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; }
371 void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
372 void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
373 void set_mask (hb_mask_t mask_) { mask = mask_; }
374 void set_syllable (uint8_t syllable_) { syllable = syllable_; }
375 void set_match_func (match_func_t match_func_,
Ebrahim Byagowid0e2add2020-07-18 22:14:52 +0430376 const void *match_data_)
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500377 { match_func = match_func_; match_data = match_data_; }
378
Behdad Esfahbod2b2a6e82013-02-21 15:07:03 -0500379 enum may_match_t {
380 MATCH_NO,
381 MATCH_YES,
382 MATCH_MAYBE
383 };
384
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330385 may_match_t may_match (const hb_glyph_info_t &info,
Behdad Esfahbod085793d2019-04-24 10:15:59 -0400386 const HBUINT16 *glyph_data) const
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500387 {
Behdad Esfahbod2b2a6e82013-02-21 15:07:03 -0500388 if (!(info.mask & mask) ||
389 (syllable && syllable != info.syllable ()))
390 return MATCH_NO;
391
392 if (match_func)
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330393 return match_func (info.codepoint, *glyph_data, match_data) ? MATCH_YES : MATCH_NO;
Behdad Esfahbod2b2a6e82013-02-21 15:07:03 -0500394
395 return MATCH_MAYBE;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500396 }
397
398 enum may_skip_t {
399 SKIP_NO,
400 SKIP_YES,
401 SKIP_MAYBE
402 };
403
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330404 may_skip_t may_skip (const hb_ot_apply_context_t *c,
405 const hb_glyph_info_t &info) const
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500406 {
Behdad Esfahbodb98c5db2014-07-16 13:44:01 -0400407 if (!c->check_glyph_property (&info, lookup_props))
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500408 return SKIP_YES;
409
Khaled Hosny06cfe3f2017-05-17 21:32:47 +0300410 if (unlikely (_hb_glyph_info_is_default_ignorable_and_not_hidden (&info) &&
Behdad Esfahbod0b454792013-02-14 10:46:52 -0500411 (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) &&
Behdad Esfahbod4ba796b2015-07-22 17:41:31 +0100412 (ignore_zwj || !_hb_glyph_info_is_zwj (&info))))
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500413 return SKIP_MAYBE;
414
415 return SKIP_NO;
416 }
417
418 protected:
419 unsigned int lookup_props;
420 bool ignore_zwnj;
Behdad Esfahbod0b454792013-02-14 10:46:52 -0500421 bool ignore_zwj;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500422 hb_mask_t mask;
423 uint8_t syllable;
424 match_func_t match_func;
425 const void *match_data;
426 };
427
Behdad Esfahbod69626692015-01-29 13:08:41 +0100428 struct skipping_iterator_t
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500429 {
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330430 void init (hb_ot_apply_context_t *c_, bool context_match = false)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500431 {
Behdad Esfahbod514564f2015-01-29 13:48:48 +0100432 c = c_;
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200433 match_glyph_data = nullptr;
434 matcher.set_match_func (nullptr, nullptr);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500435 matcher.set_lookup_props (c->lookup_props);
Behdad Esfahbod3583fb02018-09-23 22:33:38 -0400436 /* Ignore ZWNJ if we are matching GPOS, or matching GSUB context and asked to. */
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100437 matcher.set_ignore_zwnj (c->table_index == 1 || (context_match && c->auto_zwnj));
Behdad Esfahbod3583fb02018-09-23 22:33:38 -0400438 /* Ignore ZWJ if we are matching context, or asked to. */
439 matcher.set_ignore_zwj (context_match || c->auto_zwj);
Behdad Esfahbod514564f2015-01-29 13:48:48 +0100440 matcher.set_mask (context_match ? -1 : c->lookup_mask);
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500441 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330442 void set_lookup_props (unsigned int lookup_props)
Behdad Esfahbod514564f2015-01-29 13:48:48 +0100443 {
444 matcher.set_lookup_props (lookup_props);
445 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330446 void set_match_func (matcher_t::match_func_t match_func_,
447 const void *match_data_,
448 const HBUINT16 glyph_data[])
Behdad Esfahbodc074ebc2013-02-13 11:22:42 -0500449 {
Behdad Esfahbod4a6b1ee2015-10-21 11:20:55 -0200450 matcher.set_match_func (match_func_, match_data_);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500451 match_glyph_data = glyph_data;
Behdad Esfahbodc074ebc2013-02-13 11:22:42 -0500452 }
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500453
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330454 void reset (unsigned int start_index_,
Ebrahim Byagowi08428a12020-04-24 23:45:17 +0430455 unsigned int num_items_)
Behdad Esfahbodb051be52015-01-29 13:40:39 +0100456 {
457 idx = start_index_;
458 num_items = num_items_;
459 end = c->buffer->len;
460 matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
461 }
462
Ebrahim Byagowi64a45be2019-11-09 12:25:33 +0330463 void reject ()
464 {
465 num_items++;
466 if (match_glyph_data) match_glyph_data--;
467 }
Behdad Esfahbod69626692015-01-29 13:08:41 +0100468
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330469 matcher_t::may_skip_t
470 may_skip (const hb_glyph_info_t &info) const
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330471 { return matcher.may_skip (c, info); }
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200472
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330473 bool next ()
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500474 {
Behdad Esfahbod506ffeb2012-01-18 16:07:53 -0500475 assert (num_items > 0);
Behdad Esfahbod37d13ac2015-01-29 11:38:01 +0100476 while (idx + num_items < end)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500477 {
Behdad Esfahboda4a48fe2012-01-17 18:08:41 -0500478 idx++;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500479 const hb_glyph_info_t &info = c->buffer->info[idx];
480
Behdad Esfahbodff93ac82013-02-21 14:51:40 -0500481 matcher_t::may_skip_t skip = matcher.may_skip (c, info);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500482 if (unlikely (skip == matcher_t::SKIP_YES))
483 continue;
484
Behdad Esfahbod2b2a6e82013-02-21 15:07:03 -0500485 matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
Behdad Esfahbod722e8b82013-02-21 15:37:51 -0500486 if (match == matcher_t::MATCH_YES ||
487 (match == matcher_t::MATCH_MAYBE &&
488 skip == matcher_t::SKIP_NO))
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500489 {
490 num_items--;
Ebrahim Byagowiaca63902019-10-22 00:06:46 +0330491 if (match_glyph_data) match_glyph_data++;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500492 return true;
493 }
494
495 if (skip == matcher_t::SKIP_NO)
Behdad Esfahbod722e8b82013-02-21 15:37:51 -0500496 return false;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500497 }
498 return false;
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500499 }
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330500 bool prev ()
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500501 {
Behdad Esfahbod506ffeb2012-01-18 16:07:53 -0500502 assert (num_items > 0);
Behdad Esfahbod18a06f82018-07-05 14:03:48 +0430503 while (idx > num_items - 1)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500504 {
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500505 idx--;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500506 const hb_glyph_info_t &info = c->buffer->out_info[idx];
507
Behdad Esfahbodff93ac82013-02-21 14:51:40 -0500508 matcher_t::may_skip_t skip = matcher.may_skip (c, info);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500509 if (unlikely (skip == matcher_t::SKIP_YES))
510 continue;
511
Behdad Esfahbod2b2a6e82013-02-21 15:07:03 -0500512 matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
Behdad Esfahbod722e8b82013-02-21 15:37:51 -0500513 if (match == matcher_t::MATCH_YES ||
514 (match == matcher_t::MATCH_MAYBE &&
515 skip == matcher_t::SKIP_NO))
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500516 {
517 num_items--;
Ebrahim Byagowiaca63902019-10-22 00:06:46 +0330518 if (match_glyph_data) match_glyph_data++;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500519 return true;
520 }
521
522 if (skip == matcher_t::SKIP_NO)
Behdad Esfahbod722e8b82013-02-21 15:37:51 -0500523 return false;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500524 }
525 return false;
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500526 }
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500527
528 unsigned int idx;
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400529 protected:
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800530 hb_ot_apply_context_t *c;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500531 matcher_t matcher;
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100532 const HBUINT16 *match_glyph_data;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500533
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500534 unsigned int num_items;
Behdad Esfahbod69626692015-01-29 13:08:41 +0100535 unsigned int end;
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500536 };
537
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100538
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330539 const char *get_name () { return "APPLY"; }
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800540 typedef return_t (*recurse_func_t) (hb_ot_apply_context_t *c, unsigned int lookup_index);
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100541 template <typename T>
Behdad Esfahbodc14efb82019-05-05 09:54:58 -0700542 return_t dispatch (const T &obj) { return obj.apply (this); }
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330543 static return_t default_return_value () { return false; }
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100544 bool stop_sublookup_iteration (return_t r) const { return r; }
Behdad Esfahbod12757b62018-01-26 18:14:05 -0800545 return_t recurse (unsigned int sub_lookup_index)
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100546 {
Behdad Esfahbodbaf77792017-11-14 21:53:48 -0800547 if (unlikely (nesting_level_left == 0 || !recurse_func || buffer->max_ops-- <= 0))
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100548 return default_return_value ();
549
550 nesting_level_left--;
Behdad Esfahbod12757b62018-01-26 18:14:05 -0800551 bool ret = recurse_func (this, sub_lookup_index);
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100552 nesting_level_left++;
553 return ret;
554 }
555
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100556 skipping_iterator_t iter_input, iter_context;
557
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100558 hb_font_t *font;
559 hb_face_t *face;
560 hb_buffer_t *buffer;
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100561 recurse_func_t recurse_func;
562 const GDEF &gdef;
563 const VariationStore &var_store;
564
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100565 hb_direction_t direction;
566 hb_mask_t lookup_mask;
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100567 unsigned int table_index; /* GSUB/GPOS */
Behdad Esfahbod2c8b3b22015-08-18 14:36:43 +0100568 unsigned int lookup_index;
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100569 unsigned int lookup_props;
570 unsigned int nesting_level_left;
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100571
Behdad Esfahbod80de4bc2018-09-10 16:24:52 +0200572 bool has_glyph_classes;
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100573 bool auto_zwnj;
574 bool auto_zwj;
David Corbettc2a75e02018-01-25 14:22:03 -0500575 bool random;
Behdad Esfahbod80de4bc2018-09-10 16:24:52 +0200576
Behdad Esfahbodcfdea882018-09-11 10:57:48 +0200577 uint32_t random_state;
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100578
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100579
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800580 hb_ot_apply_context_t (unsigned int table_index_,
Ebrahim Byagowid0e2add2020-07-18 22:14:52 +0430581 hb_font_t *font_,
582 hb_buffer_t *buffer_) :
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100583 iter_input (), iter_context (),
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100584 font (font_), face (font->face), buffer (buffer_),
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200585 recurse_func (nullptr),
Behdad Esfahbod7dcf8e12019-06-26 13:44:10 -0700586 gdef (
587#ifndef HB_NO_OT_LAYOUT
588 *face->table.GDEF->table
589#else
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +0430590 Null (GDEF)
Behdad Esfahbod7dcf8e12019-06-26 13:44:10 -0700591#endif
592 ),
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100593 var_store (gdef.get_var_store ()),
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100594 direction (buffer_->props.direction),
595 lookup_mask (1),
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100596 table_index (table_index_),
Behdad Esfahbod2c8b3b22015-08-18 14:36:43 +0100597 lookup_index ((unsigned int) -1),
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100598 lookup_props (0),
599 nesting_level_left (HB_MAX_NESTING_LEVEL),
Behdad Esfahbod80de4bc2018-09-10 16:24:52 +0200600 has_glyph_classes (gdef.has_glyph_classes ()),
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100601 auto_zwnj (true),
602 auto_zwj (true),
David Corbettc2a75e02018-01-25 14:22:03 -0500603 random (false),
Behdad Esfahbodd748dc72018-09-24 18:30:50 -0400604 random_state (1) { init_iters (); }
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100605
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330606 void init_iters ()
Behdad Esfahbod365576d2015-01-29 13:59:42 +0100607 {
Behdad Esfahbod365576d2015-01-29 13:59:42 +0100608 iter_input.init (this, false);
609 iter_context.init (this, true);
610 }
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100611
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330612 void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; init_iters (); }
613 void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; init_iters (); }
614 void set_auto_zwnj (bool auto_zwnj_) { auto_zwnj = auto_zwnj_; init_iters (); }
615 void set_random (bool random_) { random = random_; }
616 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
617 void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; }
618 void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; init_iters (); }
Behdad Esfahbod9516cbd2018-09-23 22:00:34 -0400619
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330620 uint32_t random_number ()
Behdad Esfahbod08260c72018-09-11 10:51:19 +0200621 {
Behdad Esfahbodcfdea882018-09-11 10:57:48 +0200622 /* http://www.cplusplus.com/reference/random/minstd_rand/ */
623 random_state = random_state * 48271 % 2147483647;
624 return random_state;
Behdad Esfahbod08260c72018-09-11 10:51:19 +0200625 }
626
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330627 bool match_properties_mark (hb_codepoint_t glyph,
628 unsigned int glyph_props,
629 unsigned int match_props) const
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400630 {
631 /* If using mark filtering sets, the high short of
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700632 * match_props has the set index.
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400633 */
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700634 if (match_props & LookupFlag::UseMarkFilteringSet)
635 return gdef.mark_set_covers (match_props >> 16, glyph);
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400636
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700637 /* The second byte of match_props has the meaning
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400638 * "ignore marks of attachment type different than
639 * the attachment type specified."
640 */
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700641 if (match_props & LookupFlag::MarkAttachmentType)
642 return (match_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400643
644 return true;
645 }
646
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330647 bool check_glyph_property (const hb_glyph_info_t *info,
648 unsigned int match_props) const
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400649 {
Behdad Esfahbodb98c5db2014-07-16 13:44:01 -0400650 hb_codepoint_t glyph = info->codepoint;
651 unsigned int glyph_props = _hb_glyph_info_get_glyph_props (info);
652
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400653 /* Not covered, if, for example, glyph class is ligature and
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700654 * match_props includes LookupFlags::IgnoreLigatures
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400655 */
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700656 if (glyph_props & match_props & LookupFlag::IgnoreFlags)
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400657 return false;
658
Behdad Esfahbod5a08ecf2012-11-16 13:34:29 -0800659 if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK))
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700660 return match_properties_mark (glyph, glyph_props, match_props);
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400661
662 return true;
663 }
664
Ebrahim Byagowi9748ae72020-08-11 17:52:48 +0430665 void _set_glyph_props (hb_codepoint_t glyph_index,
666 unsigned int class_guess = 0,
667 bool ligature = false,
668 bool component = false) const
Behdad Esfahbod60da7632012-07-16 16:13:32 -0400669 {
Ebrahim Byagowi9748ae72020-08-11 17:52:48 +0430670 unsigned int add_in = _hb_glyph_info_get_glyph_props (&buffer->cur()) &
671 HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE;
672 add_in |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED;
Behdad Esfahbod09675a82013-10-18 01:05:58 +0200673 if (ligature)
Behdad Esfahbod832a6f92014-06-04 16:57:42 -0400674 {
Ebrahim Byagowi9748ae72020-08-11 17:52:48 +0430675 add_in |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED;
Behdad Esfahbod832a6f92014-06-04 16:57:42 -0400676 /* In the only place that the MULTIPLIED bit is used, Uniscribe
677 * seems to only care about the "last" transformation between
Bruce Mitchener257d0e52018-10-19 22:49:21 +0700678 * Ligature and Multiple substitutions. Ie. if you ligate, expand,
Behdad Esfahbod832a6f92014-06-04 16:57:42 -0400679 * and ligate again, it forgives the multiplication and acts as
680 * if only ligation happened. As such, clear MULTIPLIED bit.
681 */
Ebrahim Byagowi9748ae72020-08-11 17:52:48 +0430682 add_in &= ~HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
Behdad Esfahbod832a6f92014-06-04 16:57:42 -0400683 }
684 if (component)
Ebrahim Byagowi9748ae72020-08-11 17:52:48 +0430685 add_in |= HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
Behdad Esfahbod2fca1422012-07-30 18:46:41 -0400686 if (likely (has_glyph_classes))
Ebrahim Byagowi9748ae72020-08-11 17:52:48 +0430687 _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | gdef.get_glyph_props (glyph_index));
Behdad Esfahbod05bd1b62012-07-30 19:30:01 -0400688 else if (class_guess)
Ebrahim Byagowi9748ae72020-08-11 17:52:48 +0430689 _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | class_guess);
Behdad Esfahbod60da7632012-07-16 16:13:32 -0400690 }
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500691
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330692 void replace_glyph (hb_codepoint_t glyph_index) const
Behdad Esfahbod3ec77d62012-06-08 21:44:06 -0400693 {
Ebrahim Byagowi9748ae72020-08-11 17:52:48 +0430694 _set_glyph_props (glyph_index);
Behdad Esfahbod3f1998a2021-03-15 13:33:44 -0600695 (void) buffer->replace_glyph (glyph_index);
Behdad Esfahbod98370e82010-10-27 17:39:01 -0400696 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330697 void replace_glyph_inplace (hb_codepoint_t glyph_index) const
Behdad Esfahbod7fbbf862012-07-30 18:36:42 -0400698 {
Ebrahim Byagowi9748ae72020-08-11 17:52:48 +0430699 _set_glyph_props (glyph_index);
Behdad Esfahbod7fbbf862012-07-30 18:36:42 -0400700 buffer->cur().codepoint = glyph_index;
701 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330702 void replace_glyph_with_ligature (hb_codepoint_t glyph_index,
Behdad Esfahbodf4cd99f2020-04-22 14:45:57 -0700703 unsigned int class_guess) const
Behdad Esfahboda0161742013-10-18 00:06:30 +0200704 {
Ebrahim Byagowi9748ae72020-08-11 17:52:48 +0430705 _set_glyph_props (glyph_index, class_guess, true);
Behdad Esfahbod3f1998a2021-03-15 13:33:44 -0600706 (void) buffer->replace_glyph (glyph_index);
Behdad Esfahboda0161742013-10-18 00:06:30 +0200707 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330708 void output_glyph_for_component (hb_codepoint_t glyph_index,
Behdad Esfahbodf4cd99f2020-04-22 14:45:57 -0700709 unsigned int class_guess) const
Behdad Esfahboda0161742013-10-18 00:06:30 +0200710 {
Ebrahim Byagowi9748ae72020-08-11 17:52:48 +0430711 _set_glyph_props (glyph_index, class_guess, false, true);
Behdad Esfahbod34a12042021-03-15 14:39:06 -0600712 (void) buffer->output_glyph (glyph_index);
Behdad Esfahboda0161742013-10-18 00:06:30 +0200713 }
Behdad Esfahbod1376fb72010-04-29 02:19:21 -0400714};
715
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -0400716
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400717struct hb_get_subtables_context_t :
Behdad Esfahbod25aec022020-06-18 16:58:01 -0700718 hb_dispatch_context_t<hb_get_subtables_context_t>
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400719{
720 template <typename Type>
Behdad Esfahboda061e472019-12-10 13:31:50 -0600721 static inline bool apply_to (const void *obj, OT::hb_ot_apply_context_t *c)
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400722 {
723 const Type *typed_obj = (const Type *) obj;
724 return typed_obj->apply (c);
725 }
726
727 typedef bool (*hb_apply_func_t) (const void *obj, OT::hb_ot_apply_context_t *c);
728
729 struct hb_applicable_t
730 {
731 template <typename T>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330732 void init (const T &obj_, hb_apply_func_t apply_func_)
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400733 {
734 obj = &obj_;
735 apply_func = apply_func_;
736 digest.init ();
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -0700737 obj_.get_coverage ().collect_coverage (&digest);
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400738 }
739
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330740 bool apply (OT::hb_ot_apply_context_t *c) const
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400741 {
742 return digest.may_have (c->buffer->cur().codepoint) && apply_func (obj, c);
743 }
744
745 private:
746 const void *obj;
747 hb_apply_func_t apply_func;
748 hb_set_digest_t digest;
749 };
750
Behdad Esfahbodfa333e32018-12-27 17:56:22 -0500751 typedef hb_vector_t<hb_applicable_t> array_t;
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400752
753 /* Dispatch interface. */
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400754 template <typename T>
Behdad Esfahbodc14efb82019-05-05 09:54:58 -0700755 return_t dispatch (const T &obj)
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400756 {
757 hb_applicable_t *entry = array.push();
758 entry->init (obj, apply_to<T>);
Behdad Esfahbod7df3ecf2019-05-10 20:43:26 -0700759 return hb_empty_t ();
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400760 }
Behdad Esfahbod7df3ecf2019-05-10 20:43:26 -0700761 static return_t default_return_value () { return hb_empty_t (); }
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400762
763 hb_get_subtables_context_t (array_t &array_) :
Behdad Esfahbod15354402020-06-19 08:30:59 -0700764 array (array_) {}
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400765
766 array_t &array;
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400767};
768
769
770
Behdad Esfahbod94a23aa2010-05-05 01:13:09 -0400771
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700772typedef bool (*intersects_func_t) (const hb_set_t *glyphs, const HBUINT16 &value, const void *data);
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100773typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const HBUINT16 &value, const void *data);
774typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -0400775
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400776struct ContextClosureFuncs
777{
778 intersects_func_t intersects;
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400779};
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500780struct ContextCollectGlyphsFuncs
781{
782 collect_glyphs_func_t collect;
783};
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400784struct ContextApplyFuncs
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400785{
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -0400786 match_func_t match;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -0400787};
788
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500789
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700790static inline bool intersects_glyph (const hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400791{
792 return glyphs->has (value);
793}
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700794static inline bool intersects_class (const hb_set_t *glyphs, const HBUINT16 &value, const void *data)
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400795{
796 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
797 return class_def.intersects_class (glyphs, value);
798}
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700799static inline bool intersects_coverage (const hb_set_t *glyphs, const HBUINT16 &value, const void *data)
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400800{
801 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
802 return (data+coverage).intersects (glyphs);
803}
804
Qunxin Liu44d88cf2020-05-08 15:33:34 -0700805static inline bool array_is_subset_of (const hb_set_t *glyphs,
806 unsigned int count,
807 const HBUINT16 values[],
808 intersects_func_t intersects_func,
809 const void *intersects_data)
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400810{
Garret Rieger95ab1102019-10-21 13:15:46 -0700811 for (const HBUINT16 &_ : + hb_iter (values, count))
Qunxin Liu44d88cf2020-05-08 15:33:34 -0700812 if (!intersects_func (glyphs, _, intersects_data)) return false;
813 return true;
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400814}
815
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -0400816
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100817static inline void collect_glyph (hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500818{
819 glyphs->add (value);
820}
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100821static inline void collect_class (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500822{
823 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
Behdad Esfahbod89ad3c62020-04-23 10:57:30 -0700824 class_def.collect_class (glyphs, value);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500825}
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100826static inline void collect_coverage (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500827{
828 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -0700829 (data+coverage).collect_coverage (glyphs);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500830}
Behdad Esfahbod0beb66e2012-12-05 18:46:04 -0500831static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -0500832 hb_set_t *glyphs,
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500833 unsigned int count,
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100834 const HBUINT16 values[],
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500835 collect_glyphs_func_t collect_func,
836 const void *collect_data)
837{
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -0700838 return
839 + hb_iter (values, count)
840 | hb_apply ([&] (const HBUINT16 &_) { collect_func (glyphs, _, collect_data); })
841 ;
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500842}
843
844
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100845static inline bool match_glyph (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data HB_UNUSED)
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400846{
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -0400847 return glyph_id == value;
848}
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100849static inline bool match_class (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data)
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400850{
Behdad Esfahbod2b5a59c2009-08-04 11:38:50 -0400851 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -0400852 return class_def.get_class (glyph_id) == value;
853}
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100854static inline bool match_coverage (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data)
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400855{
Behdad Esfahbod6b54c5d2009-05-18 18:30:25 -0400856 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400857 return (data+coverage).get_coverage (glyph_id) != NOT_COVERED;
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -0400858}
859
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400860static inline bool would_match_input (hb_would_apply_context_t *c,
861 unsigned int count, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100862 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400863 match_func_t match_func,
864 const void *match_data)
865{
866 if (count != c->len)
867 return false;
868
869 for (unsigned int i = 1; i < count; i++)
Behdad Esfahbod472f2292012-08-07 22:25:24 -0400870 if (likely (!match_func (c->glyphs[i], input[i - 1], match_data)))
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400871 return false;
872
873 return true;
874}
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800875static inline bool match_input (hb_ot_apply_context_t *c,
Behdad Esfahbode072c242009-05-18 03:47:31 -0400876 unsigned int count, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100877 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -0400878 match_func_t match_func,
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -0400879 const void *match_data,
Behdad Esfahbod6cc136f2013-10-17 13:55:48 +0200880 unsigned int *end_offset,
Behdad Esfahbod5ba45042015-11-02 15:43:08 -0800881 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200882 unsigned int *p_total_component_count = nullptr)
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -0400883{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200884 TRACE_APPLY (nullptr);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400885
Behdad Esfahbod5ba45042015-11-02 15:43:08 -0800886 if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return_trace (false);
Behdad Esfahbod6b65a762013-10-14 18:51:39 +0200887
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200888 hb_buffer_t *buffer = c->buffer;
889
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800890 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
Behdad Esfahbodb051be52015-01-29 13:40:39 +0100891 skippy_iter.reset (buffer->idx, count - 1);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500892 skippy_iter.set_match_func (match_func, match_data, input);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400893
Behdad Esfahbod191fa882012-08-28 22:58:55 -0400894 /*
895 * This is perhaps the trickiest part of OpenType... Remarks:
896 *
897 * - If all components of the ligature were marks, we call this a mark ligature.
898 *
899 * - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize
900 * it as a ligature glyph.
901 *
902 * - Ligatures cannot be formed across glyphs attached to different components
903 * of previous ligatures. Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and
904 * LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother.
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200905 * However, it would be wrong to ligate that SHADDA,FATHA sequence.
906 * There are a couple of exceptions to this:
907 *
908 * o If a ligature tries ligating with marks that belong to it itself, go ahead,
909 * assuming that the font designer knows what they are doing (otherwise it can
910 * break Indic stuff when a matra wants to ligate with a conjunct,
911 *
912 * o If two marks want to ligate and they belong to different components of the
913 * same ligature glyph, and said ligature glyph is to be ignored according to
914 * mark-filtering rules, then allow.
ebraminio7c6937e2017-11-20 14:49:22 -0500915 * https://github.com/harfbuzz/harfbuzz/issues/545
Behdad Esfahbod191fa882012-08-28 22:58:55 -0400916 */
917
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400918 unsigned int total_component_count = 0;
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200919 total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur());
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400920
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200921 unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
922 unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -0400923
Behdad Esfahbod621c49c2017-10-04 15:06:48 +0200924 enum {
925 LIGBASE_NOT_CHECKED,
926 LIGBASE_MAY_NOT_SKIP,
927 LIGBASE_MAY_SKIP
928 } ligbase = LIGBASE_NOT_CHECKED;
929
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200930 match_positions[0] = buffer->idx;
Behdad Esfahbod370f03e2012-01-16 17:03:55 -0500931 for (unsigned int i = 1; i < count; i++)
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400932 {
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100933 if (!skippy_iter.next ()) return_trace (false);
Behdad Esfahbod6cc136f2013-10-17 13:55:48 +0200934
935 match_positions[i] = skippy_iter.idx;
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400936
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200937 unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]);
938 unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400939
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200940 if (first_lig_id && first_lig_comp)
941 {
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400942 /* If first component was attached to a previous ligature component,
943 * all subsequent components should be attached to the same ligature
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200944 * component, otherwise we shouldn't ligate them... */
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400945 if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200946 {
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330947 /* ...unless, we are attached to a base ligature and that base
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200948 * ligature is ignorable. */
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330949 if (ligbase == LIGBASE_NOT_CHECKED)
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200950 {
Behdad Esfahbod621c49c2017-10-04 15:06:48 +0200951 bool found = false;
Behdad Esfahbod4d677432019-05-10 16:35:31 -0700952 const auto *out = buffer->out_info;
Behdad Esfahbod621c49c2017-10-04 15:06:48 +0200953 unsigned int j = buffer->out_len;
954 while (j && _hb_glyph_info_get_lig_id (&out[j - 1]) == first_lig_id)
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200955 {
Behdad Esfahbod621c49c2017-10-04 15:06:48 +0200956 if (_hb_glyph_info_get_lig_comp (&out[j - 1]) == 0)
957 {
958 j--;
959 found = true;
960 break;
961 }
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200962 j--;
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200963 }
Behdad Esfahbod621c49c2017-10-04 15:06:48 +0200964
Behdad Esfahbod12757b62018-01-26 18:14:05 -0800965 if (found && skippy_iter.may_skip (out[j]) == hb_ot_apply_context_t::matcher_t::SKIP_YES)
Behdad Esfahbod621c49c2017-10-04 15:06:48 +0200966 ligbase = LIGBASE_MAY_SKIP;
967 else
968 ligbase = LIGBASE_MAY_NOT_SKIP;
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200969 }
970
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330971 if (ligbase == LIGBASE_MAY_NOT_SKIP)
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200972 return_trace (false);
973 }
974 }
975 else
Behdad Esfahbod621c49c2017-10-04 15:06:48 +0200976 {
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400977 /* If first component was NOT attached to a previous ligature component,
978 * all subsequent components should also NOT be attached to any ligature
979 * component, unless they are attached to the first component itself! */
980 if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id))
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100981 return_trace (false);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400982 }
983
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200984 total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -0400985 }
986
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200987 *end_offset = skippy_iter.idx - buffer->idx + 1;
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400988
Behdad Esfahbod191fa882012-08-28 22:58:55 -0400989 if (p_total_component_count)
990 *p_total_component_count = total_component_count;
991
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100992 return_trace (true);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400993}
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800994static inline bool ligate_input (hb_ot_apply_context_t *c,
Behdad Esfahbode714fe62013-10-17 13:49:51 +0200995 unsigned int count, /* Including the first glyph */
Bruce Mitchener5a24ea12018-10-20 08:09:52 +0700996 const unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
Behdad Esfahbode714fe62013-10-17 13:49:51 +0200997 unsigned int match_length,
Behdad Esfahboda177d022012-08-28 23:18:22 -0400998 hb_codepoint_t lig_glyph,
Behdad Esfahboda177d022012-08-28 23:18:22 -0400999 unsigned int total_component_count)
1000{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001001 TRACE_APPLY (nullptr);
Behdad Esfahbode714fe62013-10-17 13:49:51 +02001002
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +02001003 hb_buffer_t *buffer = c->buffer;
1004
1005 buffer->merge_clusters (buffer->idx, buffer->idx + match_length);
Behdad Esfahbod607feb72013-02-14 07:43:13 -05001006
Behdad Esfahbod9efddb92018-10-02 16:05:26 +02001007 /* - If a base and one or more marks ligate, consider that as a base, NOT
1008 * ligature, such that all following marks can still attach to it.
1009 * https://github.com/harfbuzz/harfbuzz/issues/1109
1010 *
1011 * - If all components of the ligature were marks, we call this a mark ligature.
Behdad Esfahbod3cca9782018-10-02 15:02:16 +02001012 * If it *is* a mark ligature, we don't allocate a new ligature id, and leave
Behdad Esfahboda177d022012-08-28 23:18:22 -04001013 * the ligature to keep its old ligature id. This will allow it to attach to
1014 * a base ligature in GPOS. Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH,
Behdad Esfahbod3cca9782018-10-02 15:02:16 +02001015 * and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA with a
Behdad Esfahboda177d022012-08-28 23:18:22 -04001016 * ligature id and component value of 2. Then if SHADDA,FATHA form a ligature
1017 * later, we don't want them to lose their ligature id/component, otherwise
1018 * GPOS will fail to correctly position the mark ligature on top of the
1019 * LAM,LAM,HEH ligature. See:
1020 * https://bugzilla.gnome.org/show_bug.cgi?id=676343
1021 *
1022 * - If a ligature is formed of components that some of which are also ligatures
1023 * themselves, and those ligature components had marks attached to *their*
1024 * components, we have to attach the marks to the new ligature component
1025 * positions! Now *that*'s tricky! And these marks may be following the
1026 * last component of the whole sequence, so we should loop forward looking
1027 * for them and update them.
1028 *
1029 * Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a
1030 * 'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature
1031 * id and component == 1. Now, during 'liga', the LAM and the LAM-HEH ligature
1032 * form a LAM-LAM-HEH ligature. We need to reassign the SHADDA and FATHA to
1033 * the new ligature with a component value of 2.
1034 *
1035 * This in fact happened to a font... See:
1036 * https://bugzilla.gnome.org/show_bug.cgi?id=437633
1037 */
1038
Behdad Esfahbod9efddb92018-10-02 16:05:26 +02001039 bool is_base_ligature = _hb_glyph_info_is_base_glyph (&buffer->info[match_positions[0]]);
1040 bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->info[match_positions[0]]);
1041 for (unsigned int i = 1; i < count; i++)
Behdad Esfahbod3cca9782018-10-02 15:02:16 +02001042 if (!_hb_glyph_info_is_mark (&buffer->info[match_positions[i]]))
1043 {
Behdad Esfahbod9efddb92018-10-02 16:05:26 +02001044 is_base_ligature = false;
Behdad Esfahbod3cca9782018-10-02 15:02:16 +02001045 is_mark_ligature = false;
1046 break;
1047 }
Behdad Esfahbod9efddb92018-10-02 16:05:26 +02001048 bool is_ligature = !is_base_ligature && !is_mark_ligature;
Behdad Esfahbod3cca9782018-10-02 15:02:16 +02001049
Behdad Esfahbod9efddb92018-10-02 16:05:26 +02001050 unsigned int klass = is_ligature ? HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE : 0;
1051 unsigned int lig_id = is_ligature ? _hb_allocate_lig_id (buffer) : 0;
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +02001052 unsigned int last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
1053 unsigned int last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
Behdad Esfahboda177d022012-08-28 23:18:22 -04001054 unsigned int components_so_far = last_num_components;
1055
Behdad Esfahbod9efddb92018-10-02 16:05:26 +02001056 if (is_ligature)
Behdad Esfahbod7e08f122013-05-27 14:48:34 -04001057 {
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +02001058 _hb_glyph_info_set_lig_props_for_ligature (&buffer->cur(), lig_id, total_component_count);
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +02001059 if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
Behdad Esfahbod3d436d32013-10-28 21:00:37 +01001060 {
Behdad Esfahbod82596692015-11-02 17:44:05 -08001061 _hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER);
Behdad Esfahbod3d436d32013-10-28 21:00:37 +01001062 }
Behdad Esfahbod7e08f122013-05-27 14:48:34 -04001063 }
Behdad Esfahboda0161742013-10-18 00:06:30 +02001064 c->replace_glyph_with_ligature (lig_glyph, klass);
Behdad Esfahboda177d022012-08-28 23:18:22 -04001065
1066 for (unsigned int i = 1; i < count; i++)
1067 {
Behdad Esfahbod7185b272018-05-31 20:03:00 -07001068 while (buffer->idx < match_positions[i] && buffer->successful)
Behdad Esfahboda177d022012-08-28 23:18:22 -04001069 {
Behdad Esfahbod9efddb92018-10-02 16:05:26 +02001070 if (is_ligature)
1071 {
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03301072 unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
Behdad Esfahbod2f02fc72015-12-17 15:21:14 +00001073 if (this_comp == 0)
Behdad Esfahbod100fbea2015-12-17 15:23:09 +00001074 this_comp = last_num_components;
Behdad Esfahboda177d022012-08-28 23:18:22 -04001075 unsigned int new_lig_comp = components_so_far - last_num_components +
Behdad Esfahbod41248cc2019-05-07 20:54:31 -07001076 hb_min (this_comp, last_num_components);
Behdad Esfahbod2f02fc72015-12-17 15:21:14 +00001077 _hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
Behdad Esfahboda177d022012-08-28 23:18:22 -04001078 }
Behdad Esfahbod8450f432021-03-15 15:18:06 -06001079 (void) buffer->next_glyph ();
Behdad Esfahboda177d022012-08-28 23:18:22 -04001080 }
1081
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +02001082 last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
1083 last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
Behdad Esfahboda177d022012-08-28 23:18:22 -04001084 components_so_far += last_num_components;
1085
1086 /* Skip the base glyph */
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +02001087 buffer->idx++;
Behdad Esfahboda177d022012-08-28 23:18:22 -04001088 }
1089
Ebrahim Byagowicc977b62020-03-26 11:18:02 +04301090 if (!is_mark_ligature && last_lig_id)
1091 {
Behdad Esfahboda177d022012-08-28 23:18:22 -04001092 /* Re-adjust components for any marks following. */
Ebrahim Byagowicc977b62020-03-26 11:18:02 +04301093 for (unsigned i = buffer->idx; i < buffer->len; ++i)
1094 {
1095 if (last_lig_id != _hb_glyph_info_get_lig_id (&buffer->info[i])) break;
1096
1097 unsigned this_comp = _hb_glyph_info_get_lig_comp (&buffer->info[i]);
1098 if (!this_comp) break;
1099
1100 unsigned new_lig_comp = components_so_far - last_num_components +
1101 hb_min (this_comp, last_num_components);
1102 _hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
Behdad Esfahboda177d022012-08-28 23:18:22 -04001103 }
1104 }
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001105 return_trace (true);
Behdad Esfahboda177d022012-08-28 23:18:22 -04001106}
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001107
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001108static inline bool match_backtrack (hb_ot_apply_context_t *c,
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001109 unsigned int count,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001110 const HBUINT16 backtrack[],
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001111 match_func_t match_func,
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001112 const void *match_data,
1113 unsigned int *match_start)
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001114{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001115 TRACE_APPLY (nullptr);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -04001116
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001117 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
Behdad Esfahbodb051be52015-01-29 13:40:39 +01001118 skippy_iter.reset (c->buffer->backtrack_len (), count);
Behdad Esfahbod607feb72013-02-14 07:43:13 -05001119 skippy_iter.set_match_func (match_func, match_data, backtrack);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001120
Behdad Esfahbod4d3aeb82012-01-16 16:43:26 -05001121 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -05001122 if (!skippy_iter.prev ())
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001123 return_trace (false);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001124
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001125 *match_start = skippy_iter.idx;
1126
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001127 return_trace (true);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001128}
1129
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001130static inline bool match_lookahead (hb_ot_apply_context_t *c,
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001131 unsigned int count,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001132 const HBUINT16 lookahead[],
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001133 match_func_t match_func,
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04001134 const void *match_data,
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001135 unsigned int offset,
1136 unsigned int *end_index)
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001137{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001138 TRACE_APPLY (nullptr);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -04001139
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001140 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
Behdad Esfahbodb051be52015-01-29 13:40:39 +01001141 skippy_iter.reset (c->buffer->idx + offset - 1, count);
Behdad Esfahbod607feb72013-02-14 07:43:13 -05001142 skippy_iter.set_match_func (match_func, match_data, lookahead);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001143
Behdad Esfahbod370f03e2012-01-16 17:03:55 -05001144 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -05001145 if (!skippy_iter.next ())
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001146 return_trace (false);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001147
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001148 *end_index = skippy_iter.idx + 1;
1149
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001150 return_trace (true);
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001151}
1152
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04001153
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001154
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001155struct LookupRecord
1156{
Qunxin Liu0b39c482019-10-22 16:00:43 -07001157 LookupRecord* copy (hb_serialize_context_t *c,
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001158 const hb_map_t *lookup_map) const
Qunxin Liu0b39c482019-10-22 16:00:43 -07001159 {
1160 TRACE_SERIALIZE (this);
1161 auto *out = c->embed (*this);
1162 if (unlikely (!out)) return_trace (nullptr);
1163
1164 out->lookupListIndex = hb_map_get (lookup_map, lookupListIndex);
1165 return_trace (out);
1166 }
1167
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301168 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001169 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001170 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001171 return_trace (c->check_struct (this));
Behdad Esfahbodcd3827e2009-08-04 02:09:34 -04001172 }
1173
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001174 HBUINT16 sequenceIndex; /* Index into current glyph
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001175 * sequence--first glyph = 0 */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001176 HBUINT16 lookupListIndex; /* Lookup to apply to that
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001177 * position--zero--based */
Behdad Esfahbod569da922010-05-10 16:38:32 -04001178 public:
1179 DEFINE_SIZE_STATIC (4);
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001180};
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001181
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001182template <typename context_t>
1183static inline void recurse_lookups (context_t *c,
1184 unsigned int lookupCount,
1185 const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001186{
Qunxin Liub4fc5932020-12-09 10:44:18 -08001187 hb_set_t *chaos = hb_set_create ();
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001188 for (unsigned int i = 0; i < lookupCount; i++)
Behdad Esfahbod86522e42013-07-22 19:07:53 -04001189 c->recurse (lookupRecord[i].lookupListIndex);
Qunxin Liub4fc5932020-12-09 10:44:18 -08001190
1191 hb_set_destroy (chaos);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001192}
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04001193
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001194static inline bool apply_lookup (hb_ot_apply_context_t *c,
Behdad Esfahbode072c242009-05-18 03:47:31 -04001195 unsigned int count, /* Including the first glyph */
Behdad Esfahbod5ba45042015-11-02 15:43:08 -08001196 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
Behdad Esfahbode072c242009-05-18 03:47:31 -04001197 unsigned int lookupCount,
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001198 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
1199 unsigned int match_length)
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001200{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001201 TRACE_APPLY (nullptr);
Behdad Esfahbod902cc8a2012-11-23 15:06:59 -05001202
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001203 hb_buffer_t *buffer = c->buffer;
jfkthame44f7d6e2017-02-17 03:03:24 +00001204 int end;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001205
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001206 /* All positions are distance from beginning of *output* buffer.
1207 * Adjust. */
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001208 {
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001209 unsigned int bl = buffer->backtrack_len ();
1210 end = bl + match_length;
Behdad Esfahbod8751de52013-07-18 16:29:50 -04001211
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001212 int delta = bl - buffer->idx;
1213 /* Convert positions to new indexing. */
1214 for (unsigned int j = 0; j < count; j++)
1215 match_positions[j] += delta;
Behdad Esfahbod8820bb22013-02-14 07:41:03 -05001216 }
Behdad Esfahbode73a0c22009-05-18 04:15:25 -04001217
Behdad Esfahbod7185b272018-05-31 20:03:00 -07001218 for (unsigned int i = 0; i < lookupCount && buffer->successful; i++)
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001219 {
1220 unsigned int idx = lookupRecord[i].sequenceIndex;
1221 if (idx >= count)
1222 continue;
1223
Behdad Esfahbod9cc1ed42015-11-19 12:39:09 -08001224 /* Don't recurse to ourself at same position.
1225 * Note that this test is too naive, it doesn't catch longer loops. */
Behdad Esfahbod1da75af2021-02-10 00:03:30 -07001226 if (unlikely (idx == 0 && lookupRecord[i].lookupListIndex == c->lookup_index))
Behdad Esfahbod9cc1ed42015-11-19 12:39:09 -08001227 continue;
1228
Behdad Esfahbode5930722017-11-14 15:47:55 -08001229 if (unlikely (!buffer->move_to (match_positions[idx])))
1230 break;
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001231
Behdad Esfahbodbaf77792017-11-14 21:53:48 -08001232 if (unlikely (buffer->max_ops <= 0))
1233 break;
1234
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001235 unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
1236 if (!c->recurse (lookupRecord[i].lookupListIndex))
1237 continue;
1238
1239 unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len ();
1240 int delta = new_len - orig_len;
1241
1242 if (!delta)
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03301243 continue;
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001244
Behdad Esfahbod9ac9af72017-03-05 13:51:01 -08001245 /* Recursed lookup changed buffer len. Adjust.
1246 *
1247 * TODO:
1248 *
1249 * Right now, if buffer length increased by n, we assume n new glyphs
1250 * were added right after the current position, and if buffer length
1251 * was decreased by n, we assume n match positions after the current
1252 * one where removed. The former (buffer length increased) case is
1253 * fine, but the decrease case can be improved in at least two ways,
1254 * both of which are significant:
1255 *
1256 * - If recursed-to lookup is MultipleSubst and buffer length
1257 * decreased, then it's current match position that was deleted,
1258 * NOT the one after it.
1259 *
1260 * - If buffer length was decreased by n, it does not necessarily
1261 * mean that n match positions where removed, as there might
1262 * have been marks and default-ignorables in the sequence. We
1263 * should instead drop match positions between current-position
Behdad Esfahbod1da75af2021-02-10 00:03:30 -07001264 * and current-position + n instead. Though, am not sure which
1265 * one is better. Both cases have valid uses. Sigh.
Behdad Esfahbod9ac9af72017-03-05 13:51:01 -08001266 *
1267 * It should be possible to construct tests for both of these cases.
1268 */
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001269
jfkthame44f7d6e2017-02-17 03:03:24 +00001270 end += delta;
Behdad Esfahbod47e7a182017-03-10 13:23:02 -08001271 if (end <= int (match_positions[idx]))
Behdad Esfahbod359dead2016-05-06 16:19:19 +01001272 {
Behdad Esfahbod4b4a1b92016-12-21 23:10:43 -06001273 /* End might end up being smaller than match_positions[idx] if the recursed
Behdad Esfahbod47e7a182017-03-10 13:23:02 -08001274 * lookup ended up removing many items, more than we have had matched.
Behdad Esfahbod4b4a1b92016-12-21 23:10:43 -06001275 * Just never rewind end back and get out of here.
1276 * https://bugs.chromium.org/p/chromium/issues/detail?id=659496 */
1277 end = match_positions[idx];
Behdad Esfahbod47e7a182017-03-10 13:23:02 -08001278 /* There can't be any further changes. */
Behdad Esfahbod359dead2016-05-06 16:19:19 +01001279 break;
1280 }
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001281
1282 unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */
1283
1284 if (delta > 0)
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001285 {
Behdad Esfahbod5ba45042015-11-02 15:43:08 -08001286 if (unlikely (delta + count > HB_MAX_CONTEXT_LENGTH))
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001287 break;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001288 }
1289 else
1290 {
Behdad Esfahbod47e7a182017-03-10 13:23:02 -08001291 /* NOTE: delta is negative. */
Behdad Esfahbod41248cc2019-05-07 20:54:31 -07001292 delta = hb_max (delta, (int) next - (int) count);
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001293 next -= delta;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001294 }
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001295
1296 /* Shift! */
1297 memmove (match_positions + next + delta, match_positions + next,
1298 (count - next) * sizeof (match_positions[0]));
1299 next += delta;
1300 count += delta;
1301
1302 /* Fill in new entries. */
1303 for (unsigned int j = idx + 1; j < next; j++)
1304 match_positions[j] = match_positions[j - 1] + 1;
1305
1306 /* And fixup the rest. */
1307 for (; next < count; next++)
1308 match_positions[next] += delta;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001309 }
1310
Behdad Esfahbodcac6c862021-03-15 13:46:54 -06001311 (void) buffer->move_to (end);
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001312
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001313 return_trace (true);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001314}
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001315
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04001316
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001317
1318/* Contextual lookups */
1319
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001320struct ContextClosureLookupContext
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001321{
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001322 ContextClosureFuncs funcs;
1323 const void *intersects_data;
1324};
1325
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001326struct ContextCollectGlyphsLookupContext
1327{
1328 ContextCollectGlyphsFuncs funcs;
1329 const void *collect_data;
1330};
1331
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001332struct ContextApplyLookupContext
1333{
1334 ContextApplyFuncs funcs;
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04001335 const void *match_data;
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001336};
1337
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001338static inline bool context_intersects (const hb_set_t *glyphs,
1339 unsigned int inputCount, /* Including the first glyph (not matched) */
1340 const HBUINT16 input[], /* Array of input values--start with second glyph */
1341 ContextClosureLookupContext &lookup_context)
1342{
Qunxin Liu44d88cf2020-05-08 15:33:34 -07001343 return array_is_subset_of (glyphs,
1344 inputCount ? inputCount - 1 : 0, input,
1345 lookup_context.funcs.intersects, lookup_context.intersects_data);
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001346}
1347
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001348static inline void context_closure_lookup (hb_closure_context_t *c,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001349 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001350 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001351 unsigned int lookupCount,
1352 const LookupRecord lookupRecord[],
1353 ContextClosureLookupContext &lookup_context)
1354{
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001355 if (context_intersects (c->glyphs,
1356 inputCount, input,
1357 lookup_context))
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001358 recurse_lookups (c,
1359 lookupCount, lookupRecord);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001360}
1361
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001362static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
1363 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001364 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001365 unsigned int lookupCount,
1366 const LookupRecord lookupRecord[],
1367 ContextCollectGlyphsLookupContext &lookup_context)
1368{
Behdad Esfahbod83035932012-12-04 17:08:41 -05001369 collect_array (c, c->input,
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001370 inputCount ? inputCount - 1 : 0, input,
1371 lookup_context.funcs.collect, lookup_context.collect_data);
1372 recurse_lookups (c,
1373 lookupCount, lookupRecord);
1374}
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001375
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001376static inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
1377 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001378 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbod0beb66e2012-12-05 18:46:04 -05001379 unsigned int lookupCount HB_UNUSED,
1380 const LookupRecord lookupRecord[] HB_UNUSED,
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001381 ContextApplyLookupContext &lookup_context)
1382{
1383 return would_match_input (c,
1384 inputCount, input,
1385 lookup_context.funcs.match, lookup_context.match_data);
1386}
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001387static inline bool context_apply_lookup (hb_ot_apply_context_t *c,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001388 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001389 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001390 unsigned int lookupCount,
1391 const LookupRecord lookupRecord[],
1392 ContextApplyLookupContext &lookup_context)
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001393{
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001394 unsigned int match_length = 0;
Behdad Esfahbod5ba45042015-11-02 15:43:08 -08001395 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001396 return match_input (c,
Behdad Esfahbod41697102010-05-05 01:37:58 -04001397 inputCount, input,
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001398 lookup_context.funcs.match, lookup_context.match_data,
1399 &match_length, match_positions)
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001400 && (c->buffer->unsafe_to_break (c->buffer->idx, c->buffer->idx + match_length),
1401 apply_lookup (c,
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001402 inputCount, match_positions,
1403 lookupCount, lookupRecord,
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001404 match_length));
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001405}
1406
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001407struct Rule
1408{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301409 bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001410 {
1411 return context_intersects (glyphs,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001412 inputCount, inputZ.arrayZ,
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001413 lookup_context);
1414 }
1415
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301416 void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001417 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04301418 if (unlikely (c->lookup_limit_exceeded ())) return;
Garret Rieger014e0382020-03-31 16:29:29 -07001419
Ebrahim Byagowi92588782019-04-30 13:05:10 -07001420 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
Behdad Esfahbod0382b712018-11-02 12:23:26 -04001421 (inputZ.as_array ((inputCount ? inputCount - 1 : 0)));
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001422 context_closure_lookup (c,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001423 inputCount, inputZ.arrayZ,
1424 lookupCount, lookupRecord.arrayZ,
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001425 lookup_context);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001426 }
1427
Garret Rieger9fad5402020-09-28 13:24:25 -07001428 void closure_lookups (hb_closure_lookups_context_t *c,
1429 ContextClosureLookupContext &lookup_context) const
Qunxin Liu0b39c482019-10-22 16:00:43 -07001430 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04301431 if (unlikely (c->lookup_limit_exceeded ())) return;
Garret Rieger9fad5402020-09-28 13:24:25 -07001432 if (!intersects (c->glyphs, lookup_context)) return;
Garret Rieger014e0382020-03-31 16:29:29 -07001433
Qunxin Liu0b39c482019-10-22 16:00:43 -07001434 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
1435 (inputZ.as_array (inputCount ? inputCount - 1 : 0));
1436 recurse_lookups (c, lookupCount, lookupRecord.arrayZ);
1437 }
1438
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301439 void collect_glyphs (hb_collect_glyphs_context_t *c,
1440 ContextCollectGlyphsLookupContext &lookup_context) const
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001441 {
Ebrahim Byagowi92588782019-04-30 13:05:10 -07001442 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
Behdad Esfahbod0382b712018-11-02 12:23:26 -04001443 (inputZ.as_array (inputCount ? inputCount - 1 : 0));
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001444 context_collect_glyphs_lookup (c,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001445 inputCount, inputZ.arrayZ,
1446 lookupCount, lookupRecord.arrayZ,
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001447 lookup_context);
1448 }
1449
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301450 bool would_apply (hb_would_apply_context_t *c,
1451 ContextApplyLookupContext &lookup_context) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001452 {
Ebrahim Byagowi92588782019-04-30 13:05:10 -07001453 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
Behdad Esfahbod0382b712018-11-02 12:23:26 -04001454 (inputZ.as_array (inputCount ? inputCount - 1 : 0));
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07001455 return context_would_apply_lookup (c,
1456 inputCount, inputZ.arrayZ,
1457 lookupCount, lookupRecord.arrayZ,
1458 lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001459 }
1460
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301461 bool apply (hb_ot_apply_context_t *c,
1462 ContextApplyLookupContext &lookup_context) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001463 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001464 TRACE_APPLY (this);
Ebrahim Byagowi92588782019-04-30 13:05:10 -07001465 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
Behdad Esfahbod0382b712018-11-02 12:23:26 -04001466 (inputZ.as_array (inputCount ? inputCount - 1 : 0));
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001467 return_trace (context_apply_lookup (c, inputCount, inputZ.arrayZ, lookupCount, lookupRecord.arrayZ, lookup_context));
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001468 }
1469
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001470 bool serialize (hb_serialize_context_t *c,
1471 const hb_map_t *input_mapping, /* old->new glyphid or class mapping */
1472 const hb_map_t *lookup_map) const
1473 {
1474 TRACE_SERIALIZE (this);
1475 auto *out = c->start_embed (this);
1476 if (unlikely (!c->extend_min (out))) return_trace (false);
1477
1478 out->inputCount = inputCount;
1479 out->lookupCount = lookupCount;
1480
1481 const hb_array_t<const HBUINT16> input = inputZ.as_array (inputCount - 1);
1482 for (const auto org : input)
1483 {
1484 HBUINT16 d;
1485 d = input_mapping->get (org);
1486 c->copy (d);
1487 }
1488
1489 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
Ebrahim Byagowi5a7cc7f2020-07-29 08:33:32 +04301490 (inputZ.as_array ((inputCount ? inputCount - 1 : 0)));
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001491 for (unsigned i = 0; i < (unsigned) lookupCount; i++)
1492 c->copy (lookupRecord[i], lookup_map);
1493
1494 return_trace (true);
1495 }
1496
1497 bool subset (hb_subset_context_t *c,
1498 const hb_map_t *lookup_map,
1499 const hb_map_t *klass_map = nullptr) const
1500 {
1501 TRACE_SUBSET (this);
1502
1503 const hb_array_t<const HBUINT16> input = inputZ.as_array ((inputCount ? inputCount - 1 : 0));
1504 if (!input.length) return_trace (false);
1505
1506 const hb_map_t *mapping = klass_map == nullptr ? c->plan->glyph_map : klass_map;
1507 if (!hb_all (input, mapping)) return_trace (false);
1508 return_trace (serialize (c->serializer, mapping, lookup_map));
1509 }
1510
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001511 public:
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301512 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001513 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001514 TRACE_SANITIZE (this);
Behdad Esfahbod5aad8192017-11-03 17:16:26 -04001515 return_trace (inputCount.sanitize (c) &&
1516 lookupCount.sanitize (c) &&
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001517 c->check_range (inputZ.arrayZ,
Behdad Esfahbod9c6921c2018-11-30 15:16:57 -05001518 inputZ.item_size * (inputCount ? inputCount - 1 : 0) +
Behdad Esfahbod6d7c6e12018-02-07 14:09:56 -06001519 LookupRecord::static_size * lookupCount));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001520 }
1521
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001522 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001523 HBUINT16 inputCount; /* Total number of glyphs in input
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001524 * glyph sequence--includes the first
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001525 * glyph */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001526 HBUINT16 lookupCount; /* Number of LookupRecords */
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001527 UnsizedArrayOf<HBUINT16>
Ebrahim Byagowice114d62019-12-31 15:53:02 +03301528 inputZ; /* Array of match inputs--start with
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001529 * second glyph */
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001530/*UnsizedArrayOf<LookupRecord>
1531 lookupRecordX;*/ /* Array of LookupRecords--in
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001532 * design order */
Behdad Esfahbod569da922010-05-10 16:38:32 -04001533 public:
Behdad Esfahbod6d7c6e12018-02-07 14:09:56 -06001534 DEFINE_SIZE_ARRAY (4, inputZ);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001535};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001536
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001537struct RuleSet
1538{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301539 bool intersects (const hb_set_t *glyphs,
1540 ContextClosureLookupContext &lookup_context) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001541 {
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001542 return
1543 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07001544 | hb_map (hb_add (this))
1545 | hb_map ([&] (const Rule &_) { return _.intersects (glyphs, lookup_context); })
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001546 | hb_any
1547 ;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001548 }
1549
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301550 void closure (hb_closure_context_t *c,
1551 ContextClosureLookupContext &lookup_context) const
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001552 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04301553 if (unlikely (c->lookup_limit_exceeded ())) return;
Garret Rieger014e0382020-03-31 16:29:29 -07001554
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001555 return
1556 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07001557 | hb_map (hb_add (this))
1558 | hb_apply ([&] (const Rule &_) { _.closure (c, lookup_context); })
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001559 ;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001560 }
1561
Garret Rieger9fad5402020-09-28 13:24:25 -07001562 void closure_lookups (hb_closure_lookups_context_t *c,
1563 ContextClosureLookupContext &lookup_context) const
Qunxin Liu0b39c482019-10-22 16:00:43 -07001564 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04301565 if (unlikely (c->lookup_limit_exceeded ())) return;
Qunxin Liu0b39c482019-10-22 16:00:43 -07001566 + hb_iter (rule)
1567 | hb_map (hb_add (this))
Garret Riegere31c2692020-09-28 16:51:25 -07001568 | hb_apply ([&] (const Rule &_) { _.closure_lookups (c, lookup_context); })
Qunxin Liu0b39c482019-10-22 16:00:43 -07001569 ;
1570 }
1571
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301572 void collect_glyphs (hb_collect_glyphs_context_t *c,
1573 ContextCollectGlyphsLookupContext &lookup_context) const
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001574 {
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001575 return
1576 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07001577 | hb_map (hb_add (this))
1578 | hb_apply ([&] (const Rule &_) { _.collect_glyphs (c, lookup_context); })
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001579 ;
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001580 }
1581
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301582 bool would_apply (hb_would_apply_context_t *c,
1583 ContextApplyLookupContext &lookup_context) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001584 {
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001585 return
1586 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07001587 | hb_map (hb_add (this))
1588 | hb_map ([&] (const Rule &_) { return _.would_apply (c, lookup_context); })
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001589 | hb_any
1590 ;
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001591 }
1592
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301593 bool apply (hb_ot_apply_context_t *c,
1594 ContextApplyLookupContext &lookup_context) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001595 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001596 TRACE_APPLY (this);
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001597 return_trace (
1598 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07001599 | hb_map (hb_add (this))
1600 | hb_map ([&] (const Rule &_) { return _.apply (c, lookup_context); })
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001601 | hb_any
1602 )
1603 ;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001604 }
1605
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001606 bool subset (hb_subset_context_t *c,
1607 const hb_map_t *lookup_map,
1608 const hb_map_t *klass_map = nullptr) const
1609 {
1610 TRACE_SUBSET (this);
1611
1612 auto snap = c->serializer->snapshot ();
1613 auto *out = c->serializer->start_embed (*this);
1614 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
1615
1616 for (const OffsetTo<Rule>& _ : rule)
1617 {
1618 if (!_) continue;
1619 auto *o = out->rule.serialize_append (c->serializer);
1620 if (unlikely (!o)) continue;
1621
1622 auto o_snap = c->serializer->snapshot ();
1623 if (!o->serialize_subset (c, _, this, lookup_map, klass_map))
1624 {
Ebrahim Byagowi5a7cc7f2020-07-29 08:33:32 +04301625 out->rule.pop ();
1626 c->serializer->revert (o_snap);
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001627 }
1628 }
1629
1630 bool ret = bool (out->rule);
1631 if (!ret) c->serializer->revert (snap);
1632
1633 return_trace (ret);
1634 }
1635
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301636 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001637 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001638 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001639 return_trace (rule.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001640 }
1641
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001642 protected:
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001643 OffsetArrayOf<Rule>
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001644 rule; /* Array of Rule tables
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001645 * ordered by preference */
Behdad Esfahboded074222010-05-10 18:08:46 -04001646 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04001647 DEFINE_SIZE_ARRAY (2, rule);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001648};
1649
1650
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001651struct ContextFormat1
1652{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301653 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001654 {
1655 struct ContextClosureLookupContext lookup_context = {
1656 {intersects_glyph},
1657 nullptr
1658 };
Behdad Esfahbod05f21302019-03-29 22:40:13 -07001659
1660 return
1661 + hb_zip (this+coverage, ruleSet)
1662 | hb_filter (*glyphs, hb_first)
1663 | hb_map (hb_second)
Behdad Esfahbod23768672019-05-15 21:57:26 -07001664 | hb_map (hb_add (this))
1665 | hb_map ([&] (const RuleSet &_) { return _.intersects (glyphs, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07001666 | hb_any
1667 ;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001668 }
1669
Qunxin Liub4fc5932020-12-09 10:44:18 -08001670 bool may_have_non_1to1 () const
1671 { return true; }
1672
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301673 void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001674 {
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001675 struct ContextClosureLookupContext lookup_context = {
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001676 {intersects_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001677 nullptr
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001678 };
Behdad Esfahbod05f21302019-03-29 22:40:13 -07001679
1680 + hb_zip (this+coverage, ruleSet)
1681 | hb_filter (*c->glyphs, hb_first)
1682 | hb_map (hb_second)
Behdad Esfahbod23768672019-05-15 21:57:26 -07001683 | hb_map (hb_add (this))
1684 | hb_apply ([&] (const RuleSet &_) { _.closure (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07001685 ;
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001686 }
1687
Qunxin Liu0b39c482019-10-22 16:00:43 -07001688 void closure_lookups (hb_closure_lookups_context_t *c) const
1689 {
Garret Rieger9fad5402020-09-28 13:24:25 -07001690 struct ContextClosureLookupContext lookup_context = {
1691 {intersects_glyph},
1692 nullptr
1693 };
1694
1695 + hb_zip (this+coverage, ruleSet)
1696 | hb_filter (*c->glyphs, hb_first)
1697 | hb_map (hb_second)
Qunxin Liu0b39c482019-10-22 16:00:43 -07001698 | hb_map (hb_add (this))
Garret Riegere31c2692020-09-28 16:51:25 -07001699 | hb_apply ([&] (const RuleSet &_) { _.closure_lookups (c, lookup_context); })
Qunxin Liu0b39c482019-10-22 16:00:43 -07001700 ;
1701 }
1702
Qunxin Liu8200e482020-02-26 13:11:42 -08001703 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
1704
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301705 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001706 {
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07001707 (this+coverage).collect_coverage (c->input);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001708
1709 struct ContextCollectGlyphsLookupContext lookup_context = {
1710 {collect_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001711 nullptr
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001712 };
1713
Behdad Esfahbod05f21302019-03-29 22:40:13 -07001714 + hb_iter (ruleSet)
Behdad Esfahbod23768672019-05-15 21:57:26 -07001715 | hb_map (hb_add (this))
1716 | hb_apply ([&] (const RuleSet &_) { _.collect_glyphs (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07001717 ;
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001718 }
1719
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301720 bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001721 {
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05001722 const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001723 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001724 {match_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001725 nullptr
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001726 };
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07001727 return rule_set.would_apply (c, lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001728 }
1729
Ebrahim Byagowie4120082018-12-17 21:31:01 +03301730 const Coverage &get_coverage () const { return this+coverage; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001731
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301732 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001733 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001734 TRACE_APPLY (this);
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05001735 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -04001736 if (likely (index == NOT_COVERED))
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001737 return_trace (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04001738
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001739 const RuleSet &rule_set = this+ruleSet[index];
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001740 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001741 {match_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001742 nullptr
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001743 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001744 return_trace (rule_set.apply (c, lookup_context));
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001745 }
1746
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301747 bool subset (hb_subset_context_t *c) const
Behdad Esfahbod339d3602018-09-03 17:33:34 -07001748 {
1749 TRACE_SUBSET (this);
Garret Riegere5835052020-09-29 11:05:08 -07001750 const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001751 const hb_map_t &glyph_map = *c->plan->glyph_map;
1752
1753 auto *out = c->serializer->start_embed (*this);
1754 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
1755 out->format = format;
1756
1757 const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
1758 hb_sorted_vector_t<hb_codepoint_t> new_coverage;
1759 + hb_zip (this+coverage, ruleSet)
1760 | hb_filter (glyphset, hb_first)
1761 | hb_filter (subset_offset_array (c, out->ruleSet, this, lookup_map), hb_second)
1762 | hb_map (hb_first)
1763 | hb_map (glyph_map)
1764 | hb_sink (new_coverage)
1765 ;
1766
1767 out->coverage.serialize (c->serializer, out)
Ebrahim Byagowi5a7cc7f2020-07-29 08:33:32 +04301768 .serialize (c->serializer, new_coverage.iter ());
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001769 return_trace (bool (new_coverage));
Behdad Esfahbod339d3602018-09-03 17:33:34 -07001770 }
1771
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301772 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001773 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001774 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001775 return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001776 }
1777
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001778 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001779 HBUINT16 format; /* Format identifier--format = 1 */
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001780 OffsetTo<Coverage>
1781 coverage; /* Offset to Coverage table--from
1782 * beginning of table */
1783 OffsetArrayOf<RuleSet>
1784 ruleSet; /* Array of RuleSet tables
1785 * ordered by Coverage Index */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04001786 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04001787 DEFINE_SIZE_ARRAY (6, ruleSet);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001788};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001789
1790
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001791struct ContextFormat2
1792{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301793 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001794 {
1795 if (!(this+coverage).intersects (glyphs))
1796 return false;
1797
1798 const ClassDef &class_def = this+classDef;
1799
1800 struct ContextClosureLookupContext lookup_context = {
1801 {intersects_class},
1802 &class_def
1803 };
1804
Behdad Esfahbod668d2d52019-03-29 22:48:38 -07001805 return
Behdad Esfahbod26111a12020-06-28 02:59:47 -07001806 + hb_iter (ruleSet)
1807 | hb_map (hb_add (this))
1808 | hb_enumerate
1809 | hb_map ([&] (const hb_pair_t<unsigned, const RuleSet &> p)
Behdad Esfahbode5306922019-03-29 23:31:07 -07001810 { return class_def.intersects_class (glyphs, p.first) &&
Behdad Esfahbod26111a12020-06-28 02:59:47 -07001811 p.second.intersects (glyphs, lookup_context); })
Behdad Esfahbod668d2d52019-03-29 22:48:38 -07001812 | hb_any
1813 ;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001814 }
1815
Qunxin Liub4fc5932020-12-09 10:44:18 -08001816 bool may_have_non_1to1 () const
1817 { return true; }
1818
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301819 void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001820 {
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001821 if (!(this+coverage).intersects (c->glyphs))
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001822 return;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001823
1824 const ClassDef &class_def = this+classDef;
1825
1826 struct ContextClosureLookupContext lookup_context = {
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001827 {intersects_class},
Behdad Esfahbod11fba792013-01-02 23:36:37 -06001828 &class_def
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001829 };
1830
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07001831 return
1832 + hb_enumerate (ruleSet)
Behdad Esfahbod78d35f02019-05-15 18:15:05 -07001833 | hb_filter ([&] (unsigned _)
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07001834 { return class_def.intersects_class (c->glyphs, _); },
1835 hb_first)
1836 | hb_map (hb_second)
Behdad Esfahbod23768672019-05-15 21:57:26 -07001837 | hb_map (hb_add (this))
1838 | hb_apply ([&] (const RuleSet &_) { _.closure (c, lookup_context); })
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07001839 ;
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001840 }
1841
Qunxin Liu0b39c482019-10-22 16:00:43 -07001842 void closure_lookups (hb_closure_lookups_context_t *c) const
1843 {
Garret Rieger9fad5402020-09-28 13:24:25 -07001844 if (!(this+coverage).intersects (c->glyphs))
1845 return;
1846
1847 const ClassDef &class_def = this+classDef;
1848
1849 struct ContextClosureLookupContext lookup_context = {
1850 {intersects_class},
1851 &class_def
1852 };
1853
Qunxin Liu0b39c482019-10-22 16:00:43 -07001854 + hb_iter (ruleSet)
1855 | hb_map (hb_add (this))
Garret Rieger9fad5402020-09-28 13:24:25 -07001856 | hb_enumerate
1857 | hb_filter ([&] (const hb_pair_t<unsigned, const RuleSet &> p)
1858 { return class_def.intersects_class (c->glyphs, p.first); })
1859 | hb_map (hb_second)
1860 | hb_apply ([&] (const RuleSet & _)
1861 { _.closure_lookups (c, lookup_context); });
Qunxin Liu0b39c482019-10-22 16:00:43 -07001862 }
1863
Qunxin Liu8200e482020-02-26 13:11:42 -08001864 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
1865
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301866 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001867 {
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07001868 (this+coverage).collect_coverage (c->input);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001869
Behdad Esfahbod11fba792013-01-02 23:36:37 -06001870 const ClassDef &class_def = this+classDef;
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001871 struct ContextCollectGlyphsLookupContext lookup_context = {
1872 {collect_class},
Behdad Esfahbod11fba792013-01-02 23:36:37 -06001873 &class_def
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001874 };
1875
Behdad Esfahbod05f21302019-03-29 22:40:13 -07001876 + hb_iter (ruleSet)
Behdad Esfahbod23768672019-05-15 21:57:26 -07001877 | hb_map (hb_add (this))
1878 | hb_apply ([&] (const RuleSet &_) { _.collect_glyphs (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07001879 ;
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001880 }
1881
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301882 bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001883 {
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001884 const ClassDef &class_def = this+classDef;
Behdad Esfahbod2dc11412012-11-24 19:16:34 -05001885 unsigned int index = class_def.get_class (c->glyphs[0]);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001886 const RuleSet &rule_set = this+ruleSet[index];
1887 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001888 {match_class},
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001889 &class_def
1890 };
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07001891 return rule_set.would_apply (c, lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001892 }
1893
Ebrahim Byagowie4120082018-12-17 21:31:01 +03301894 const Coverage &get_coverage () const { return this+coverage; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001895
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301896 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001897 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001898 TRACE_APPLY (this);
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05001899 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001900 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04001901
1902 const ClassDef &class_def = this+classDef;
Behdad Esfahbod2dc11412012-11-24 19:16:34 -05001903 index = class_def.get_class (c->buffer->cur().codepoint);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001904 const RuleSet &rule_set = this+ruleSet[index];
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001905 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001906 {match_class},
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04001907 &class_def
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001908 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001909 return_trace (rule_set.apply (c, lookup_context));
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001910 }
1911
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301912 bool subset (hb_subset_context_t *c) const
Behdad Esfahbod339d3602018-09-03 17:33:34 -07001913 {
1914 TRACE_SUBSET (this);
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001915 auto *out = c->serializer->start_embed (*this);
1916 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
1917 out->format = format;
1918 if (unlikely (!out->coverage.serialize_subset (c, coverage, this)))
1919 return_trace (false);
1920
1921 hb_map_t klass_map;
1922 out->classDef.serialize_subset (c, classDef, this, &klass_map);
1923
1924 const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
1925 bool ret = true;
Garret Rieger8c3d4de2020-09-09 12:38:34 -07001926 int non_zero_index = 0, index = 0;
Behdad Esfahbod6d941942021-02-19 17:08:10 -07001927 for (const auto& _ : + hb_enumerate (ruleSet)
1928 | hb_filter (klass_map, hb_first))
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001929 {
1930 auto *o = out->ruleSet.serialize_append (c->serializer);
1931 if (unlikely (!o))
1932 {
Ebrahim Byagowi5a7cc7f2020-07-29 08:33:32 +04301933 ret = false;
1934 break;
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001935 }
1936
1937 if (o->serialize_subset (c, _.second, this, lookup_map, &klass_map))
Ebrahim Byagowi5a7cc7f2020-07-29 08:33:32 +04301938 non_zero_index = index;
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001939
1940 index++;
1941 }
1942
1943 if (!ret) return_trace (ret);
1944
1945 //prune empty trailing ruleSets
1946 --index;
1947 while (index > non_zero_index)
1948 {
1949 out->ruleSet.pop ();
1950 index--;
1951 }
1952
1953 return_trace (bool (out->ruleSet));
Behdad Esfahbod339d3602018-09-03 17:33:34 -07001954 }
1955
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301956 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001957 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001958 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001959 return_trace (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001960 }
1961
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001962 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001963 HBUINT16 format; /* Format identifier--format = 2 */
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001964 OffsetTo<Coverage>
1965 coverage; /* Offset to Coverage table--from
1966 * beginning of table */
1967 OffsetTo<ClassDef>
1968 classDef; /* Offset to glyph ClassDef table--from
1969 * beginning of table */
1970 OffsetArrayOf<RuleSet>
1971 ruleSet; /* Array of RuleSet tables
1972 * ordered by class */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04001973 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04001974 DEFINE_SIZE_ARRAY (8, ruleSet);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001975};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001976
1977
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001978struct ContextFormat3
1979{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301980 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001981 {
Behdad Esfahbodfb059082018-11-30 20:45:40 -05001982 if (!(this+coverageZ[0]).intersects (glyphs))
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001983 return false;
1984
1985 struct ContextClosureLookupContext lookup_context = {
1986 {intersects_coverage},
1987 this
1988 };
1989 return context_intersects (glyphs,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001990 glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001991 lookup_context);
1992 }
1993
Qunxin Liub4fc5932020-12-09 10:44:18 -08001994 bool may_have_non_1to1 () const
1995 { return true; }
1996
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301997 void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001998 {
Behdad Esfahbodfb059082018-11-30 20:45:40 -05001999 if (!(this+coverageZ[0]).intersects (c->glyphs))
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002000 return;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002001
Behdad Esfahbod0382b712018-11-02 12:23:26 -04002002 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002003 struct ContextClosureLookupContext lookup_context = {
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002004 {intersects_coverage},
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002005 this
2006 };
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002007 context_closure_lookup (c,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02002008 glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002009 lookupCount, lookupRecord,
2010 lookup_context);
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002011 }
2012
Qunxin Liu0b39c482019-10-22 16:00:43 -07002013 void closure_lookups (hb_closure_lookups_context_t *c) const
2014 {
Garret Riegera5c0ec72020-09-25 14:57:20 -07002015 if (!intersects (c->glyphs))
2016 return;
Qunxin Liu0b39c482019-10-22 16:00:43 -07002017 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
2018 recurse_lookups (c, lookupCount, lookupRecord);
2019 }
2020
Qunxin Liu8200e482020-02-26 13:11:42 -08002021 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
2022
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302023 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002024 {
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07002025 (this+coverageZ[0]).collect_coverage (c->input);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05002026
Behdad Esfahbod0382b712018-11-02 12:23:26 -04002027 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05002028 struct ContextCollectGlyphsLookupContext lookup_context = {
2029 {collect_coverage},
Behdad Esfahbode75943d2012-11-30 08:38:24 +02002030 this
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05002031 };
2032
2033 context_collect_glyphs_lookup (c,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02002034 glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05002035 lookupCount, lookupRecord,
2036 lookup_context);
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002037 }
2038
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302039 bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002040 {
Behdad Esfahbod0382b712018-11-02 12:23:26 -04002041 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002042 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002043 {match_coverage},
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002044 this
2045 };
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07002046 return context_would_apply_lookup (c,
2047 glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
2048 lookupCount, lookupRecord,
2049 lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002050 }
2051
Ebrahim Byagowie4120082018-12-17 21:31:01 +03302052 const Coverage &get_coverage () const { return this+coverageZ[0]; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002053
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302054 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002055 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002056 TRACE_APPLY (this);
Behdad Esfahbodfb059082018-11-30 20:45:40 -05002057 unsigned int index = (this+coverageZ[0]).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002058 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04002059
Behdad Esfahbod0382b712018-11-02 12:23:26 -04002060 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002061 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002062 {match_coverage},
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04002063 this
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002064 };
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02002065 return_trace (context_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, lookup_context));
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002066 }
2067
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302068 bool subset (hb_subset_context_t *c) const
Behdad Esfahbod339d3602018-09-03 17:33:34 -07002069 {
2070 TRACE_SUBSET (this);
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002071 auto *out = c->serializer->start_embed (this);
2072 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
2073
2074 out->format = format;
2075 out->glyphCount = glyphCount;
2076 out->lookupCount = lookupCount;
2077
Behdad Esfahbod26111a12020-06-28 02:59:47 -07002078 auto coverages = coverageZ.as_array (glyphCount);
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002079
2080 for (const OffsetTo<Coverage>& offset : coverages)
2081 {
Behdad Esfahbod6d941942021-02-19 17:08:10 -07002082 /* TODO(subset) This looks like should not be necessary to write this way. */
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002083 auto *o = c->serializer->allocate_size<OffsetTo<Coverage>> (OffsetTo<Coverage>::static_size);
2084 if (unlikely (!o)) return_trace (false);
2085 if (!o->serialize_subset (c, offset, this)) return_trace (false);
2086 }
2087
2088 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
2089 const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
2090 for (unsigned i = 0; i < (unsigned) lookupCount; i++)
2091 c->serializer->copy (lookupRecord[i], lookup_map);
Ebrahim Byagowia79d0e42020-05-21 07:32:58 +04302092
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002093 return_trace (true);
Behdad Esfahbod339d3602018-09-03 17:33:34 -07002094 }
2095
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302096 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002097 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002098 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002099 if (!c->check_struct (this)) return_trace (false);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002100 unsigned int count = glyphCount;
Behdad Esfahbodfb059082018-11-30 20:45:40 -05002101 if (!count) return_trace (false); /* We want to access coverageZ[0] freely. */
Behdad Esfahbod9507b052018-09-10 23:18:07 +02002102 if (!c->check_array (coverageZ.arrayZ, count)) return_trace (false);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002103 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002104 if (!coverageZ[i].sanitize (c, this)) return_trace (false);
Behdad Esfahbod0382b712018-11-02 12:23:26 -04002105 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
Behdad Esfahbod9507b052018-09-10 23:18:07 +02002106 return_trace (c->check_array (lookupRecord, lookupCount));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002107 }
2108
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002109 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002110 HBUINT16 format; /* Format identifier--format = 3 */
2111 HBUINT16 glyphCount; /* Number of glyphs in the input glyph
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002112 * sequence */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002113 HBUINT16 lookupCount; /* Number of LookupRecords */
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002114 UnsizedArrayOf<OffsetTo<Coverage>>
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02002115 coverageZ; /* Array of offsets to Coverage
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002116 * table in glyph sequence order */
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02002117/*UnsizedArrayOf<LookupRecord>
2118 lookupRecordX;*/ /* Array of LookupRecords--in
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002119 * design order */
Behdad Esfahbod569da922010-05-10 16:38:32 -04002120 public:
Behdad Esfahbod6d7c6e12018-02-07 14:09:56 -06002121 DEFINE_SIZE_ARRAY (6, coverageZ);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002122};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002123
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002124struct Context
2125{
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -07002126 template <typename context_t, typename ...Ts>
Behdad Esfahbod83e3eab2019-05-07 20:58:43 -07002127 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002128 {
Behdad Esfahbod00f6a8e2014-12-12 20:36:49 -08002129 TRACE_DISPATCH (this, u.format);
Behdad Esfahbodf396fbb2015-10-09 12:25:55 -04002130 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002131 switch (u.format) {
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -07002132 case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
2133 case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
2134 case 3: return_trace (c->dispatch (u.format3, hb_forward<Ts> (ds)...));
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002135 default:return_trace (c->default_return_value ());
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002136 }
2137 }
2138
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002139 protected:
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002140 union {
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002141 HBUINT16 format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -04002142 ContextFormat1 format1;
2143 ContextFormat2 format2;
2144 ContextFormat3 format3;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002145 } u;
2146};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002147
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002148
2149/* Chaining Contextual lookups */
2150
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002151struct ChainContextClosureLookupContext
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002152{
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002153 ContextClosureFuncs funcs;
2154 const void *intersects_data[3];
2155};
2156
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002157struct ChainContextCollectGlyphsLookupContext
2158{
2159 ContextCollectGlyphsFuncs funcs;
2160 const void *collect_data[3];
2161};
2162
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002163struct ChainContextApplyLookupContext
2164{
2165 ContextApplyFuncs funcs;
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04002166 const void *match_data[3];
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04002167};
2168
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002169static inline bool chain_context_intersects (const hb_set_t *glyphs,
2170 unsigned int backtrackCount,
2171 const HBUINT16 backtrack[],
2172 unsigned int inputCount, /* Including the first glyph (not matched) */
2173 const HBUINT16 input[], /* Array of input values--start with second glyph */
2174 unsigned int lookaheadCount,
2175 const HBUINT16 lookahead[],
2176 ChainContextClosureLookupContext &lookup_context)
2177{
Qunxin Liu44d88cf2020-05-08 15:33:34 -07002178 return array_is_subset_of (glyphs,
2179 backtrackCount, backtrack,
2180 lookup_context.funcs.intersects, lookup_context.intersects_data[0])
2181 && array_is_subset_of (glyphs,
2182 inputCount ? inputCount - 1 : 0, input,
2183 lookup_context.funcs.intersects, lookup_context.intersects_data[1])
2184 && array_is_subset_of (glyphs,
2185 lookaheadCount, lookahead,
2186 lookup_context.funcs.intersects, lookup_context.intersects_data[2]);
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002187}
2188
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002189static inline void chain_context_closure_lookup (hb_closure_context_t *c,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002190 unsigned int backtrackCount,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002191 const HBUINT16 backtrack[],
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002192 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002193 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002194 unsigned int lookaheadCount,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002195 const HBUINT16 lookahead[],
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002196 unsigned int lookupCount,
2197 const LookupRecord lookupRecord[],
2198 ChainContextClosureLookupContext &lookup_context)
2199{
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002200 if (chain_context_intersects (c->glyphs,
2201 backtrackCount, backtrack,
2202 inputCount, input,
2203 lookaheadCount, lookahead,
2204 lookup_context))
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05002205 recurse_lookups (c,
2206 lookupCount, lookupRecord);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002207}
2208
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002209static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03302210 unsigned int backtrackCount,
2211 const HBUINT16 backtrack[],
2212 unsigned int inputCount, /* Including the first glyph (not matched) */
2213 const HBUINT16 input[], /* Array of input values--start with second glyph */
2214 unsigned int lookaheadCount,
2215 const HBUINT16 lookahead[],
2216 unsigned int lookupCount,
2217 const LookupRecord lookupRecord[],
2218 ChainContextCollectGlyphsLookupContext &lookup_context)
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002219{
Behdad Esfahbod83035932012-12-04 17:08:41 -05002220 collect_array (c, c->before,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002221 backtrackCount, backtrack,
2222 lookup_context.funcs.collect, lookup_context.collect_data[0]);
Behdad Esfahbod83035932012-12-04 17:08:41 -05002223 collect_array (c, c->input,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002224 inputCount ? inputCount - 1 : 0, input,
2225 lookup_context.funcs.collect, lookup_context.collect_data[1]);
Behdad Esfahbod83035932012-12-04 17:08:41 -05002226 collect_array (c, c->after,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002227 lookaheadCount, lookahead,
2228 lookup_context.funcs.collect, lookup_context.collect_data[2]);
2229 recurse_lookups (c,
2230 lookupCount, lookupRecord);
2231}
2232
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002233static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c,
2234 unsigned int backtrackCount,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002235 const HBUINT16 backtrack[] HB_UNUSED,
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002236 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002237 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002238 unsigned int lookaheadCount,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002239 const HBUINT16 lookahead[] HB_UNUSED,
Behdad Esfahbod0beb66e2012-12-05 18:46:04 -05002240 unsigned int lookupCount HB_UNUSED,
2241 const LookupRecord lookupRecord[] HB_UNUSED,
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002242 ChainContextApplyLookupContext &lookup_context)
2243{
Behdad Esfahbodd9b204d2012-08-23 16:22:28 -04002244 return (c->zero_context ? !backtrackCount && !lookaheadCount : true)
Behdad Esfahbod1f2bb172012-08-23 16:10:37 -04002245 && would_match_input (c,
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002246 inputCount, input,
2247 lookup_context.funcs.match, lookup_context.match_data[1]);
2248}
2249
Behdad Esfahbodfd034492018-01-17 16:46:51 -08002250static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002251 unsigned int backtrackCount,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002252 const HBUINT16 backtrack[],
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002253 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002254 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002255 unsigned int lookaheadCount,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002256 const HBUINT16 lookahead[],
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002257 unsigned int lookupCount,
2258 const LookupRecord lookupRecord[],
2259 ChainContextApplyLookupContext &lookup_context)
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04002260{
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02002261 unsigned int start_index = 0, match_length = 0, end_index = 0;
Behdad Esfahbod5ba45042015-11-02 15:43:08 -08002262 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
Behdad Esfahbodf19e0b02012-06-09 02:26:57 -04002263 return match_input (c,
Behdad Esfahbod41697102010-05-05 01:37:58 -04002264 inputCount, input,
2265 lookup_context.funcs.match, lookup_context.match_data[1],
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02002266 &match_length, match_positions)
Behdad Esfahbodf19e0b02012-06-09 02:26:57 -04002267 && match_backtrack (c,
2268 backtrackCount, backtrack,
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02002269 lookup_context.funcs.match, lookup_context.match_data[0],
2270 &start_index)
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04002271 && match_lookahead (c,
Behdad Esfahbod41697102010-05-05 01:37:58 -04002272 lookaheadCount, lookahead,
2273 lookup_context.funcs.match, lookup_context.match_data[2],
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02002274 match_length, &end_index)
2275 && (c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index),
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03302276 apply_lookup (c,
2277 inputCount, match_positions,
2278 lookupCount, lookupRecord,
2279 match_length));
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04002280}
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04002281
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002282struct ChainRule
2283{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302284 bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002285 {
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002286 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
2287 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002288 return chain_context_intersects (glyphs,
2289 backtrack.len, backtrack.arrayZ,
Behdad Esfahbodeffc7ce2018-09-13 20:21:54 +02002290 input.lenP1, input.arrayZ,
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002291 lookahead.len, lookahead.arrayZ,
2292 lookup_context);
2293 }
2294
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302295 void closure (hb_closure_context_t *c,
2296 ChainContextClosureLookupContext &lookup_context) const
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002297 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04302298 if (unlikely (c->lookup_limit_exceeded ())) return;
Garret Rieger4ad686b2020-03-25 23:32:28 -07002299
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002300 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
2301 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
2302 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002303 chain_context_closure_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002304 backtrack.len, backtrack.arrayZ,
Behdad Esfahbodeffc7ce2018-09-13 20:21:54 +02002305 input.lenP1, input.arrayZ,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002306 lookahead.len, lookahead.arrayZ,
2307 lookup.len, lookup.arrayZ,
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002308 lookup_context);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002309 }
2310
Garret Riegerad241f92020-09-28 15:26:13 -07002311 void closure_lookups (hb_closure_lookups_context_t *c,
2312 ChainContextClosureLookupContext &lookup_context) const
Qunxin Liu0b39c482019-10-22 16:00:43 -07002313 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04302314 if (unlikely (c->lookup_limit_exceeded ())) return;
Garret Riegerad241f92020-09-28 15:26:13 -07002315 if (!intersects (c->glyphs, lookup_context)) return;
Garret Rieger4ad686b2020-03-25 23:32:28 -07002316
Qunxin Liu0b39c482019-10-22 16:00:43 -07002317 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
2318 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
2319 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
2320 recurse_lookups (c, lookup.len, lookup.arrayZ);
2321 }
2322
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302323 void collect_glyphs (hb_collect_glyphs_context_t *c,
2324 ChainContextCollectGlyphsLookupContext &lookup_context) const
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002325 {
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002326 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
2327 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
2328 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002329 chain_context_collect_glyphs_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002330 backtrack.len, backtrack.arrayZ,
Behdad Esfahbodeffc7ce2018-09-13 20:21:54 +02002331 input.lenP1, input.arrayZ,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002332 lookahead.len, lookahead.arrayZ,
2333 lookup.len, lookup.arrayZ,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002334 lookup_context);
2335 }
2336
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302337 bool would_apply (hb_would_apply_context_t *c,
2338 ChainContextApplyLookupContext &lookup_context) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002339 {
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002340 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
2341 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
2342 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07002343 return chain_context_would_apply_lookup (c,
2344 backtrack.len, backtrack.arrayZ,
2345 input.lenP1, input.arrayZ,
2346 lookahead.len, lookahead.arrayZ, lookup.len,
2347 lookup.arrayZ, lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002348 }
2349
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302350 bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002351 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002352 TRACE_APPLY (this);
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002353 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
2354 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
2355 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002356 return_trace (chain_context_apply_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002357 backtrack.len, backtrack.arrayZ,
Behdad Esfahbodeffc7ce2018-09-13 20:21:54 +02002358 input.lenP1, input.arrayZ,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002359 lookahead.len, lookahead.arrayZ, lookup.len,
2360 lookup.arrayZ, lookup_context));
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002361 }
2362
Qunxin Liub66094a2019-09-30 16:19:18 -07002363 template<typename Iterator,
2364 hb_requires (hb_is_iterator (Iterator))>
2365 void serialize_array (hb_serialize_context_t *c,
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04302366 HBUINT16 len,
2367 Iterator it) const
Qunxin Liub66094a2019-09-30 16:19:18 -07002368 {
2369 c->copy (len);
2370 for (const auto g : it)
Behdad Esfahbod83b66bf2021-02-23 13:04:25 -07002371 c->copy ((HBUINT16) g);
Qunxin Liub66094a2019-09-30 16:19:18 -07002372 }
2373
2374 ChainRule* copy (hb_serialize_context_t *c,
Qunxin Liu593e58c2020-05-20 18:00:25 -07002375 const hb_map_t *lookup_map,
Qunxin Liub66094a2019-09-30 16:19:18 -07002376 const hb_map_t *backtrack_map,
2377 const hb_map_t *input_map = nullptr,
2378 const hb_map_t *lookahead_map = nullptr) const
2379 {
2380 TRACE_SERIALIZE (this);
2381 auto *out = c->start_embed (this);
2382 if (unlikely (!out)) return_trace (nullptr);
2383
2384 const hb_map_t *mapping = backtrack_map;
2385 serialize_array (c, backtrack.len, + backtrack.iter ()
2386 | hb_map (mapping));
2387
2388 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
2389 if (input_map) mapping = input_map;
2390 serialize_array (c, input.lenP1, + input.iter ()
2391 | hb_map (mapping));
2392
2393 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
2394 if (lookahead_map) mapping = lookahead_map;
2395 serialize_array (c, lookahead.len, + lookahead.iter ()
2396 | hb_map (mapping));
2397
Qunxin Liu593e58c2020-05-20 18:00:25 -07002398 const ArrayOf<LookupRecord> &lookupRecord = StructAfter<ArrayOf<LookupRecord>> (lookahead);
Qunxin Liu593e58c2020-05-20 18:00:25 -07002399
Garret Rieger8f47dd52020-11-04 11:05:22 -08002400 HBUINT16* lookupCount = c->embed (&(lookupRecord.len));
2401 if (!lookupCount) return_trace (nullptr);
2402
2403 for (unsigned i = 0; i < lookupRecord.len; i++)
2404 {
2405 if (!lookup_map->has (lookupRecord[i].lookupListIndex))
2406 {
2407 (*lookupCount)--;
2408 continue;
2409 }
Qunxin Liu593e58c2020-05-20 18:00:25 -07002410 if (!c->copy (lookupRecord[i], lookup_map)) return_trace (nullptr);
Garret Rieger8f47dd52020-11-04 11:05:22 -08002411 }
Qunxin Liub66094a2019-09-30 16:19:18 -07002412
2413 return_trace (out);
2414 }
2415
2416 bool subset (hb_subset_context_t *c,
Qunxin Liu593e58c2020-05-20 18:00:25 -07002417 const hb_map_t *lookup_map,
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04302418 const hb_map_t *backtrack_map = nullptr,
2419 const hb_map_t *input_map = nullptr,
2420 const hb_map_t *lookahead_map = nullptr) const
Qunxin Liub66094a2019-09-30 16:19:18 -07002421 {
2422 TRACE_SUBSET (this);
2423
Qunxin Liub2fcca62019-10-24 15:15:26 -07002424 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
2425 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
2426
Qunxin Liub66094a2019-09-30 16:19:18 -07002427 if (!backtrack_map)
2428 {
Garret Riegere5835052020-09-29 11:05:08 -07002429 const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
Qunxin Liub66094a2019-09-30 16:19:18 -07002430 if (!hb_all (backtrack, glyphset) ||
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04302431 !hb_all (input, glyphset) ||
2432 !hb_all (lookahead, glyphset))
2433 return_trace (false);
Qunxin Liub66094a2019-09-30 16:19:18 -07002434
Qunxin Liu593e58c2020-05-20 18:00:25 -07002435 copy (c->serializer, lookup_map, c->plan->glyph_map);
Qunxin Liub66094a2019-09-30 16:19:18 -07002436 }
2437 else
2438 {
2439 if (!hb_all (backtrack, backtrack_map) ||
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04302440 !hb_all (input, input_map) ||
2441 !hb_all (lookahead, lookahead_map))
2442 return_trace (false);
Ebrahim Byagowiaca63902019-10-22 00:06:46 +03302443
Qunxin Liu593e58c2020-05-20 18:00:25 -07002444 copy (c->serializer, lookup_map, backtrack_map, input_map, lookahead_map);
Qunxin Liub66094a2019-09-30 16:19:18 -07002445 }
2446
2447 return_trace (true);
2448 }
2449
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302450 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002451 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002452 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002453 if (!backtrack.sanitize (c)) return_trace (false);
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002454 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002455 if (!input.sanitize (c)) return_trace (false);
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002456 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002457 if (!lookahead.sanitize (c)) return_trace (false);
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002458 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002459 return_trace (lookup.sanitize (c));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002460 }
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002461
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002462 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002463 ArrayOf<HBUINT16>
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04002464 backtrack; /* Array of backtracking values
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002465 * (to be matched before the input
2466 * sequence) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002467 HeadlessArrayOf<HBUINT16>
Behdad Esfahbode8cbaaf2009-05-18 02:03:58 -04002468 inputX; /* Array of input values (start with
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002469 * second glyph) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002470 ArrayOf<HBUINT16>
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04002471 lookaheadX; /* Array of lookahead values's (to be
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04002472 * matched after the input sequence) */
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04002473 ArrayOf<LookupRecord>
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04002474 lookupX; /* Array of LookupRecords--in
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002475 * design order) */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04002476 public:
Behdad Esfahbodbea34c72010-05-10 17:28:16 -04002477 DEFINE_SIZE_MIN (8);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002478};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002479
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002480struct ChainRuleSet
2481{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302482 bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002483 {
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002484 return
2485 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002486 | hb_map (hb_add (this))
2487 | hb_map ([&] (const ChainRule &_) { return _.intersects (glyphs, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002488 | hb_any
2489 ;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002490 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302491 void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002492 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04302493 if (unlikely (c->lookup_limit_exceeded ())) return;
Garret Rieger4ad686b2020-03-25 23:32:28 -07002494
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002495 return
2496 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002497 | hb_map (hb_add (this))
2498 | hb_apply ([&] (const ChainRule &_) { _.closure (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002499 ;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002500 }
2501
Garret Riegerad241f92020-09-28 15:26:13 -07002502 void closure_lookups (hb_closure_lookups_context_t *c,
2503 ChainContextClosureLookupContext &lookup_context) const
Qunxin Liu0b39c482019-10-22 16:00:43 -07002504 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04302505 if (unlikely (c->lookup_limit_exceeded ())) return;
Garret Rieger4ad686b2020-03-25 23:32:28 -07002506
Qunxin Liu0b39c482019-10-22 16:00:43 -07002507 + hb_iter (rule)
2508 | hb_map (hb_add (this))
Garret Riegere31c2692020-09-28 16:51:25 -07002509 | hb_apply ([&] (const ChainRule &_) { _.closure_lookups (c, lookup_context); })
Qunxin Liu0b39c482019-10-22 16:00:43 -07002510 ;
2511 }
2512
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302513 void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002514 {
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002515 return
2516 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002517 | hb_map (hb_add (this))
2518 | hb_apply ([&] (const ChainRule &_) { _.collect_glyphs (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002519 ;
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002520 }
2521
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302522 bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002523 {
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002524 return
2525 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002526 | hb_map (hb_add (this))
2527 | hb_map ([&] (const ChainRule &_) { return _.would_apply (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002528 | hb_any
2529 ;
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002530 }
2531
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302532 bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002533 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002534 TRACE_APPLY (this);
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002535 return_trace (
2536 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002537 | hb_map (hb_add (this))
2538 | hb_map ([&] (const ChainRule &_) { return _.apply (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002539 | hb_any
2540 )
2541 ;
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04002542 }
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002543
Qunxin Liub66094a2019-09-30 16:19:18 -07002544 bool subset (hb_subset_context_t *c,
Qunxin Liu593e58c2020-05-20 18:00:25 -07002545 const hb_map_t *lookup_map,
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04302546 const hb_map_t *backtrack_klass_map = nullptr,
2547 const hb_map_t *input_klass_map = nullptr,
2548 const hb_map_t *lookahead_klass_map = nullptr) const
Qunxin Liub66094a2019-09-30 16:19:18 -07002549 {
2550 TRACE_SUBSET (this);
2551
2552 auto snap = c->serializer->snapshot ();
2553 auto *out = c->serializer->start_embed (*this);
2554 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
2555
2556 for (const OffsetTo<ChainRule>& _ : rule)
2557 {
2558 if (!_) continue;
2559 auto *o = out->rule.serialize_append (c->serializer);
2560 if (unlikely (!o)) continue;
Ebrahim Byagowiaca63902019-10-22 00:06:46 +03302561
Qunxin Liub66094a2019-09-30 16:19:18 -07002562 auto o_snap = c->serializer->snapshot ();
ariza188a0a42020-03-07 11:02:36 -08002563 if (!o->serialize_subset (c, _, this,
Qunxin Liu593e58c2020-05-20 18:00:25 -07002564 lookup_map,
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04302565 backtrack_klass_map,
2566 input_klass_map,
2567 lookahead_klass_map))
Qunxin Liub66094a2019-09-30 16:19:18 -07002568 {
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04302569 out->rule.pop ();
2570 c->serializer->revert (o_snap);
Qunxin Liub66094a2019-09-30 16:19:18 -07002571 }
2572 }
2573
2574 bool ret = bool (out->rule);
2575 if (!ret) c->serializer->revert (snap);
Ebrahim Byagowiaca63902019-10-22 00:06:46 +03302576
Qunxin Liub66094a2019-09-30 16:19:18 -07002577 return_trace (ret);
2578 }
2579
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302580 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002581 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002582 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002583 return_trace (rule.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002584 }
2585
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002586 protected:
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04002587 OffsetArrayOf<ChainRule>
2588 rule; /* Array of ChainRule tables
2589 * ordered by preference */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04002590 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04002591 DEFINE_SIZE_ARRAY (2, rule);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002592};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002593
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002594struct ChainContextFormat1
2595{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302596 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002597 {
2598 struct ChainContextClosureLookupContext lookup_context = {
2599 {intersects_glyph},
2600 {nullptr, nullptr, nullptr}
2601 };
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002602
2603 return
2604 + hb_zip (this+coverage, ruleSet)
2605 | hb_filter (*glyphs, hb_first)
2606 | hb_map (hb_second)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002607 | hb_map (hb_add (this))
2608 | hb_map ([&] (const ChainRuleSet &_) { return _.intersects (glyphs, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002609 | hb_any
2610 ;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002611 }
2612
Qunxin Liub4fc5932020-12-09 10:44:18 -08002613 bool may_have_non_1to1 () const
2614 { return true; }
2615
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302616 void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002617 {
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002618 struct ChainContextClosureLookupContext lookup_context = {
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002619 {intersects_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02002620 {nullptr, nullptr, nullptr}
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002621 };
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002622
2623 + hb_zip (this+coverage, ruleSet)
2624 | hb_filter (*c->glyphs, hb_first)
2625 | hb_map (hb_second)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002626 | hb_map (hb_add (this))
2627 | hb_apply ([&] (const ChainRuleSet &_) { _.closure (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002628 ;
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002629 }
2630
Qunxin Liu0b39c482019-10-22 16:00:43 -07002631 void closure_lookups (hb_closure_lookups_context_t *c) const
2632 {
Garret Riegerad241f92020-09-28 15:26:13 -07002633 struct ChainContextClosureLookupContext lookup_context = {
2634 {intersects_glyph},
2635 {nullptr, nullptr, nullptr}
2636 };
2637
2638 + hb_zip (this+coverage, ruleSet)
2639 | hb_filter (*c->glyphs, hb_first)
2640 | hb_map (hb_second)
Qunxin Liu0b39c482019-10-22 16:00:43 -07002641 | hb_map (hb_add (this))
Garret Riegere31c2692020-09-28 16:51:25 -07002642 | hb_apply ([&] (const ChainRuleSet &_) { _.closure_lookups (c, lookup_context); })
Qunxin Liu0b39c482019-10-22 16:00:43 -07002643 ;
2644 }
2645
Qunxin Liu8200e482020-02-26 13:11:42 -08002646 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
2647
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302648 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002649 {
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07002650 (this+coverage).collect_coverage (c->input);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002651
2652 struct ChainContextCollectGlyphsLookupContext lookup_context = {
2653 {collect_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02002654 {nullptr, nullptr, nullptr}
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002655 };
2656
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002657 + hb_iter (ruleSet)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002658 | hb_map (hb_add (this))
2659 | hb_apply ([&] (const ChainRuleSet &_) { _.collect_glyphs (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002660 ;
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002661 }
2662
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302663 bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002664 {
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05002665 const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002666 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002667 {match_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02002668 {nullptr, nullptr, nullptr}
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002669 };
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07002670 return rule_set.would_apply (c, lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002671 }
2672
Ebrahim Byagowie4120082018-12-17 21:31:01 +03302673 const Coverage &get_coverage () const { return this+coverage; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002674
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302675 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002676 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002677 TRACE_APPLY (this);
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05002678 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002679 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002680
2681 const ChainRuleSet &rule_set = this+ruleSet[index];
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002682 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002683 {match_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02002684 {nullptr, nullptr, nullptr}
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002685 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002686 return_trace (rule_set.apply (c, lookup_context));
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002687 }
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002688
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302689 bool subset (hb_subset_context_t *c) const
Behdad Esfahbod339d3602018-09-03 17:33:34 -07002690 {
2691 TRACE_SUBSET (this);
Garret Riegere5835052020-09-29 11:05:08 -07002692 const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
Qunxin Liub66094a2019-09-30 16:19:18 -07002693 const hb_map_t &glyph_map = *c->plan->glyph_map;
2694
2695 auto *out = c->serializer->start_embed (*this);
2696 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
2697 out->format = format;
2698
Qunxin Liu593e58c2020-05-20 18:00:25 -07002699 const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
Qunxin Liub66094a2019-09-30 16:19:18 -07002700 hb_sorted_vector_t<hb_codepoint_t> new_coverage;
2701 + hb_zip (this+coverage, ruleSet)
2702 | hb_filter (glyphset, hb_first)
Qunxin Liu593e58c2020-05-20 18:00:25 -07002703 | hb_filter (subset_offset_array (c, out->ruleSet, this, lookup_map), hb_second)
Qunxin Liub66094a2019-09-30 16:19:18 -07002704 | hb_map (hb_first)
2705 | hb_map (glyph_map)
2706 | hb_sink (new_coverage)
2707 ;
2708
2709 out->coverage.serialize (c->serializer, out)
2710 .serialize (c->serializer, new_coverage.iter ());
2711 return_trace (bool (new_coverage));
Behdad Esfahbod339d3602018-09-03 17:33:34 -07002712 }
2713
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302714 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002715 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002716 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002717 return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002718 }
2719
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002720 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002721 HBUINT16 format; /* Format identifier--format = 1 */
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04002722 OffsetTo<Coverage>
2723 coverage; /* Offset to Coverage table--from
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002724 * beginning of table */
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002725 OffsetArrayOf<ChainRuleSet>
2726 ruleSet; /* Array of ChainRuleSet tables
2727 * ordered by Coverage Index */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04002728 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04002729 DEFINE_SIZE_ARRAY (6, ruleSet);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002730};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002731
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002732struct ChainContextFormat2
2733{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302734 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002735 {
2736 if (!(this+coverage).intersects (glyphs))
2737 return false;
2738
2739 const ClassDef &backtrack_class_def = this+backtrackClassDef;
2740 const ClassDef &input_class_def = this+inputClassDef;
2741 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2742
2743 struct ChainContextClosureLookupContext lookup_context = {
2744 {intersects_class},
2745 {&backtrack_class_def,
2746 &input_class_def,
2747 &lookahead_class_def}
2748 };
2749
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07002750 return
Behdad Esfahbod26111a12020-06-28 02:59:47 -07002751 + hb_iter (ruleSet)
2752 | hb_map (hb_add (this))
2753 | hb_enumerate
2754 | hb_map ([&] (const hb_pair_t<unsigned, const ChainRuleSet &> p)
Behdad Esfahbod78d35f02019-05-15 18:15:05 -07002755 { return input_class_def.intersects_class (glyphs, p.first) &&
Behdad Esfahbod26111a12020-06-28 02:59:47 -07002756 p.second.intersects (glyphs, lookup_context); })
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07002757 | hb_any
2758 ;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002759 }
Qunxin Liub4fc5932020-12-09 10:44:18 -08002760
2761 bool may_have_non_1to1 () const
2762 { return true; }
2763
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302764 void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002765 {
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002766 if (!(this+coverage).intersects (c->glyphs))
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002767 return;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002768
2769 const ClassDef &backtrack_class_def = this+backtrackClassDef;
2770 const ClassDef &input_class_def = this+inputClassDef;
2771 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2772
2773 struct ChainContextClosureLookupContext lookup_context = {
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002774 {intersects_class},
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002775 {&backtrack_class_def,
2776 &input_class_def,
2777 &lookahead_class_def}
2778 };
2779
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07002780 return
2781 + hb_enumerate (ruleSet)
Behdad Esfahbod78d35f02019-05-15 18:15:05 -07002782 | hb_filter ([&] (unsigned _)
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07002783 { return input_class_def.intersects_class (c->glyphs, _); },
2784 hb_first)
2785 | hb_map (hb_second)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002786 | hb_map (hb_add (this))
2787 | hb_apply ([&] (const ChainRuleSet &_) { _.closure (c, lookup_context); })
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07002788 ;
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002789 }
2790
Qunxin Liu0b39c482019-10-22 16:00:43 -07002791 void closure_lookups (hb_closure_lookups_context_t *c) const
2792 {
Garret Riegerad241f92020-09-28 15:26:13 -07002793 if (!(this+coverage).intersects (c->glyphs))
2794 return;
2795
2796 const ClassDef &backtrack_class_def = this+backtrackClassDef;
2797 const ClassDef &input_class_def = this+inputClassDef;
2798 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2799
2800 struct ChainContextClosureLookupContext lookup_context = {
2801 {intersects_class},
2802 {&backtrack_class_def,
2803 &input_class_def,
2804 &lookahead_class_def}
2805 };
2806
Qunxin Liu0b39c482019-10-22 16:00:43 -07002807 + hb_iter (ruleSet)
2808 | hb_map (hb_add (this))
Garret Riegerad241f92020-09-28 15:26:13 -07002809 | hb_enumerate
Behdad Esfahbod6e1afac2021-02-09 18:48:46 -07002810 | hb_filter([&] (unsigned klass)
2811 { return input_class_def.intersects_class (c->glyphs, klass); }, hb_first)
Garret Riegerad241f92020-09-28 15:26:13 -07002812 | hb_map (hb_second)
2813 | hb_apply ([&] (const ChainRuleSet &_)
2814 { _.closure_lookups (c, lookup_context); })
Qunxin Liu0b39c482019-10-22 16:00:43 -07002815 ;
2816 }
2817
Qunxin Liu8200e482020-02-26 13:11:42 -08002818 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
2819
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302820 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002821 {
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07002822 (this+coverage).collect_coverage (c->input);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002823
Behdad Esfahbod11fba792013-01-02 23:36:37 -06002824 const ClassDef &backtrack_class_def = this+backtrackClassDef;
2825 const ClassDef &input_class_def = this+inputClassDef;
2826 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2827
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002828 struct ChainContextCollectGlyphsLookupContext lookup_context = {
2829 {collect_class},
Behdad Esfahbod11fba792013-01-02 23:36:37 -06002830 {&backtrack_class_def,
2831 &input_class_def,
2832 &lookahead_class_def}
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002833 };
2834
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002835 + hb_iter (ruleSet)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002836 | hb_map (hb_add (this))
2837 | hb_apply ([&] (const ChainRuleSet &_) { _.collect_glyphs (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002838 ;
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002839 }
2840
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302841 bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002842 {
Behdad Esfahbod11fba792013-01-02 23:36:37 -06002843 const ClassDef &backtrack_class_def = this+backtrackClassDef;
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002844 const ClassDef &input_class_def = this+inputClassDef;
Behdad Esfahbod11fba792013-01-02 23:36:37 -06002845 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002846
Behdad Esfahbod2dc11412012-11-24 19:16:34 -05002847 unsigned int index = input_class_def.get_class (c->glyphs[0]);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002848 const ChainRuleSet &rule_set = this+ruleSet[index];
2849 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002850 {match_class},
Behdad Esfahbod11fba792013-01-02 23:36:37 -06002851 {&backtrack_class_def,
2852 &input_class_def,
2853 &lookahead_class_def}
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002854 };
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07002855 return rule_set.would_apply (c, lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002856 }
2857
Ebrahim Byagowie4120082018-12-17 21:31:01 +03302858 const Coverage &get_coverage () const { return this+coverage; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002859
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302860 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002861 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002862 TRACE_APPLY (this);
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05002863 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002864 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002865
2866 const ClassDef &backtrack_class_def = this+backtrackClassDef;
2867 const ClassDef &input_class_def = this+inputClassDef;
2868 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2869
Behdad Esfahbod2dc11412012-11-24 19:16:34 -05002870 index = input_class_def.get_class (c->buffer->cur().codepoint);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002871 const ChainRuleSet &rule_set = this+ruleSet[index];
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002872 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002873 {match_class},
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04002874 {&backtrack_class_def,
2875 &input_class_def,
2876 &lookahead_class_def}
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002877 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002878 return_trace (rule_set.apply (c, lookup_context));
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002879 }
2880
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302881 bool subset (hb_subset_context_t *c) const
Behdad Esfahbod339d3602018-09-03 17:33:34 -07002882 {
2883 TRACE_SUBSET (this);
Qunxin Liub66094a2019-09-30 16:19:18 -07002884 auto *out = c->serializer->start_embed (*this);
2885 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
2886 out->format = format;
ariza188a0a42020-03-07 11:02:36 -08002887 out->coverage.serialize_subset (c, coverage, this);
Qunxin Liub66094a2019-09-30 16:19:18 -07002888
2889 hb_map_t backtrack_klass_map;
Qunxin Liub66094a2019-09-30 16:19:18 -07002890 hb_map_t input_klass_map;
Qunxin Liub66094a2019-09-30 16:19:18 -07002891 hb_map_t lookahead_klass_map;
Behdad Esfahboddfa9d7a2021-02-11 11:08:52 -07002892
2893 out->backtrackClassDef.serialize_subset (c, backtrackClassDef, this, &backtrack_klass_map);
2894 // TODO: subset inputClassDef based on glyphs survived in Coverage subsetting
2895 out->inputClassDef.serialize_subset (c, inputClassDef, this, &input_klass_map);
ariza188a0a42020-03-07 11:02:36 -08002896 out->lookaheadClassDef.serialize_subset (c, lookaheadClassDef, this, &lookahead_klass_map);
Behdad Esfahboddfa9d7a2021-02-11 11:08:52 -07002897
2898 if (unlikely (!c->serializer->propagate_error (backtrack_klass_map,
2899 input_klass_map,
2900 lookahead_klass_map)))
Garret Rieger06dbb6a2020-07-31 15:56:14 -07002901 return_trace (false);
Qunxin Liub66094a2019-09-30 16:19:18 -07002902
Garret Riegerdc375552020-09-25 13:08:46 -07002903 int non_zero_index = -1, index = 0;
Qunxin Liub66094a2019-09-30 16:19:18 -07002904 bool ret = true;
Qunxin Liu593e58c2020-05-20 18:00:25 -07002905 const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
Garret Riegerdc375552020-09-25 13:08:46 -07002906 auto last_non_zero = c->serializer->snapshot ();
Qunxin Liub66094a2019-09-30 16:19:18 -07002907 for (const OffsetTo<ChainRuleSet>& _ : + hb_enumerate (ruleSet)
2908 | hb_filter (input_klass_map, hb_first)
2909 | hb_map (hb_second))
2910 {
2911 auto *o = out->ruleSet.serialize_append (c->serializer);
2912 if (unlikely (!o))
2913 {
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04302914 ret = false;
2915 break;
Qunxin Liub66094a2019-09-30 16:19:18 -07002916 }
Qunxin Liu593e58c2020-05-20 18:00:25 -07002917 if (o->serialize_subset (c, _, this,
2918 lookup_map,
2919 &backtrack_klass_map,
2920 &input_klass_map,
2921 &lookahead_klass_map))
Garret Riegerdc375552020-09-25 13:08:46 -07002922 {
2923 last_non_zero = c->serializer->snapshot ();
Ebrahim Byagowi5a7cc7f2020-07-29 08:33:32 +04302924 non_zero_index = index;
Garret Riegerdc375552020-09-25 13:08:46 -07002925 }
Qunxin Liu593e58c2020-05-20 18:00:25 -07002926
2927 index++;
Qunxin Liub66094a2019-09-30 16:19:18 -07002928 }
2929
2930 if (!ret) return_trace (ret);
2931
Garret Riegerdc375552020-09-25 13:08:46 -07002932 // prune empty trailing ruleSets
2933 if (index > non_zero_index) {
2934 c->serializer->revert (last_non_zero);
2935 out->ruleSet.len = non_zero_index + 1;
Qunxin Liub66094a2019-09-30 16:19:18 -07002936 }
2937
2938 return_trace (bool (out->ruleSet));
Behdad Esfahbod339d3602018-09-03 17:33:34 -07002939 }
2940
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302941 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002942 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002943 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002944 return_trace (coverage.sanitize (c, this) &&
2945 backtrackClassDef.sanitize (c, this) &&
2946 inputClassDef.sanitize (c, this) &&
2947 lookaheadClassDef.sanitize (c, this) &&
2948 ruleSet.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002949 }
2950
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002951 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002952 HBUINT16 format; /* Format identifier--format = 2 */
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002953 OffsetTo<Coverage>
2954 coverage; /* Offset to Coverage table--from
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002955 * beginning of table */
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002956 OffsetTo<ClassDef>
2957 backtrackClassDef; /* Offset to glyph ClassDef table
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002958 * containing backtrack sequence
2959 * data--from beginning of table */
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002960 OffsetTo<ClassDef>
2961 inputClassDef; /* Offset to glyph ClassDef
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002962 * table containing input sequence
2963 * data--from beginning of table */
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002964 OffsetTo<ClassDef>
2965 lookaheadClassDef; /* Offset to glyph ClassDef table
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002966 * containing lookahead sequence
2967 * data--from beginning of table */
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002968 OffsetArrayOf<ChainRuleSet>
2969 ruleSet; /* Array of ChainRuleSet tables
2970 * ordered by class */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04002971 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04002972 DEFINE_SIZE_ARRAY (12, ruleSet);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002973};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002974
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002975struct ChainContextFormat3
2976{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302977 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002978 {
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002979 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002980
2981 if (!(this+input[0]).intersects (glyphs))
2982 return false;
2983
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002984 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002985 struct ChainContextClosureLookupContext lookup_context = {
2986 {intersects_coverage},
2987 {this, this, this}
2988 };
2989 return chain_context_intersects (glyphs,
2990 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2991 input.len, (const HBUINT16 *) input.arrayZ + 1,
2992 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2993 lookup_context);
2994 }
2995
Qunxin Liub4fc5932020-12-09 10:44:18 -08002996 bool may_have_non_1to1 () const
2997 { return true; }
2998
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302999 void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04003000 {
Ebrahim Byagowi92588782019-04-30 13:05:10 -07003001 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
Behdad Esfahbod5caece62012-04-23 23:03:12 -04003002
3003 if (!(this+input[0]).intersects (c->glyphs))
3004 return;
3005
Ebrahim Byagowi92588782019-04-30 13:05:10 -07003006 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
3007 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
Behdad Esfahbod5caece62012-04-23 23:03:12 -04003008 struct ChainContextClosureLookupContext lookup_context = {
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05003009 {intersects_coverage},
Behdad Esfahbod5caece62012-04-23 23:03:12 -04003010 {this, this, this}
3011 };
3012 chain_context_closure_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07003013 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
3014 input.len, (const HBUINT16 *) input.arrayZ + 1,
3015 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
3016 lookup.len, lookup.arrayZ,
Behdad Esfahbod5caece62012-04-23 23:03:12 -04003017 lookup_context);
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04003018 }
3019
Qunxin Liu0b39c482019-10-22 16:00:43 -07003020 void closure_lookups (hb_closure_lookups_context_t *c) const
3021 {
Garret Riegera5c0ec72020-09-25 14:57:20 -07003022 if (!intersects (c->glyphs))
3023 return;
3024
Qunxin Liu0b39c482019-10-22 16:00:43 -07003025 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
3026 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
3027 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
3028 recurse_lookups (c, lookup.len, lookup.arrayZ);
3029 }
3030
Qunxin Liu8200e482020-02-26 13:11:42 -08003031 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
3032
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303033 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbod26514d52012-11-23 18:13:48 -05003034 {
Ebrahim Byagowi92588782019-04-30 13:05:10 -07003035 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05003036
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07003037 (this+input[0]).collect_coverage (c->input);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05003038
Ebrahim Byagowi92588782019-04-30 13:05:10 -07003039 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
3040 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05003041 struct ChainContextCollectGlyphsLookupContext lookup_context = {
3042 {collect_coverage},
3043 {this, this, this}
3044 };
3045 chain_context_collect_glyphs_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07003046 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
3047 input.len, (const HBUINT16 *) input.arrayZ + 1,
3048 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
3049 lookup.len, lookup.arrayZ,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05003050 lookup_context);
Behdad Esfahbod26514d52012-11-23 18:13:48 -05003051 }
3052
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303053 bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003054 {
Ebrahim Byagowi92588782019-04-30 13:05:10 -07003055 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
3056 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
3057 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003058 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05003059 {match_coverage},
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003060 {this, this, this}
3061 };
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07003062 return chain_context_would_apply_lookup (c,
3063 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
3064 input.len, (const HBUINT16 *) input.arrayZ + 1,
3065 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
3066 lookup.len, lookup.arrayZ, lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003067 }
3068
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303069 const Coverage &get_coverage () const
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05003070 {
Ebrahim Byagowi92588782019-04-30 13:05:10 -07003071 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05003072 return this+input[0];
3073 }
3074
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303075 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04003076 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05003077 TRACE_APPLY (this);
Ebrahim Byagowi92588782019-04-30 13:05:10 -07003078 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04003079
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05003080 unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003081 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003082
Ebrahim Byagowi92588782019-04-30 13:05:10 -07003083 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
3084 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04003085 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05003086 {match_coverage},
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04003087 {this, this, this}
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04003088 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003089 return_trace (chain_context_apply_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07003090 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
3091 input.len, (const HBUINT16 *) input.arrayZ + 1,
3092 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
3093 lookup.len, lookup.arrayZ, lookup_context));
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003094 }
3095
Qunxin Liub66094a2019-09-30 16:19:18 -07003096 template<typename Iterator,
3097 hb_requires (hb_is_iterator (Iterator))>
Ebrahim Byagowi07acd1a2020-03-08 23:39:24 +03303098 bool serialize_coverage_offsets (hb_subset_context_t *c, Iterator it, const void* base) const
Qunxin Liub66094a2019-09-30 16:19:18 -07003099 {
3100 TRACE_SERIALIZE (this);
3101 auto *out = c->serializer->start_embed<OffsetArrayOf<Coverage>> ();
3102
Garret Rieger90eb1a42020-09-25 12:36:32 -07003103 if (unlikely (!c->serializer->allocate_size<HBUINT16> (HBUINT16::static_size)))
Garret Rieger940e1c62020-09-28 17:22:01 -07003104 return_trace (false);
Qunxin Liub66094a2019-09-30 16:19:18 -07003105
Garret Rieger940e1c62020-09-28 17:22:01 -07003106 for (auto& offset : it) {
3107 auto *o = out->serialize_append (c->serializer);
3108 if (unlikely (!o) || !o->serialize_subset (c, offset, base))
3109 return_trace (false);
3110 }
Qunxin Liub66094a2019-09-30 16:19:18 -07003111
Garret Rieger940e1c62020-09-28 17:22:01 -07003112 return_trace (true);
Qunxin Liub66094a2019-09-30 16:19:18 -07003113 }
3114
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303115 bool subset (hb_subset_context_t *c) const
Behdad Esfahbod339d3602018-09-03 17:33:34 -07003116 {
3117 TRACE_SUBSET (this);
Qunxin Liub66094a2019-09-30 16:19:18 -07003118
3119 auto *out = c->serializer->start_embed (this);
3120 if (unlikely (!out)) return_trace (false);
3121 if (unlikely (!c->serializer->embed (this->format))) return_trace (false);
3122
ariza188a0a42020-03-07 11:02:36 -08003123 if (!serialize_coverage_offsets (c, backtrack.iter (), this))
Qunxin Liub66094a2019-09-30 16:19:18 -07003124 return_trace (false);
Ebrahim Byagowiaca63902019-10-22 00:06:46 +03303125
Qunxin Liub66094a2019-09-30 16:19:18 -07003126 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
ariza188a0a42020-03-07 11:02:36 -08003127 if (!serialize_coverage_offsets (c, input.iter (), this))
Qunxin Liub66094a2019-09-30 16:19:18 -07003128 return_trace (false);
3129
3130 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
ariza188a0a42020-03-07 11:02:36 -08003131 if (!serialize_coverage_offsets (c, lookahead.iter (), this))
Qunxin Liub66094a2019-09-30 16:19:18 -07003132 return_trace (false);
Ebrahim Byagowiaca63902019-10-22 00:06:46 +03303133
Qunxin Liu593e58c2020-05-20 18:00:25 -07003134 const ArrayOf<LookupRecord> &lookupRecord = StructAfter<ArrayOf<LookupRecord>> (lookahead);
3135 HBUINT16 lookupCount;
3136 lookupCount = lookupRecord.len;
3137 if (!c->serializer->copy (lookupCount)) return_trace (false);
3138
3139 const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
3140 for (unsigned i = 0; i < (unsigned) lookupCount; i++)
3141 if (!c->serializer->copy (lookupRecord[i], lookup_map)) return_trace (false);
Ebrahim Byagowid0e2add2020-07-18 22:14:52 +04303142
Qunxin Liu593e58c2020-05-20 18:00:25 -07003143 return_trace (true);
Behdad Esfahbod339d3602018-09-03 17:33:34 -07003144 }
3145
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303146 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03003147 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05003148 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003149 if (!backtrack.sanitize (c, this)) return_trace (false);
Ebrahim Byagowi92588782019-04-30 13:05:10 -07003150 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003151 if (!input.sanitize (c, this)) return_trace (false);
3152 if (!input.len) return_trace (false); /* To be consistent with Context. */
Ebrahim Byagowi92588782019-04-30 13:05:10 -07003153 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003154 if (!lookahead.sanitize (c, this)) return_trace (false);
Ebrahim Byagowi92588782019-04-30 13:05:10 -07003155 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003156 return_trace (lookup.sanitize (c));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04003157 }
3158
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04003159 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01003160 HBUINT16 format; /* Format identifier--format = 3 */
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04003161 OffsetArrayOf<Coverage>
Behdad Esfahbod13ed4402009-05-18 02:14:37 -04003162 backtrack; /* Array of coverage tables
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003163 * in backtracking sequence, in glyph
3164 * sequence order */
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04003165 OffsetArrayOf<Coverage>
Behdad Esfahbod13ed4402009-05-18 02:14:37 -04003166 inputX ; /* Array of coverage
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003167 * tables in input sequence, in glyph
3168 * sequence order */
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04003169 OffsetArrayOf<Coverage>
Behdad Esfahbod13ed4402009-05-18 02:14:37 -04003170 lookaheadX; /* Array of coverage tables
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003171 * in lookahead sequence, in glyph
3172 * sequence order */
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04003173 ArrayOf<LookupRecord>
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04003174 lookupX; /* Array of LookupRecords--in
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04003175 * design order) */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04003176 public:
Behdad Esfahbodbea34c72010-05-10 17:28:16 -04003177 DEFINE_SIZE_MIN (10);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003178};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003179
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04003180struct ChainContext
3181{
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -07003182 template <typename context_t, typename ...Ts>
Behdad Esfahbod83e3eab2019-05-07 20:58:43 -07003183 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04003184 {
Behdad Esfahbod00f6a8e2014-12-12 20:36:49 -08003185 TRACE_DISPATCH (this, u.format);
Behdad Esfahbodf396fbb2015-10-09 12:25:55 -04003186 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04003187 switch (u.format) {
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -07003188 case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
3189 case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
3190 case 3: return_trace (c->dispatch (u.format3, hb_forward<Ts> (ds)...));
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003191 default:return_trace (c->default_return_value ());
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003192 }
3193 }
3194
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04003195 protected:
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003196 union {
Behdad Esfahbod6b191782018-01-10 03:07:30 +01003197 HBUINT16 format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -04003198 ChainContextFormat1 format1;
3199 ChainContextFormat2 format2;
3200 ChainContextFormat3 format3;
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003201 } u;
3202};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003203
3204
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003205template <typename T>
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003206struct ExtensionFormat1
3207{
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303208 unsigned int get_type () const { return extensionLookupType; }
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003209
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003210 template <typename X>
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303211 const X& get_subtable () const
Behdad Esfahbod858b6272019-12-10 13:18:32 -06003212 { return this + reinterpret_cast<const LOffsetTo<typename T::SubTable> &> (extensionOffset); }
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003213
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -07003214 template <typename context_t, typename ...Ts>
Behdad Esfahbod83e3eab2019-05-07 20:58:43 -07003215 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003216 {
3217 TRACE_DISPATCH (this, format);
Behdad Esfahbodf396fbb2015-10-09 12:25:55 -04003218 if (unlikely (!c->may_dispatch (this, this))) return_trace (c->no_dispatch_return_value ());
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -07003219 return_trace (get_subtable<typename T::SubTable> ().dispatch (c, get_type (), hb_forward<Ts> (ds)...));
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003220 }
3221
Qunxin Liu8200e482020-02-26 13:11:42 -08003222 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
3223 { dispatch (c); }
3224
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003225 /* This is called from may_dispatch() above with hb_sanitize_context_t. */
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303226 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03003227 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05003228 TRACE_SANITIZE (this);
Behdad Esfahbod949f6af2018-01-15 20:44:10 -05003229 return_trace (c->check_struct (this) &&
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07003230 extensionLookupType != T::SubTable::Extension);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04003231 }
3232
Garret Rieger08a49972020-10-06 13:02:12 -07003233 bool subset (hb_subset_context_t *c) const
3234 {
3235 TRACE_SUBSET (this);
3236
3237 auto *out = c->serializer->start_embed (this);
3238 if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
3239
3240 out->format = format;
3241 out->extensionLookupType = extensionLookupType;
3242
3243 const auto& src_offset =
3244 reinterpret_cast<const LOffsetTo<typename T::SubTable> &> (extensionOffset);
3245 auto& dest_offset =
3246 reinterpret_cast<LOffsetTo<typename T::SubTable> &> (out->extensionOffset);
3247
3248 return_trace (dest_offset.serialize_subset (c, src_offset, this, get_type ()));
3249 }
3250
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04003251 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01003252 HBUINT16 format; /* Format identifier. Set to 1. */
3253 HBUINT16 extensionLookupType; /* Lookup type of subtable referenced
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003254 * by ExtensionOffset (i.e. the
3255 * extension subtable). */
Behdad Esfahbodcd9bc732019-05-10 13:17:41 -07003256 Offset32 extensionOffset; /* Offset to the extension subtable,
Behdad Esfahbod81f2af42010-04-22 00:58:49 -04003257 * of lookup type subtable. */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04003258 public:
3259 DEFINE_SIZE_STATIC (8);
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003260};
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003261
Behdad Esfahbod653eeb22012-11-23 16:57:36 -05003262template <typename T>
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003263struct Extension
3264{
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303265 unsigned int get_type () const
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003266 {
3267 switch (u.format) {
Behdad Esfahboddacebca2010-05-10 19:45:41 -04003268 case 1: return u.format1.get_type ();
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003269 default:return 0;
3270 }
3271 }
Behdad Esfahbod7dddd4e2012-11-23 17:04:55 -05003272 template <typename X>
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303273 const X& get_subtable () const
Behdad Esfahbod7dddd4e2012-11-23 17:04:55 -05003274 {
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003275 switch (u.format) {
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07003276 case 1: return u.format1.template get_subtable<typename T::SubTable> ();
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04303277 default:return Null (typename T::SubTable);
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003278 }
Behdad Esfahbod7dddd4e2012-11-23 17:04:55 -05003279 }
3280
Garret Rieger08a49972020-10-06 13:02:12 -07003281 // Specialization of dispatch for subset. dispatch() normally just
3282 // dispatches to the sub table this points too, but for subset
3283 // we need to run subset on this subtable too.
3284 template <typename ...Ts>
3285 typename hb_subset_context_t::return_t dispatch (hb_subset_context_t *c, Ts&&... ds) const
3286 {
3287 switch (u.format) {
3288 case 1: return u.format1.subset (c);
3289 default: return c->default_return_value ();
3290 }
3291 }
3292
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -07003293 template <typename context_t, typename ...Ts>
Behdad Esfahbod83e3eab2019-05-07 20:58:43 -07003294 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
Behdad Esfahbod653eeb22012-11-23 16:57:36 -05003295 {
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003296 TRACE_DISPATCH (this, u.format);
Behdad Esfahbodf396fbb2015-10-09 12:25:55 -04003297 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04003298 switch (u.format) {
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -07003299 case 1: return_trace (u.format1.dispatch (c, hb_forward<Ts> (ds)...));
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003300 default:return_trace (c->default_return_value ());
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04003301 }
3302 }
3303
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04003304 protected:
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003305 union {
Behdad Esfahbod6b191782018-01-10 03:07:30 +01003306 HBUINT16 format; /* Format identifier */
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003307 ExtensionFormat1<T> format1;
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003308 } u;
3309};
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003310
3311
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04003312/*
3313 * GSUB/GPOS Common
3314 */
3315
Behdad Esfahbod97e59132018-10-10 11:41:05 -04003316struct hb_ot_layout_lookup_accelerator_t
3317{
3318 template <typename TLookup>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303319 void init (const TLookup &lookup)
Behdad Esfahbod97e59132018-10-10 11:41:05 -04003320 {
3321 digest.init ();
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07003322 lookup.collect_coverage (&digest);
Behdad Esfahbod78c09bf2018-10-10 11:50:46 -04003323
3324 subtables.init ();
3325 OT::hb_get_subtables_context_t c_get_subtables (subtables);
3326 lookup.dispatch (&c_get_subtables);
Behdad Esfahbod97e59132018-10-10 11:41:05 -04003327 }
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303328 void fini () { subtables.fini (); }
Behdad Esfahbod97e59132018-10-10 11:41:05 -04003329
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303330 bool may_have (hb_codepoint_t g) const
Behdad Esfahbod97e59132018-10-10 11:41:05 -04003331 { return digest.may_have (g); }
3332
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303333 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbode78549e2018-10-10 11:54:48 -04003334 {
Behdad Esfahbod474a1202018-12-21 18:46:51 -05003335 for (unsigned int i = 0; i < subtables.length; i++)
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03303336 if (subtables[i].apply (c))
3337 return true;
3338 return false;
Behdad Esfahbode78549e2018-10-10 11:54:48 -04003339 }
3340
3341 private:
Behdad Esfahbod97e59132018-10-10 11:41:05 -04003342 hb_set_digest_t digest;
Behdad Esfahbod78c09bf2018-10-10 11:50:46 -04003343 hb_get_subtables_context_t::array_t subtables;
Behdad Esfahbod97e59132018-10-10 11:41:05 -04003344};
3345
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04003346struct GSUBGPOS
3347{
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303348 bool has_data () const { return version.to_int (); }
3349 unsigned int get_script_count () const
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04003350 { return (this+scriptList).len; }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303351 const Tag& get_script_tag (unsigned int i) const
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04003352 { return (this+scriptList).get_tag (i); }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303353 unsigned int get_script_tags (unsigned int start_offset,
3354 unsigned int *script_count /* IN/OUT */,
3355 hb_tag_t *script_tags /* OUT */) const
Behdad Esfahbode21899b2009-11-04 16:36:14 -05003356 { return (this+scriptList).get_tags (start_offset, script_count, script_tags); }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303357 const Script& get_script (unsigned int i) const
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04003358 { return (this+scriptList)[i]; }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303359 bool find_script_index (hb_tag_t tag, unsigned int *index) const
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04003360 { return (this+scriptList).find_index (tag, index); }
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04003361
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303362 unsigned int get_feature_count () const
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04003363 { return (this+featureList).len; }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303364 hb_tag_t get_feature_tag (unsigned int i) const
Jonathan Kewda132932014-04-27 14:05:24 +01003365 { return i == Index::NOT_FOUND_INDEX ? HB_TAG_NONE : (this+featureList).get_tag (i); }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303366 unsigned int get_feature_tags (unsigned int start_offset,
3367 unsigned int *feature_count /* IN/OUT */,
3368 hb_tag_t *feature_tags /* OUT */) const
Behdad Esfahbode21899b2009-11-04 16:36:14 -05003369 { return (this+featureList).get_tags (start_offset, feature_count, feature_tags); }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303370 const Feature& get_feature (unsigned int i) const
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04003371 { return (this+featureList)[i]; }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303372 bool find_feature_index (hb_tag_t tag, unsigned int *index) const
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04003373 { return (this+featureList).find_index (tag, index); }
3374
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303375 unsigned int get_lookup_count () const
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04003376 { return (this+lookupList).len; }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303377 const Lookup& get_lookup (unsigned int i) const
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04003378 { return (this+lookupList)[i]; }
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04003379
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303380 bool find_variations_index (const int *coords, unsigned int num_coords,
3381 unsigned int *index) const
Behdad Esfahboda8498732019-06-19 19:26:22 -07003382 {
Qunxin Liu0b39c482019-10-22 16:00:43 -07003383#ifdef HB_NO_VAR
Ebrahim Byagowi2e1bf612020-03-26 22:59:26 +04303384 *index = FeatureVariations::NOT_FOUND_INDEX;
Behdad Esfahboda8498732019-06-19 19:26:22 -07003385 return false;
3386#endif
Ebrahim Byagowi071e2e32020-03-26 12:01:53 +04303387 return (version.to_int () >= 0x00010001u ? this+featureVars : Null (FeatureVariations))
Behdad Esfahboda8498732019-06-19 19:26:22 -07003388 .find_index (coords, num_coords, index);
3389 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303390 const Feature& get_feature_variation (unsigned int feature_index,
Behdad Esfahbod3d9a6e62019-01-22 12:02:06 +01003391 unsigned int variations_index) const
Behdad Esfahbodec87ba92016-09-10 03:53:11 -07003392 {
Behdad Esfahboda8498732019-06-19 19:26:22 -07003393#ifndef HB_NO_VAR
Behdad Esfahbodec87ba92016-09-10 03:53:11 -07003394 if (FeatureVariations::NOT_FOUND_INDEX != variations_index &&
3395 version.to_int () >= 0x00010001u)
3396 {
Behdad Esfahbod4ebbeb72016-09-10 04:52:34 -07003397 const Feature *feature = (this+featureVars).find_substitute (variations_index,
3398 feature_index);
Behdad Esfahbodec87ba92016-09-10 03:53:11 -07003399 if (feature)
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03303400 return *feature;
Behdad Esfahbodec87ba92016-09-10 03:53:11 -07003401 }
Behdad Esfahboda8498732019-06-19 19:26:22 -07003402#endif
Behdad Esfahbodec87ba92016-09-10 03:53:11 -07003403 return get_feature (feature_index);
3404 }
Behdad Esfahbod59055b52016-09-10 01:24:28 -07003405
Qunxin Liu0b39c482019-10-22 16:00:43 -07003406 void feature_variation_collect_lookups (const hb_set_t *feature_indexes,
3407 hb_set_t *lookup_indexes /* OUT */) const
3408 {
3409#ifndef HB_NO_VAR
3410 if (version.to_int () >= 0x00010001u)
3411 (this+featureVars).collect_lookups (feature_indexes, lookup_indexes);
3412#endif
3413 }
3414
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07003415 template <typename TLookup>
Qunxin Liu973c47f2020-06-11 11:27:57 -07003416 void closure_lookups (hb_face_t *face,
3417 const hb_set_t *glyphs,
Ebrahim Byagowi5a7cc7f2020-07-29 08:33:32 +04303418 hb_set_t *lookup_indexes /* IN/OUT */) const
Qunxin Liu973c47f2020-06-11 11:27:57 -07003419 {
3420 hb_set_t visited_lookups, inactive_lookups;
3421 OT::hb_closure_lookups_context_t c (face, glyphs, &visited_lookups, &inactive_lookups);
3422
3423 for (unsigned lookup_index : + hb_iter (lookup_indexes))
3424 reinterpret_cast<const TLookup &> (get_lookup (lookup_index)).closure_lookups (&c, lookup_index);
3425
3426 hb_set_union (lookup_indexes, &visited_lookups);
3427 hb_set_subtract (lookup_indexes, &inactive_lookups);
3428 }
3429
3430 template <typename TLookup>
Qunxin Liue565d1f2019-11-01 10:21:36 -07003431 bool subset (hb_subset_layout_context_t *c) const
Behdad Esfahbodbfa72a92018-09-01 18:34:50 -07003432 {
3433 TRACE_SUBSET (this);
Qunxin Liue565d1f2019-11-01 10:21:36 -07003434 auto *out = c->subset_context->serializer->embed (*this);
Behdad Esfahbodbfa72a92018-09-01 18:34:50 -07003435 if (unlikely (!out)) return_trace (false);
Behdad Esfahbod1b6d0c42018-12-13 18:10:48 -05003436
Qunxin Liue565d1f2019-11-01 10:21:36 -07003437 typedef LookupOffsetList<TLookup> TLookupList;
Behdad Esfahbod858b6272019-12-10 13:18:32 -06003438 reinterpret_cast<OffsetTo<TLookupList> &> (out->lookupList)
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04303439 .serialize_subset (c->subset_context,
Qunxin Liue565d1f2019-11-01 10:21:36 -07003440 reinterpret_cast<const OffsetTo<TLookupList> &> (lookupList),
3441 this,
Qunxin Liue565d1f2019-11-01 10:21:36 -07003442 c);
3443
3444 reinterpret_cast<OffsetTo<RecordListOfFeature> &> (out->featureList)
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04303445 .serialize_subset (c->subset_context,
Qunxin Liue565d1f2019-11-01 10:21:36 -07003446 reinterpret_cast<const OffsetTo<RecordListOfFeature> &> (featureList),
3447 this,
Qunxin Liue565d1f2019-11-01 10:21:36 -07003448 c);
3449
3450 out->scriptList.serialize_subset (c->subset_context,
3451 scriptList,
3452 this,
Qunxin Liue565d1f2019-11-01 10:21:36 -07003453 c);
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07003454
Behdad Esfahboda8498732019-06-19 19:26:22 -07003455#ifndef HB_NO_VAR
Behdad Esfahbodbfa72a92018-09-01 18:34:50 -07003456 if (version.to_int () >= 0x00010001u)
Qunxin Liue565d1f2019-11-01 10:21:36 -07003457 {
ariza188a0a42020-03-07 11:02:36 -08003458 bool ret = out->featureVars.serialize_subset (c->subset_context, featureVars, this, c);
Qunxin Liue565d1f2019-11-01 10:21:36 -07003459 if (!ret)
3460 {
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04303461 out->version.major = 1;
3462 out->version.minor = 0;
Qunxin Liue565d1f2019-11-01 10:21:36 -07003463 }
3464 }
Behdad Esfahboda8498732019-06-19 19:26:22 -07003465#endif
Behdad Esfahbod1b6d0c42018-12-13 18:10:48 -05003466
Behdad Esfahbodbfa72a92018-09-01 18:34:50 -07003467 return_trace (true);
3468 }
3469
Garret Rieger718bf5a2020-09-29 13:16:01 -07003470 void prune_features (const hb_map_t *lookup_indices, /* IN */
3471 hb_set_t *feature_indices /* IN/OUT */) const
Qunxin Liu8ffc9ad2019-10-31 15:59:02 -07003472 {
Garret Rieger718bf5a2020-09-29 13:16:01 -07003473#ifndef HB_NO_VAR
3474 // This is the set of feature indices which have alternate versions defined
3475 // if the FeatureVariation's table and the alternate version(s) intersect the
3476 // set of lookup indices.
3477 hb_set_t alternate_feature_indices;
3478 if (version.to_int () >= 0x00010001u)
3479 (this+featureVars).closure_features (lookup_indices, &alternate_feature_indices);
Behdad Esfahbodd7e2a512021-02-11 10:55:03 -07003480 if (unlikely (alternate_feature_indices.in_error())) {
Garret Rieger718bf5a2020-09-29 13:16:01 -07003481 feature_indices->successful = false;
3482 return;
3483 }
3484#endif
3485
3486 for (unsigned i : feature_indices->iter())
Qunxin Liu8ffc9ad2019-10-31 15:59:02 -07003487 {
Qunxin Liud7c012a2020-02-26 13:11:42 -08003488 const Feature& f = get_feature (i);
Garret Rieger718bf5a2020-09-29 13:16:01 -07003489
3490 if (f.featureParams.is_null ()
Behdad Esfahbod29025292021-03-02 15:05:22 -07003491 && !f.intersects_lookup_indexes (lookup_indices)
3492#ifndef HB_NO_VAR
3493 && !alternate_feature_indices.has (i)
3494#endif
3495 )
3496 feature_indices->del (i);
Qunxin Liu8ffc9ad2019-10-31 15:59:02 -07003497 }
Qunxin Liu8ffc9ad2019-10-31 15:59:02 -07003498 }
3499
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303500 unsigned int get_size () const
Behdad Esfahbodbfa72a92018-09-01 18:34:50 -07003501 {
3502 return min_size +
3503 (version.to_int () >= 0x00010001u ? featureVars.static_size : 0);
3504 }
3505
Behdad Esfahbod6d618522018-09-03 16:41:28 -07003506 template <typename TLookup>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303507 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03003508 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05003509 TRACE_SANITIZE (this);
Behdad Esfahbod6d618522018-09-03 16:41:28 -07003510 typedef OffsetListOf<TLookup> TLookupList;
Behdad Esfahbod8e3cde62019-06-19 19:58:24 -07003511 if (unlikely (!(version.sanitize (c) &&
3512 likely (version.major == 1) &&
3513 scriptList.sanitize (c, this) &&
3514 featureList.sanitize (c, this) &&
Behdad Esfahbod858b6272019-12-10 13:18:32 -06003515 reinterpret_cast<const OffsetTo<TLookupList> &> (lookupList).sanitize (c, this))))
Behdad Esfahbod8e3cde62019-06-19 19:58:24 -07003516 return_trace (false);
3517
Behdad Esfahboda8498732019-06-19 19:26:22 -07003518#ifndef HB_NO_VAR
Behdad Esfahbod8e3cde62019-06-19 19:58:24 -07003519 if (unlikely (!(version.to_int () < 0x00010001u || featureVars.sanitize (c, this))))
3520 return_trace (false);
Behdad Esfahboda8498732019-06-19 19:26:22 -07003521#endif
Behdad Esfahbod8e3cde62019-06-19 19:58:24 -07003522
3523 return_trace (true);
Behdad Esfahbodcd3827e2009-08-04 02:09:34 -04003524 }
3525
Behdad Esfahbod963413f2018-08-26 00:47:55 -07003526 template <typename T>
3527 struct accelerator_t
3528 {
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303529 void init (hb_face_t *face)
Behdad Esfahbod963413f2018-08-26 00:47:55 -07003530 {
Ebrahim Byagowiba22df32020-03-10 10:42:20 +03303531 this->table = hb_sanitize_context_t ().reference_table<T> (face);
Behdad Esfahbod56719472020-06-05 12:57:23 -07003532 if (unlikely (this->table->is_blocklisted (this->table.get_blob (), face)))
Behdad Esfahbod574d8882018-11-25 16:51:22 -05003533 {
3534 hb_blob_destroy (this->table.get_blob ());
3535 this->table = hb_blob_get_empty ();
3536 }
Behdad Esfahbod963413f2018-08-26 00:47:55 -07003537
Behdad Esfahbodb9291002018-08-26 01:15:47 -07003538 this->lookup_count = table->get_lookup_count ();
Behdad Esfahbod963413f2018-08-26 00:47:55 -07003539
3540 this->accels = (hb_ot_layout_lookup_accelerator_t *) calloc (this->lookup_count, sizeof (hb_ot_layout_lookup_accelerator_t));
3541 if (unlikely (!this->accels))
Dominik Röttschesa5f6f862020-10-23 14:25:05 +03003542 {
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03303543 this->lookup_count = 0;
Behdad Esfahbod53806e52020-11-25 11:51:37 -07003544 this->table.destroy ();
Dominik Röttschesa5f6f862020-10-23 14:25:05 +03003545 this->table = hb_blob_get_empty ();
3546 }
Behdad Esfahbod963413f2018-08-26 00:47:55 -07003547
3548 for (unsigned int i = 0; i < this->lookup_count; i++)
Behdad Esfahbodb9291002018-08-26 01:15:47 -07003549 this->accels[i].init (table->get_lookup (i));
Behdad Esfahbod963413f2018-08-26 00:47:55 -07003550 }
3551
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303552 void fini ()
Behdad Esfahbod963413f2018-08-26 00:47:55 -07003553 {
Behdad Esfahbodb9291002018-08-26 01:15:47 -07003554 for (unsigned int i = 0; i < this->lookup_count; i++)
3555 this->accels[i].fini ();
3556 free (this->accels);
Behdad Esfahbodda6aa3b2018-11-11 11:40:57 -05003557 this->table.destroy ();
Behdad Esfahbod963413f2018-08-26 00:47:55 -07003558 }
3559
Behdad Esfahbod5d0078a2018-11-10 23:52:15 -05003560 hb_blob_ptr_t<T> table;
Behdad Esfahbodb9291002018-08-26 01:15:47 -07003561 unsigned int lookup_count;
3562 hb_ot_layout_lookup_accelerator_t *accels;
Behdad Esfahbod963413f2018-08-26 00:47:55 -07003563 };
3564
Behdad Esfahbod212aba62009-05-24 00:50:27 -04003565 protected:
Behdad Esfahbod9a13ed42016-02-22 11:44:45 +09003566 FixedVersion<>version; /* Version of the GSUB/GPOS table--initially set
Behdad Esfahbod76271002014-07-11 14:54:42 -04003567 * to 0x00010000u */
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04003568 OffsetTo<ScriptList>
Ebrahim Byagowice114d62019-12-31 15:53:02 +03303569 scriptList; /* ScriptList table */
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04003570 OffsetTo<FeatureList>
Ebrahim Byagowice114d62019-12-31 15:53:02 +03303571 featureList; /* FeatureList table */
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04003572 OffsetTo<LookupList>
Ebrahim Byagowice114d62019-12-31 15:53:02 +03303573 lookupList; /* LookupList table */
Behdad Esfahbod5e156fa2017-01-22 20:28:56 -08003574 LOffsetTo<FeatureVariations>
Behdad Esfahbod59055b52016-09-10 01:24:28 -07003575 featureVars; /* Offset to Feature Variations
3576 table--from beginning of table
3577 * (may be NULL). Introduced
3578 * in version 0x00010001. */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04003579 public:
Behdad Esfahbod59055b52016-09-10 01:24:28 -07003580 DEFINE_SIZE_MIN (10);
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04003581};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04003582
Behdad Esfahbod6f20f722009-05-17 20:28:01 -04003583
Behdad Esfahbod7d52e662012-11-16 18:49:54 -08003584} /* namespace OT */
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -04003585
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04003586
Behdad Esfahbodc77ae402018-08-25 22:36:36 -07003587#endif /* HB_OT_LAYOUT_GSUBGPOS_HH */