blob: f52a9483602cf6a20ce4ebb799d76ecbea0bfe10 [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 :
45 hb_dispatch_context_t<hb_intersects_context_t, bool, 0>
46{
Ebrahim Byagowie4120082018-12-17 21:31:01 +033047 const char *get_name () { return "INTERSECTS"; }
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -070048 template <typename T>
Behdad Esfahbodc14efb82019-05-05 09:54:58 -070049 return_t dispatch (const T &obj) { return obj.intersects (this->glyphs); }
Ebrahim Byagowie4120082018-12-17 21:31:01 +033050 static return_t default_return_value () { return false; }
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -070051 bool stop_sublookup_iteration (return_t r) const { return r; }
52
53 const hb_set_t *glyphs;
54 unsigned int debug_depth;
55
56 hb_intersects_context_t (const hb_set_t *glyphs_) :
57 glyphs (glyphs_),
58 debug_depth (0) {}
59};
60
Behdad Esfahbod77a1a2b2015-10-09 12:20:58 -040061struct hb_closure_context_t :
Behdad Esfahbod7df3ecf2019-05-10 20:43:26 -070062 hb_dispatch_context_t<hb_closure_context_t, hb_empty_t, 0>
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -040063{
Ebrahim Byagowie4120082018-12-17 21:31:01 +033064 const char *get_name () { return "CLOSURE"; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -050065 typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
66 template <typename T>
Behdad Esfahbod7df3ecf2019-05-10 20:43:26 -070067 return_t dispatch (const T &obj) { obj.closure (this); return hb_empty_t (); }
68 static return_t default_return_value () { return hb_empty_t (); }
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -070069 void recurse (unsigned int lookup_index)
Behdad Esfahbod44fc2372012-11-21 23:33:13 -050070 {
Behdad Esfahbod9b346772012-11-23 17:55:40 -050071 if (unlikely (nesting_level_left == 0 || !recurse_func))
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -070072 return;
Behdad Esfahbod44fc2372012-11-21 23:33:13 -050073
74 nesting_level_left--;
75 recurse_func (this, lookup_index);
76 nesting_level_left++;
Behdad Esfahbod44fc2372012-11-21 23:33:13 -050077 }
78
Garret Rieger4ad686b2020-03-25 23:32:28 -070079 bool lookup_limit_exceeded ()
Ebrahim Byagowi1a482782020-03-26 11:15:09 +043080 { return lookup_count > HB_MAX_LOOKUP_INDICES; }
Garret Rieger4ad686b2020-03-25 23:32:28 -070081
Behdad Esfahbodba0ea562018-06-11 23:24:41 -040082 bool should_visit_lookup (unsigned int lookup_index)
Garret Rieger45186b92018-06-05 17:14:42 -070083 {
Garret Rieger834a2242020-03-12 03:02:36 -070084 if (lookup_count++ > HB_MAX_LOOKUP_INDICES)
85 return false;
86
Garret Rieger45186b92018-06-05 17:14:42 -070087 if (is_lookup_done (lookup_index))
88 return false;
Garret Rieger834a2242020-03-12 03:02:36 -070089
Garret Rieger45186b92018-06-05 17:14:42 -070090 done_lookups->set (lookup_index, glyphs->get_population ());
91 return true;
92 }
93
94 bool is_lookup_done (unsigned int lookup_index)
95 {
Behdad Esfahbodc38bd402018-07-24 09:43:27 -070096 /* Have we visited this lookup with the current set of glyphs? */
Garret Rieger45186b92018-06-05 17:14:42 -070097 return done_lookups->get (lookup_index) == glyphs->get_population ();
98 }
99
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400100 hb_face_t *face;
Behdad Esfahbod6a9be5b2012-04-23 22:23:17 -0400101 hb_set_t *glyphs;
Behdad Esfahbodede1a712019-01-09 10:45:53 -0800102 hb_set_t output[1];
Behdad Esfahbod44fc2372012-11-21 23:33:13 -0500103 recurse_func_t recurse_func;
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400104 unsigned int nesting_level_left;
105 unsigned int debug_depth;
106
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400107 hb_closure_context_t (hb_face_t *face_,
Behdad Esfahbod6a9be5b2012-04-23 22:23:17 -0400108 hb_set_t *glyphs_,
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330109 hb_map_t *done_lookups_,
110 unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400111 face (face_),
112 glyphs (glyphs_),
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200113 recurse_func (nullptr),
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400114 nesting_level_left (nesting_level_left_),
Behdad Esfahboda7e1b4a2018-06-11 22:05:08 -0400115 debug_depth (0),
Garret Rieger834a2242020-03-12 03:02:36 -0700116 done_lookups (done_lookups_),
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +0430117 lookup_count (0)
Garret Rieger834a2242020-03-12 03:02:36 -0700118 {}
Behdad Esfahbod9b346772012-11-23 17:55:40 -0500119
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330120 ~hb_closure_context_t () { flush (); }
Behdad Esfahbodc38bd402018-07-24 09:43:27 -0700121
Behdad Esfahbod9b346772012-11-23 17:55:40 -0500122 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
Garret Rieger45186b92018-06-05 17:14:42 -0700123
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330124 void flush ()
Behdad Esfahbodc38bd402018-07-24 09:43:27 -0700125 {
Michiharu Arizaff5223b2020-02-23 15:53:21 -0800126 hb_set_del_range (output, face->get_num_glyphs (), hb_set_get_max (output)); /* Remove invalid glyphs. */
Behdad Esfahbodede1a712019-01-09 10:45:53 -0800127 hb_set_union (glyphs, output);
128 hb_set_clear (output);
Behdad Esfahbodc38bd402018-07-24 09:43:27 -0700129 }
130
Garret Rieger45186b92018-06-05 17:14:42 -0700131 private:
132 hb_map_t *done_lookups;
Garret Rieger834a2242020-03-12 03:02:36 -0700133 unsigned int lookup_count;
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400134};
135
Qunxin Liu0b39c482019-10-22 16:00:43 -0700136struct hb_closure_lookups_context_t :
137 hb_dispatch_context_t<hb_closure_lookups_context_t, hb_empty_t, 0>
138{
139 const char *get_name () { return "CLOSURE_LOOKUPS"; }
140 typedef return_t (*recurse_func_t) (hb_closure_lookups_context_t *c, unsigned lookup_index);
141 template <typename T>
142 return_t dispatch (const T &obj) { obj.closure_lookups (this); return hb_empty_t (); }
143 static return_t default_return_value () { return hb_empty_t (); }
144 void recurse (unsigned lookup_index)
145 {
146 if (unlikely (nesting_level_left == 0 || !recurse_func))
147 return;
148
149 /* Return if new lookup was recursed to before. */
150 if (is_lookup_visited (lookup_index))
151 return;
152
153 set_lookup_visited (lookup_index);
154 nesting_level_left--;
155 recurse_func (this, lookup_index);
156 nesting_level_left++;
157 }
158
159 void set_lookup_visited (unsigned lookup_index)
160 { visited_lookups->add (lookup_index); }
161
162 void set_lookup_inactive (unsigned lookup_index)
163 { inactive_lookups->add (lookup_index); }
164
Garret Rieger4ad686b2020-03-25 23:32:28 -0700165 bool lookup_limit_exceeded ()
Ebrahim Byagowi1a482782020-03-26 11:15:09 +0430166 { return lookup_count > HB_MAX_LOOKUP_INDICES; }
Garret Rieger4ad686b2020-03-25 23:32:28 -0700167
Qunxin Liu0b39c482019-10-22 16:00:43 -0700168 bool is_lookup_visited (unsigned lookup_index)
Garret Rieger834a2242020-03-12 03:02:36 -0700169 {
170 if (lookup_count++ > HB_MAX_LOOKUP_INDICES)
171 return true;
172
173 return visited_lookups->has (lookup_index);
174 }
Qunxin Liu0b39c482019-10-22 16:00:43 -0700175
176 hb_face_t *face;
177 const hb_set_t *glyphs;
178 recurse_func_t recurse_func;
179 unsigned int nesting_level_left;
180 unsigned int debug_depth;
181
182 hb_closure_lookups_context_t (hb_face_t *face_,
183 const hb_set_t *glyphs_,
184 hb_set_t *visited_lookups_,
185 hb_set_t *inactive_lookups_,
186 unsigned nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
187 face (face_),
188 glyphs (glyphs_),
189 recurse_func (nullptr),
190 nesting_level_left (nesting_level_left_),
191 debug_depth (0),
192 visited_lookups (visited_lookups_),
Garret Rieger834a2242020-03-12 03:02:36 -0700193 inactive_lookups (inactive_lookups_),
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +0430194 lookup_count (0) {}
Qunxin Liu0b39c482019-10-22 16:00:43 -0700195
196 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
197
198 private:
199 hb_set_t *visited_lookups;
200 hb_set_t *inactive_lookups;
Garret Rieger834a2242020-03-12 03:02:36 -0700201 unsigned int lookup_count;
Qunxin Liu0b39c482019-10-22 16:00:43 -0700202};
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400203
Behdad Esfahbod77a1a2b2015-10-09 12:20:58 -0400204struct hb_would_apply_context_t :
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -0700205 hb_dispatch_context_t<hb_would_apply_context_t, bool, 0>
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400206{
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330207 const char *get_name () { return "WOULD_APPLY"; }
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500208 template <typename T>
Behdad Esfahbodc14efb82019-05-05 09:54:58 -0700209 return_t dispatch (const T &obj) { return obj.would_apply (this); }
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330210 static return_t default_return_value () { return false; }
Behdad Esfahbod7b912c12013-01-04 01:25:27 -0600211 bool stop_sublookup_iteration (return_t r) const { return r; }
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500212
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400213 hb_face_t *face;
Behdad Esfahbod472f2292012-08-07 22:25:24 -0400214 const hb_codepoint_t *glyphs;
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400215 unsigned int len;
Behdad Esfahbodd9b204d2012-08-23 16:22:28 -0400216 bool zero_context;
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400217 unsigned int debug_depth;
218
219 hb_would_apply_context_t (hb_face_t *face_,
Behdad Esfahbod472f2292012-08-07 22:25:24 -0400220 const hb_codepoint_t *glyphs_,
221 unsigned int len_,
Behdad Esfahbod2bd9fe32012-09-04 15:15:19 -0400222 bool zero_context_) :
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400223 face (face_),
Behdad Esfahbod472f2292012-08-07 22:25:24 -0400224 glyphs (glyphs_),
225 len (len_),
Behdad Esfahbodd9b204d2012-08-23 16:22:28 -0400226 zero_context (zero_context_),
Behdad Esfahboda1733db2012-11-23 16:40:04 -0500227 debug_depth (0) {}
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400228};
229
230
Behdad Esfahbod77a1a2b2015-10-09 12:20:58 -0400231struct hb_collect_glyphs_context_t :
Behdad Esfahbod7df3ecf2019-05-10 20:43:26 -0700232 hb_dispatch_context_t<hb_collect_glyphs_context_t, hb_empty_t, 0>
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800233{
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330234 const char *get_name () { return "COLLECT_GLYPHS"; }
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500235 typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index);
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500236 template <typename T>
Behdad Esfahbod7df3ecf2019-05-10 20:43:26 -0700237 return_t dispatch (const T &obj) { obj.collect_glyphs (this); return hb_empty_t (); }
238 static return_t default_return_value () { return hb_empty_t (); }
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700239 void recurse (unsigned int lookup_index)
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500240 {
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500241 if (unlikely (nesting_level_left == 0 || !recurse_func))
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700242 return;
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500243
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200244 /* Note that GPOS sets recurse_func to nullptr already, so it doesn't get
Behdad Esfahbod1bcfa062012-12-04 16:58:09 -0500245 * past the previous check. For GSUB, we only want to collect the output
Behdad Esfahbod76ea5632013-05-04 16:01:20 -0400246 * glyphs in the recursion. If output is not requested, we can go home now.
247 *
248 * Note further, that the above is not exactly correct. A recursed lookup
249 * is allowed to match input that is not matched in the context, but that's
250 * not how most fonts are built. It's possible to relax that and recurse
251 * with all sets here if it proves to be an issue.
252 */
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500253
254 if (output == hb_set_get_empty ())
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700255 return;
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500256
Behdad Esfahbodfde3e4a2014-10-29 11:23:08 -0700257 /* Return if new lookup was recursed to before. */
Behdad Esfahbod8b9d9b72017-10-22 17:48:06 -0400258 if (recursed_lookups->has (lookup_index))
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700259 return;
Behdad Esfahbodfde3e4a2014-10-29 11:23:08 -0700260
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500261 hb_set_t *old_before = before;
262 hb_set_t *old_input = input;
263 hb_set_t *old_after = after;
264 before = input = after = hb_set_get_empty ();
Behdad Esfahbod1bcfa062012-12-04 16:58:09 -0500265
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500266 nesting_level_left--;
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500267 recurse_func (this, lookup_index);
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500268 nesting_level_left++;
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500269
270 before = old_before;
271 input = old_input;
272 after = old_after;
273
Behdad Esfahbod8b9d9b72017-10-22 17:48:06 -0400274 recursed_lookups->add (lookup_index);
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500275 }
276
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800277 hb_face_t *face;
Behdad Esfahbod83035932012-12-04 17:08:41 -0500278 hb_set_t *before;
279 hb_set_t *input;
280 hb_set_t *after;
281 hb_set_t *output;
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500282 recurse_func_t recurse_func;
Behdad Esfahbod8b9d9b72017-10-22 17:48:06 -0400283 hb_set_t *recursed_lookups;
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500284 unsigned int nesting_level_left;
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800285 unsigned int debug_depth;
286
287 hb_collect_glyphs_context_t (hb_face_t *face_,
Ebrahim Byagowi63109432018-10-13 14:00:05 +0330288 hb_set_t *glyphs_before, /* OUT. May be NULL */
289 hb_set_t *glyphs_input, /* OUT. May be NULL */
290 hb_set_t *glyphs_after, /* OUT. May be NULL */
291 hb_set_t *glyphs_output, /* OUT. May be NULL */
Behdad Esfahbod5ba45042015-11-02 15:43:08 -0800292 unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800293 face (face_),
Behdad Esfahbod83035932012-12-04 17:08:41 -0500294 before (glyphs_before ? glyphs_before : hb_set_get_empty ()),
295 input (glyphs_input ? glyphs_input : hb_set_get_empty ()),
296 after (glyphs_after ? glyphs_after : hb_set_get_empty ()),
297 output (glyphs_output ? glyphs_output : hb_set_get_empty ()),
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200298 recurse_func (nullptr),
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700299 recursed_lookups (hb_set_create ()),
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500300 nesting_level_left (nesting_level_left_),
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700301 debug_depth (0) {}
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330302 ~hb_collect_glyphs_context_t () { hb_set_destroy (recursed_lookups); }
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500303
304 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800305};
306
307
308
Behdad Esfahbod8e36ccf2015-02-17 19:15:34 +0300309template <typename set_t>
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -0700310struct hb_collect_coverage_context_t :
311 hb_dispatch_context_t<hb_collect_coverage_context_t<set_t>, const Coverage &, HB_DEBUG_GET_COVERAGE>
Behdad Esfahbod2005fa52012-11-22 14:38:10 -0500312{
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330313 const char *get_name () { return "GET_COVERAGE"; }
Behdad Esfahbod2005fa52012-11-22 14:38:10 -0500314 typedef const Coverage &return_t;
315 template <typename T>
Behdad Esfahbodc14efb82019-05-05 09:54:58 -0700316 return_t dispatch (const T &obj) { return obj.get_coverage (); }
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +0430317 static return_t default_return_value () { return Null (Coverage); }
Behdad Esfahbod8e36ccf2015-02-17 19:15:34 +0300318 bool stop_sublookup_iteration (return_t r) const
319 {
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -0700320 r.collect_coverage (set);
Behdad Esfahbod8e36ccf2015-02-17 19:15:34 +0300321 return false;
322 }
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500323
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -0700324 hb_collect_coverage_context_t (set_t *set_) :
325 set (set_),
326 debug_depth (0) {}
Behdad Esfahboda1733db2012-11-23 16:40:04 -0500327
Behdad Esfahbod8e36ccf2015-02-17 19:15:34 +0300328 set_t *set;
Behdad Esfahboda1733db2012-11-23 16:40:04 -0500329 unsigned int debug_depth;
Behdad Esfahbod2005fa52012-11-22 14:38:10 -0500330};
331
332
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800333struct hb_ot_apply_context_t :
334 hb_dispatch_context_t<hb_ot_apply_context_t, bool, HB_DEBUG_APPLY>
Behdad Esfahbod1376fb72010-04-29 02:19:21 -0400335{
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500336 struct matcher_t
337 {
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330338 matcher_t () :
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500339 lookup_props (0),
Behdad Esfahbodcfc507c2013-02-14 10:40:12 -0500340 ignore_zwnj (false),
341 ignore_zwj (false),
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500342 mask (-1),
343#define arg1(arg) (arg) /* Remove the macro to see why it's needed! */
344 syllable arg1(0),
345#undef arg1
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200346 match_func (nullptr),
Ebrahim Byagowif7a08cd2018-10-30 11:29:09 +0330347 match_data (nullptr) {}
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500348
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100349 typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500350
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330351 void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; }
352 void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
353 void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
354 void set_mask (hb_mask_t mask_) { mask = mask_; }
355 void set_syllable (uint8_t syllable_) { syllable = syllable_; }
356 void set_match_func (match_func_t match_func_,
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500357 const void *match_data_)
358 { match_func = match_func_; match_data = match_data_; }
359
Behdad Esfahbod2b2a6e82013-02-21 15:07:03 -0500360 enum may_match_t {
361 MATCH_NO,
362 MATCH_YES,
363 MATCH_MAYBE
364 };
365
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330366 may_match_t may_match (const hb_glyph_info_t &info,
Behdad Esfahbod085793d2019-04-24 10:15:59 -0400367 const HBUINT16 *glyph_data) const
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500368 {
Behdad Esfahbod2b2a6e82013-02-21 15:07:03 -0500369 if (!(info.mask & mask) ||
370 (syllable && syllable != info.syllable ()))
371 return MATCH_NO;
372
373 if (match_func)
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330374 return match_func (info.codepoint, *glyph_data, match_data) ? MATCH_YES : MATCH_NO;
Behdad Esfahbod2b2a6e82013-02-21 15:07:03 -0500375
376 return MATCH_MAYBE;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500377 }
378
379 enum may_skip_t {
380 SKIP_NO,
381 SKIP_YES,
382 SKIP_MAYBE
383 };
384
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330385 may_skip_t may_skip (const hb_ot_apply_context_t *c,
386 const hb_glyph_info_t &info) const
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500387 {
Behdad Esfahbodb98c5db2014-07-16 13:44:01 -0400388 if (!c->check_glyph_property (&info, lookup_props))
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500389 return SKIP_YES;
390
Khaled Hosny06cfe3f2017-05-17 21:32:47 +0300391 if (unlikely (_hb_glyph_info_is_default_ignorable_and_not_hidden (&info) &&
Behdad Esfahbod0b454792013-02-14 10:46:52 -0500392 (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) &&
Behdad Esfahbod4ba796b2015-07-22 17:41:31 +0100393 (ignore_zwj || !_hb_glyph_info_is_zwj (&info))))
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500394 return SKIP_MAYBE;
395
396 return SKIP_NO;
397 }
398
399 protected:
400 unsigned int lookup_props;
401 bool ignore_zwnj;
Behdad Esfahbod0b454792013-02-14 10:46:52 -0500402 bool ignore_zwj;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500403 hb_mask_t mask;
404 uint8_t syllable;
405 match_func_t match_func;
406 const void *match_data;
407 };
408
Behdad Esfahbod69626692015-01-29 13:08:41 +0100409 struct skipping_iterator_t
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500410 {
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330411 void init (hb_ot_apply_context_t *c_, bool context_match = false)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500412 {
Behdad Esfahbod514564f2015-01-29 13:48:48 +0100413 c = c_;
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200414 match_glyph_data = nullptr;
415 matcher.set_match_func (nullptr, nullptr);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500416 matcher.set_lookup_props (c->lookup_props);
Behdad Esfahbod3583fb02018-09-23 22:33:38 -0400417 /* Ignore ZWNJ if we are matching GPOS, or matching GSUB context and asked to. */
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100418 matcher.set_ignore_zwnj (c->table_index == 1 || (context_match && c->auto_zwnj));
Behdad Esfahbod3583fb02018-09-23 22:33:38 -0400419 /* Ignore ZWJ if we are matching context, or asked to. */
420 matcher.set_ignore_zwj (context_match || c->auto_zwj);
Behdad Esfahbod514564f2015-01-29 13:48:48 +0100421 matcher.set_mask (context_match ? -1 : c->lookup_mask);
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500422 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330423 void set_lookup_props (unsigned int lookup_props)
Behdad Esfahbod514564f2015-01-29 13:48:48 +0100424 {
425 matcher.set_lookup_props (lookup_props);
426 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330427 void set_match_func (matcher_t::match_func_t match_func_,
428 const void *match_data_,
429 const HBUINT16 glyph_data[])
Behdad Esfahbodc074ebc2013-02-13 11:22:42 -0500430 {
Behdad Esfahbod4a6b1ee2015-10-21 11:20:55 -0200431 matcher.set_match_func (match_func_, match_data_);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500432 match_glyph_data = glyph_data;
Behdad Esfahbodc074ebc2013-02-13 11:22:42 -0500433 }
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500434
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330435 void reset (unsigned int start_index_,
Ebrahim Byagowi08428a12020-04-24 23:45:17 +0430436 unsigned int num_items_)
Behdad Esfahbodb051be52015-01-29 13:40:39 +0100437 {
438 idx = start_index_;
439 num_items = num_items_;
440 end = c->buffer->len;
441 matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
442 }
443
Ebrahim Byagowi64a45be2019-11-09 12:25:33 +0330444 void reject ()
445 {
446 num_items++;
447 if (match_glyph_data) match_glyph_data--;
448 }
Behdad Esfahbod69626692015-01-29 13:08:41 +0100449
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330450 matcher_t::may_skip_t
451 may_skip (const hb_glyph_info_t &info) const
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330452 { return matcher.may_skip (c, info); }
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200453
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330454 bool next ()
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500455 {
Behdad Esfahbod506ffeb2012-01-18 16:07:53 -0500456 assert (num_items > 0);
Behdad Esfahbod37d13ac2015-01-29 11:38:01 +0100457 while (idx + num_items < end)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500458 {
Behdad Esfahboda4a48fe2012-01-17 18:08:41 -0500459 idx++;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500460 const hb_glyph_info_t &info = c->buffer->info[idx];
461
Behdad Esfahbodff93ac82013-02-21 14:51:40 -0500462 matcher_t::may_skip_t skip = matcher.may_skip (c, info);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500463 if (unlikely (skip == matcher_t::SKIP_YES))
464 continue;
465
Behdad Esfahbod2b2a6e82013-02-21 15:07:03 -0500466 matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
Behdad Esfahbod722e8b82013-02-21 15:37:51 -0500467 if (match == matcher_t::MATCH_YES ||
468 (match == matcher_t::MATCH_MAYBE &&
469 skip == matcher_t::SKIP_NO))
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500470 {
471 num_items--;
Ebrahim Byagowiaca63902019-10-22 00:06:46 +0330472 if (match_glyph_data) match_glyph_data++;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500473 return true;
474 }
475
476 if (skip == matcher_t::SKIP_NO)
Behdad Esfahbod722e8b82013-02-21 15:37:51 -0500477 return false;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500478 }
479 return false;
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500480 }
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330481 bool prev ()
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500482 {
Behdad Esfahbod506ffeb2012-01-18 16:07:53 -0500483 assert (num_items > 0);
Behdad Esfahbod18a06f82018-07-05 14:03:48 +0430484 while (idx > num_items - 1)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500485 {
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500486 idx--;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500487 const hb_glyph_info_t &info = c->buffer->out_info[idx];
488
Behdad Esfahbodff93ac82013-02-21 14:51:40 -0500489 matcher_t::may_skip_t skip = matcher.may_skip (c, info);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500490 if (unlikely (skip == matcher_t::SKIP_YES))
491 continue;
492
Behdad Esfahbod2b2a6e82013-02-21 15:07:03 -0500493 matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
Behdad Esfahbod722e8b82013-02-21 15:37:51 -0500494 if (match == matcher_t::MATCH_YES ||
495 (match == matcher_t::MATCH_MAYBE &&
496 skip == matcher_t::SKIP_NO))
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500497 {
498 num_items--;
Ebrahim Byagowiaca63902019-10-22 00:06:46 +0330499 if (match_glyph_data) match_glyph_data++;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500500 return true;
501 }
502
503 if (skip == matcher_t::SKIP_NO)
Behdad Esfahbod722e8b82013-02-21 15:37:51 -0500504 return false;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500505 }
506 return false;
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500507 }
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500508
509 unsigned int idx;
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400510 protected:
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800511 hb_ot_apply_context_t *c;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500512 matcher_t matcher;
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100513 const HBUINT16 *match_glyph_data;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500514
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500515 unsigned int num_items;
Behdad Esfahbod69626692015-01-29 13:08:41 +0100516 unsigned int end;
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500517 };
518
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100519
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330520 const char *get_name () { return "APPLY"; }
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800521 typedef return_t (*recurse_func_t) (hb_ot_apply_context_t *c, unsigned int lookup_index);
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100522 template <typename T>
Behdad Esfahbodc14efb82019-05-05 09:54:58 -0700523 return_t dispatch (const T &obj) { return obj.apply (this); }
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330524 static return_t default_return_value () { return false; }
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100525 bool stop_sublookup_iteration (return_t r) const { return r; }
Behdad Esfahbod12757b62018-01-26 18:14:05 -0800526 return_t recurse (unsigned int sub_lookup_index)
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100527 {
Behdad Esfahbodbaf77792017-11-14 21:53:48 -0800528 if (unlikely (nesting_level_left == 0 || !recurse_func || buffer->max_ops-- <= 0))
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100529 return default_return_value ();
530
531 nesting_level_left--;
Behdad Esfahbod12757b62018-01-26 18:14:05 -0800532 bool ret = recurse_func (this, sub_lookup_index);
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100533 nesting_level_left++;
534 return ret;
535 }
536
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100537 skipping_iterator_t iter_input, iter_context;
538
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100539 hb_font_t *font;
540 hb_face_t *face;
541 hb_buffer_t *buffer;
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100542 recurse_func_t recurse_func;
543 const GDEF &gdef;
544 const VariationStore &var_store;
545
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100546 hb_direction_t direction;
547 hb_mask_t lookup_mask;
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100548 unsigned int table_index; /* GSUB/GPOS */
Behdad Esfahbod2c8b3b22015-08-18 14:36:43 +0100549 unsigned int lookup_index;
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100550 unsigned int lookup_props;
551 unsigned int nesting_level_left;
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100552 unsigned int debug_depth;
553
Behdad Esfahbod80de4bc2018-09-10 16:24:52 +0200554 bool has_glyph_classes;
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100555 bool auto_zwnj;
556 bool auto_zwj;
David Corbettc2a75e02018-01-25 14:22:03 -0500557 bool random;
Behdad Esfahbod80de4bc2018-09-10 16:24:52 +0200558
Behdad Esfahbodcfdea882018-09-11 10:57:48 +0200559 uint32_t random_state;
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100560
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100561
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800562 hb_ot_apply_context_t (unsigned int table_index_,
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100563 hb_font_t *font_,
564 hb_buffer_t *buffer_) :
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100565 iter_input (), iter_context (),
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100566 font (font_), face (font->face), buffer (buffer_),
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200567 recurse_func (nullptr),
Behdad Esfahbod7dcf8e12019-06-26 13:44:10 -0700568 gdef (
569#ifndef HB_NO_OT_LAYOUT
570 *face->table.GDEF->table
571#else
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +0430572 Null (GDEF)
Behdad Esfahbod7dcf8e12019-06-26 13:44:10 -0700573#endif
574 ),
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100575 var_store (gdef.get_var_store ()),
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100576 direction (buffer_->props.direction),
577 lookup_mask (1),
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100578 table_index (table_index_),
Behdad Esfahbod2c8b3b22015-08-18 14:36:43 +0100579 lookup_index ((unsigned int) -1),
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100580 lookup_props (0),
581 nesting_level_left (HB_MAX_NESTING_LEVEL),
582 debug_depth (0),
Behdad Esfahbod80de4bc2018-09-10 16:24:52 +0200583 has_glyph_classes (gdef.has_glyph_classes ()),
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100584 auto_zwnj (true),
585 auto_zwj (true),
David Corbettc2a75e02018-01-25 14:22:03 -0500586 random (false),
Behdad Esfahbodd748dc72018-09-24 18:30:50 -0400587 random_state (1) { init_iters (); }
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100588
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330589 void init_iters ()
Behdad Esfahbod365576d2015-01-29 13:59:42 +0100590 {
Behdad Esfahbod365576d2015-01-29 13:59:42 +0100591 iter_input.init (this, false);
592 iter_context.init (this, true);
593 }
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100594
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330595 void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; init_iters (); }
596 void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; init_iters (); }
597 void set_auto_zwnj (bool auto_zwnj_) { auto_zwnj = auto_zwnj_; init_iters (); }
598 void set_random (bool random_) { random = random_; }
599 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
600 void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; }
601 void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; init_iters (); }
Behdad Esfahbod9516cbd2018-09-23 22:00:34 -0400602
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330603 uint32_t random_number ()
Behdad Esfahbod08260c72018-09-11 10:51:19 +0200604 {
Behdad Esfahbodcfdea882018-09-11 10:57:48 +0200605 /* http://www.cplusplus.com/reference/random/minstd_rand/ */
606 random_state = random_state * 48271 % 2147483647;
607 return random_state;
Behdad Esfahbod08260c72018-09-11 10:51:19 +0200608 }
609
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330610 bool match_properties_mark (hb_codepoint_t glyph,
611 unsigned int glyph_props,
612 unsigned int match_props) const
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400613 {
614 /* If using mark filtering sets, the high short of
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700615 * match_props has the set index.
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400616 */
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700617 if (match_props & LookupFlag::UseMarkFilteringSet)
618 return gdef.mark_set_covers (match_props >> 16, glyph);
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400619
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700620 /* The second byte of match_props has the meaning
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400621 * "ignore marks of attachment type different than
622 * the attachment type specified."
623 */
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700624 if (match_props & LookupFlag::MarkAttachmentType)
625 return (match_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400626
627 return true;
628 }
629
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330630 bool check_glyph_property (const hb_glyph_info_t *info,
631 unsigned int match_props) const
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400632 {
Behdad Esfahbodb98c5db2014-07-16 13:44:01 -0400633 hb_codepoint_t glyph = info->codepoint;
634 unsigned int glyph_props = _hb_glyph_info_get_glyph_props (info);
635
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400636 /* Not covered, if, for example, glyph class is ligature and
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700637 * match_props includes LookupFlags::IgnoreLigatures
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400638 */
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700639 if (glyph_props & match_props & LookupFlag::IgnoreFlags)
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400640 return false;
641
Behdad Esfahbod5a08ecf2012-11-16 13:34:29 -0800642 if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK))
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700643 return match_properties_mark (glyph, glyph_props, match_props);
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400644
645 return true;
646 }
647
Behdad Esfahbodf4cd99f2020-04-22 14:45:57 -0700648 void _set_glyph_class (hb_codepoint_t glyph_index,
649 unsigned int class_guess = 0,
650 bool ligature = false,
651 bool component = false) const
Behdad Esfahbod60da7632012-07-16 16:13:32 -0400652 {
Behdad Esfahbodf4cd99f2020-04-22 14:45:57 -0700653 unsigned int props = _hb_glyph_info_get_glyph_props (&buffer->cur());
654
655 props |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED;
Behdad Esfahbod09675a82013-10-18 01:05:58 +0200656 if (ligature)
Behdad Esfahbod832a6f92014-06-04 16:57:42 -0400657 {
Behdad Esfahbodf4cd99f2020-04-22 14:45:57 -0700658 props |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED;
Behdad Esfahbod832a6f92014-06-04 16:57:42 -0400659 /* In the only place that the MULTIPLIED bit is used, Uniscribe
660 * seems to only care about the "last" transformation between
Bruce Mitchener257d0e52018-10-19 22:49:21 +0700661 * Ligature and Multiple substitutions. Ie. if you ligate, expand,
Behdad Esfahbod832a6f92014-06-04 16:57:42 -0400662 * and ligate again, it forgives the multiplication and acts as
663 * if only ligation happened. As such, clear MULTIPLIED bit.
664 */
Behdad Esfahbodf4cd99f2020-04-22 14:45:57 -0700665 props &= ~HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
Behdad Esfahbod832a6f92014-06-04 16:57:42 -0400666 }
667 if (component)
Behdad Esfahbodf4cd99f2020-04-22 14:45:57 -0700668 props |= HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
669
Behdad Esfahbod2fca1422012-07-30 18:46:41 -0400670 if (likely (has_glyph_classes))
Behdad Esfahbodf4cd99f2020-04-22 14:45:57 -0700671 props = (props & ~HB_OT_LAYOUT_GLYPH_PROPS_CLASS_MASK) | gdef.get_glyph_props (glyph_index);
Behdad Esfahbod05bd1b62012-07-30 19:30:01 -0400672 else if (class_guess)
Behdad Esfahbodf4cd99f2020-04-22 14:45:57 -0700673 props = (props & ~HB_OT_LAYOUT_GLYPH_PROPS_CLASS_MASK) | class_guess;
674
675 _hb_glyph_info_set_glyph_props (&buffer->cur(), props);
Behdad Esfahbod60da7632012-07-16 16:13:32 -0400676 }
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500677
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330678 void replace_glyph (hb_codepoint_t glyph_index) const
Behdad Esfahbod3ec77d62012-06-08 21:44:06 -0400679 {
Behdad Esfahbodf4cd99f2020-04-22 14:45:57 -0700680 _set_glyph_class (glyph_index);
Behdad Esfahbod98370e82010-10-27 17:39:01 -0400681 buffer->replace_glyph (glyph_index);
682 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330683 void replace_glyph_inplace (hb_codepoint_t glyph_index) const
Behdad Esfahbod7fbbf862012-07-30 18:36:42 -0400684 {
Behdad Esfahbodf4cd99f2020-04-22 14:45:57 -0700685 _set_glyph_class (glyph_index);
Behdad Esfahbod7fbbf862012-07-30 18:36:42 -0400686 buffer->cur().codepoint = glyph_index;
687 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330688 void replace_glyph_with_ligature (hb_codepoint_t glyph_index,
Behdad Esfahbodf4cd99f2020-04-22 14:45:57 -0700689 unsigned int class_guess) const
Behdad Esfahboda0161742013-10-18 00:06:30 +0200690 {
Behdad Esfahbodf4cd99f2020-04-22 14:45:57 -0700691 _set_glyph_class (glyph_index, class_guess, true);
Behdad Esfahboda0161742013-10-18 00:06:30 +0200692 buffer->replace_glyph (glyph_index);
693 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330694 void output_glyph_for_component (hb_codepoint_t glyph_index,
Behdad Esfahbodf4cd99f2020-04-22 14:45:57 -0700695 unsigned int class_guess) const
Behdad Esfahboda0161742013-10-18 00:06:30 +0200696 {
Behdad Esfahbodf4cd99f2020-04-22 14:45:57 -0700697 _set_glyph_class (glyph_index, class_guess, false, true);
Behdad Esfahboda0161742013-10-18 00:06:30 +0200698 buffer->output_glyph (glyph_index);
699 }
Behdad Esfahbod1376fb72010-04-29 02:19:21 -0400700};
701
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -0400702
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400703struct hb_get_subtables_context_t :
Behdad Esfahbod7df3ecf2019-05-10 20:43:26 -0700704 hb_dispatch_context_t<hb_get_subtables_context_t, hb_empty_t, HB_DEBUG_APPLY>
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400705{
706 template <typename Type>
Behdad Esfahboda061e472019-12-10 13:31:50 -0600707 static inline bool apply_to (const void *obj, OT::hb_ot_apply_context_t *c)
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400708 {
709 const Type *typed_obj = (const Type *) obj;
710 return typed_obj->apply (c);
711 }
712
713 typedef bool (*hb_apply_func_t) (const void *obj, OT::hb_ot_apply_context_t *c);
714
715 struct hb_applicable_t
716 {
717 template <typename T>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330718 void init (const T &obj_, hb_apply_func_t apply_func_)
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400719 {
720 obj = &obj_;
721 apply_func = apply_func_;
722 digest.init ();
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -0700723 obj_.get_coverage ().collect_coverage (&digest);
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400724 }
725
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330726 bool apply (OT::hb_ot_apply_context_t *c) const
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400727 {
728 return digest.may_have (c->buffer->cur().codepoint) && apply_func (obj, c);
729 }
730
731 private:
732 const void *obj;
733 hb_apply_func_t apply_func;
734 hb_set_digest_t digest;
735 };
736
Behdad Esfahbodfa333e32018-12-27 17:56:22 -0500737 typedef hb_vector_t<hb_applicable_t> array_t;
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400738
739 /* Dispatch interface. */
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330740 const char *get_name () { return "GET_SUBTABLES"; }
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400741 template <typename T>
Behdad Esfahbodc14efb82019-05-05 09:54:58 -0700742 return_t dispatch (const T &obj)
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400743 {
744 hb_applicable_t *entry = array.push();
745 entry->init (obj, apply_to<T>);
Behdad Esfahbod7df3ecf2019-05-10 20:43:26 -0700746 return hb_empty_t ();
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400747 }
Behdad Esfahbod7df3ecf2019-05-10 20:43:26 -0700748 static return_t default_return_value () { return hb_empty_t (); }
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400749
750 hb_get_subtables_context_t (array_t &array_) :
751 array (array_),
752 debug_depth (0) {}
753
754 array_t &array;
755 unsigned int debug_depth;
756};
757
758
759
Behdad Esfahbod94a23aa2010-05-05 01:13:09 -0400760
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700761typedef bool (*intersects_func_t) (const hb_set_t *glyphs, const HBUINT16 &value, const void *data);
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100762typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const HBUINT16 &value, const void *data);
763typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -0400764
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400765struct ContextClosureFuncs
766{
767 intersects_func_t intersects;
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400768};
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500769struct ContextCollectGlyphsFuncs
770{
771 collect_glyphs_func_t collect;
772};
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400773struct ContextApplyFuncs
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400774{
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -0400775 match_func_t match;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -0400776};
777
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500778
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700779static inline bool intersects_glyph (const hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400780{
781 return glyphs->has (value);
782}
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700783static inline bool intersects_class (const hb_set_t *glyphs, const HBUINT16 &value, const void *data)
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400784{
785 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
786 return class_def.intersects_class (glyphs, value);
787}
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700788static inline bool intersects_coverage (const hb_set_t *glyphs, const HBUINT16 &value, const void *data)
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400789{
790 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
791 return (data+coverage).intersects (glyphs);
792}
793
Qunxin Liu44d88cf2020-05-08 15:33:34 -0700794static inline bool array_is_subset_of (const hb_set_t *glyphs,
795 unsigned int count,
796 const HBUINT16 values[],
797 intersects_func_t intersects_func,
798 const void *intersects_data)
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400799{
Garret Rieger95ab1102019-10-21 13:15:46 -0700800 for (const HBUINT16 &_ : + hb_iter (values, count))
Qunxin Liu44d88cf2020-05-08 15:33:34 -0700801 if (!intersects_func (glyphs, _, intersects_data)) return false;
802 return true;
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400803}
804
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -0400805
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100806static inline void collect_glyph (hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500807{
808 glyphs->add (value);
809}
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100810static inline void collect_class (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500811{
812 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
Behdad Esfahbod89ad3c62020-04-23 10:57:30 -0700813 class_def.collect_class (glyphs, value);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500814}
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100815static inline void collect_coverage (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500816{
817 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -0700818 (data+coverage).collect_coverage (glyphs);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500819}
Behdad Esfahbod0beb66e2012-12-05 18:46:04 -0500820static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -0500821 hb_set_t *glyphs,
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500822 unsigned int count,
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100823 const HBUINT16 values[],
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500824 collect_glyphs_func_t collect_func,
825 const void *collect_data)
826{
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -0700827 return
828 + hb_iter (values, count)
829 | hb_apply ([&] (const HBUINT16 &_) { collect_func (glyphs, _, collect_data); })
830 ;
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500831}
832
833
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100834static inline bool match_glyph (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data HB_UNUSED)
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400835{
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -0400836 return glyph_id == value;
837}
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100838static inline bool match_class (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data)
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400839{
Behdad Esfahbod2b5a59c2009-08-04 11:38:50 -0400840 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -0400841 return class_def.get_class (glyph_id) == value;
842}
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100843static inline bool match_coverage (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data)
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400844{
Behdad Esfahbod6b54c5d2009-05-18 18:30:25 -0400845 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400846 return (data+coverage).get_coverage (glyph_id) != NOT_COVERED;
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -0400847}
848
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400849static inline bool would_match_input (hb_would_apply_context_t *c,
850 unsigned int count, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100851 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400852 match_func_t match_func,
853 const void *match_data)
854{
855 if (count != c->len)
856 return false;
857
858 for (unsigned int i = 1; i < count; i++)
Behdad Esfahbod472f2292012-08-07 22:25:24 -0400859 if (likely (!match_func (c->glyphs[i], input[i - 1], match_data)))
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400860 return false;
861
862 return true;
863}
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800864static inline bool match_input (hb_ot_apply_context_t *c,
Behdad Esfahbode072c242009-05-18 03:47:31 -0400865 unsigned int count, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100866 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -0400867 match_func_t match_func,
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -0400868 const void *match_data,
Behdad Esfahbod6cc136f2013-10-17 13:55:48 +0200869 unsigned int *end_offset,
Behdad Esfahbod5ba45042015-11-02 15:43:08 -0800870 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200871 unsigned int *p_total_component_count = nullptr)
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -0400872{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200873 TRACE_APPLY (nullptr);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400874
Behdad Esfahbod5ba45042015-11-02 15:43:08 -0800875 if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return_trace (false);
Behdad Esfahbod6b65a762013-10-14 18:51:39 +0200876
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200877 hb_buffer_t *buffer = c->buffer;
878
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800879 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
Behdad Esfahbodb051be52015-01-29 13:40:39 +0100880 skippy_iter.reset (buffer->idx, count - 1);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500881 skippy_iter.set_match_func (match_func, match_data, input);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400882
Behdad Esfahbod191fa882012-08-28 22:58:55 -0400883 /*
884 * This is perhaps the trickiest part of OpenType... Remarks:
885 *
886 * - If all components of the ligature were marks, we call this a mark ligature.
887 *
888 * - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize
889 * it as a ligature glyph.
890 *
891 * - Ligatures cannot be formed across glyphs attached to different components
892 * of previous ligatures. Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and
893 * LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother.
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200894 * However, it would be wrong to ligate that SHADDA,FATHA sequence.
895 * There are a couple of exceptions to this:
896 *
897 * o If a ligature tries ligating with marks that belong to it itself, go ahead,
898 * assuming that the font designer knows what they are doing (otherwise it can
899 * break Indic stuff when a matra wants to ligate with a conjunct,
900 *
901 * o If two marks want to ligate and they belong to different components of the
902 * same ligature glyph, and said ligature glyph is to be ignored according to
903 * mark-filtering rules, then allow.
ebraminio7c6937e2017-11-20 14:49:22 -0500904 * https://github.com/harfbuzz/harfbuzz/issues/545
Behdad Esfahbod191fa882012-08-28 22:58:55 -0400905 */
906
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400907 unsigned int total_component_count = 0;
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200908 total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur());
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400909
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200910 unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
911 unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -0400912
Behdad Esfahbod621c49c2017-10-04 15:06:48 +0200913 enum {
914 LIGBASE_NOT_CHECKED,
915 LIGBASE_MAY_NOT_SKIP,
916 LIGBASE_MAY_SKIP
917 } ligbase = LIGBASE_NOT_CHECKED;
918
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200919 match_positions[0] = buffer->idx;
Behdad Esfahbod370f03e2012-01-16 17:03:55 -0500920 for (unsigned int i = 1; i < count; i++)
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400921 {
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100922 if (!skippy_iter.next ()) return_trace (false);
Behdad Esfahbod6cc136f2013-10-17 13:55:48 +0200923
924 match_positions[i] = skippy_iter.idx;
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400925
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200926 unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]);
927 unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400928
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200929 if (first_lig_id && first_lig_comp)
930 {
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400931 /* If first component was attached to a previous ligature component,
932 * all subsequent components should be attached to the same ligature
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200933 * component, otherwise we shouldn't ligate them... */
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400934 if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200935 {
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330936 /* ...unless, we are attached to a base ligature and that base
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200937 * ligature is ignorable. */
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330938 if (ligbase == LIGBASE_NOT_CHECKED)
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200939 {
Behdad Esfahbod621c49c2017-10-04 15:06:48 +0200940 bool found = false;
Behdad Esfahbod4d677432019-05-10 16:35:31 -0700941 const auto *out = buffer->out_info;
Behdad Esfahbod621c49c2017-10-04 15:06:48 +0200942 unsigned int j = buffer->out_len;
943 while (j && _hb_glyph_info_get_lig_id (&out[j - 1]) == first_lig_id)
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200944 {
Behdad Esfahbod621c49c2017-10-04 15:06:48 +0200945 if (_hb_glyph_info_get_lig_comp (&out[j - 1]) == 0)
946 {
947 j--;
948 found = true;
949 break;
950 }
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200951 j--;
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200952 }
Behdad Esfahbod621c49c2017-10-04 15:06:48 +0200953
Behdad Esfahbod12757b62018-01-26 18:14:05 -0800954 if (found && skippy_iter.may_skip (out[j]) == hb_ot_apply_context_t::matcher_t::SKIP_YES)
Behdad Esfahbod621c49c2017-10-04 15:06:48 +0200955 ligbase = LIGBASE_MAY_SKIP;
956 else
957 ligbase = LIGBASE_MAY_NOT_SKIP;
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200958 }
959
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330960 if (ligbase == LIGBASE_MAY_NOT_SKIP)
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200961 return_trace (false);
962 }
963 }
964 else
Behdad Esfahbod621c49c2017-10-04 15:06:48 +0200965 {
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400966 /* If first component was NOT attached to a previous ligature component,
967 * all subsequent components should also NOT be attached to any ligature
968 * component, unless they are attached to the first component itself! */
969 if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id))
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100970 return_trace (false);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400971 }
972
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200973 total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -0400974 }
975
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200976 *end_offset = skippy_iter.idx - buffer->idx + 1;
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400977
Behdad Esfahbod191fa882012-08-28 22:58:55 -0400978 if (p_total_component_count)
979 *p_total_component_count = total_component_count;
980
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100981 return_trace (true);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400982}
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800983static inline bool ligate_input (hb_ot_apply_context_t *c,
Behdad Esfahbode714fe62013-10-17 13:49:51 +0200984 unsigned int count, /* Including the first glyph */
Bruce Mitchener5a24ea12018-10-20 08:09:52 +0700985 const unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
Behdad Esfahbode714fe62013-10-17 13:49:51 +0200986 unsigned int match_length,
Behdad Esfahboda177d022012-08-28 23:18:22 -0400987 hb_codepoint_t lig_glyph,
Behdad Esfahboda177d022012-08-28 23:18:22 -0400988 unsigned int total_component_count)
989{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200990 TRACE_APPLY (nullptr);
Behdad Esfahbode714fe62013-10-17 13:49:51 +0200991
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200992 hb_buffer_t *buffer = c->buffer;
993
994 buffer->merge_clusters (buffer->idx, buffer->idx + match_length);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500995
Behdad Esfahbod9efddb92018-10-02 16:05:26 +0200996 /* - If a base and one or more marks ligate, consider that as a base, NOT
997 * ligature, such that all following marks can still attach to it.
998 * https://github.com/harfbuzz/harfbuzz/issues/1109
999 *
1000 * - If all components of the ligature were marks, we call this a mark ligature.
Behdad Esfahbod3cca9782018-10-02 15:02:16 +02001001 * If it *is* a mark ligature, we don't allocate a new ligature id, and leave
Behdad Esfahboda177d022012-08-28 23:18:22 -04001002 * the ligature to keep its old ligature id. This will allow it to attach to
1003 * a base ligature in GPOS. Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH,
Behdad Esfahbod3cca9782018-10-02 15:02:16 +02001004 * and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA with a
Behdad Esfahboda177d022012-08-28 23:18:22 -04001005 * ligature id and component value of 2. Then if SHADDA,FATHA form a ligature
1006 * later, we don't want them to lose their ligature id/component, otherwise
1007 * GPOS will fail to correctly position the mark ligature on top of the
1008 * LAM,LAM,HEH ligature. See:
1009 * https://bugzilla.gnome.org/show_bug.cgi?id=676343
1010 *
1011 * - If a ligature is formed of components that some of which are also ligatures
1012 * themselves, and those ligature components had marks attached to *their*
1013 * components, we have to attach the marks to the new ligature component
1014 * positions! Now *that*'s tricky! And these marks may be following the
1015 * last component of the whole sequence, so we should loop forward looking
1016 * for them and update them.
1017 *
1018 * Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a
1019 * 'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature
1020 * id and component == 1. Now, during 'liga', the LAM and the LAM-HEH ligature
1021 * form a LAM-LAM-HEH ligature. We need to reassign the SHADDA and FATHA to
1022 * the new ligature with a component value of 2.
1023 *
1024 * This in fact happened to a font... See:
1025 * https://bugzilla.gnome.org/show_bug.cgi?id=437633
1026 */
1027
Behdad Esfahbod9efddb92018-10-02 16:05:26 +02001028 bool is_base_ligature = _hb_glyph_info_is_base_glyph (&buffer->info[match_positions[0]]);
1029 bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->info[match_positions[0]]);
1030 for (unsigned int i = 1; i < count; i++)
Behdad Esfahbod3cca9782018-10-02 15:02:16 +02001031 if (!_hb_glyph_info_is_mark (&buffer->info[match_positions[i]]))
1032 {
Behdad Esfahbod9efddb92018-10-02 16:05:26 +02001033 is_base_ligature = false;
Behdad Esfahbod3cca9782018-10-02 15:02:16 +02001034 is_mark_ligature = false;
1035 break;
1036 }
Behdad Esfahbod9efddb92018-10-02 16:05:26 +02001037 bool is_ligature = !is_base_ligature && !is_mark_ligature;
Behdad Esfahbod3cca9782018-10-02 15:02:16 +02001038
Behdad Esfahbod9efddb92018-10-02 16:05:26 +02001039 unsigned int klass = is_ligature ? HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE : 0;
1040 unsigned int lig_id = is_ligature ? _hb_allocate_lig_id (buffer) : 0;
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +02001041 unsigned int last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
1042 unsigned int last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
Behdad Esfahboda177d022012-08-28 23:18:22 -04001043 unsigned int components_so_far = last_num_components;
1044
Behdad Esfahbod9efddb92018-10-02 16:05:26 +02001045 if (is_ligature)
Behdad Esfahbod7e08f122013-05-27 14:48:34 -04001046 {
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +02001047 _hb_glyph_info_set_lig_props_for_ligature (&buffer->cur(), lig_id, total_component_count);
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +02001048 if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
Behdad Esfahbod3d436d32013-10-28 21:00:37 +01001049 {
Behdad Esfahbod82596692015-11-02 17:44:05 -08001050 _hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER);
Behdad Esfahbod3d436d32013-10-28 21:00:37 +01001051 }
Behdad Esfahbod7e08f122013-05-27 14:48:34 -04001052 }
Behdad Esfahboda0161742013-10-18 00:06:30 +02001053 c->replace_glyph_with_ligature (lig_glyph, klass);
Behdad Esfahboda177d022012-08-28 23:18:22 -04001054
1055 for (unsigned int i = 1; i < count; i++)
1056 {
Behdad Esfahbod7185b272018-05-31 20:03:00 -07001057 while (buffer->idx < match_positions[i] && buffer->successful)
Behdad Esfahboda177d022012-08-28 23:18:22 -04001058 {
Behdad Esfahbod9efddb92018-10-02 16:05:26 +02001059 if (is_ligature)
1060 {
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03301061 unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
Behdad Esfahbod2f02fc72015-12-17 15:21:14 +00001062 if (this_comp == 0)
Behdad Esfahbod100fbea2015-12-17 15:23:09 +00001063 this_comp = last_num_components;
Behdad Esfahboda177d022012-08-28 23:18:22 -04001064 unsigned int new_lig_comp = components_so_far - last_num_components +
Behdad Esfahbod41248cc2019-05-07 20:54:31 -07001065 hb_min (this_comp, last_num_components);
Behdad Esfahbod2f02fc72015-12-17 15:21:14 +00001066 _hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
Behdad Esfahboda177d022012-08-28 23:18:22 -04001067 }
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +02001068 buffer->next_glyph ();
Behdad Esfahboda177d022012-08-28 23:18:22 -04001069 }
1070
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +02001071 last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
1072 last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
Behdad Esfahboda177d022012-08-28 23:18:22 -04001073 components_so_far += last_num_components;
1074
1075 /* Skip the base glyph */
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +02001076 buffer->idx++;
Behdad Esfahboda177d022012-08-28 23:18:22 -04001077 }
1078
Ebrahim Byagowicc977b62020-03-26 11:18:02 +04301079 if (!is_mark_ligature && last_lig_id)
1080 {
Behdad Esfahboda177d022012-08-28 23:18:22 -04001081 /* Re-adjust components for any marks following. */
Ebrahim Byagowicc977b62020-03-26 11:18:02 +04301082 for (unsigned i = buffer->idx; i < buffer->len; ++i)
1083 {
1084 if (last_lig_id != _hb_glyph_info_get_lig_id (&buffer->info[i])) break;
1085
1086 unsigned this_comp = _hb_glyph_info_get_lig_comp (&buffer->info[i]);
1087 if (!this_comp) break;
1088
1089 unsigned new_lig_comp = components_so_far - last_num_components +
1090 hb_min (this_comp, last_num_components);
1091 _hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
Behdad Esfahboda177d022012-08-28 23:18:22 -04001092 }
1093 }
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001094 return_trace (true);
Behdad Esfahboda177d022012-08-28 23:18:22 -04001095}
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001096
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001097static inline bool match_backtrack (hb_ot_apply_context_t *c,
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001098 unsigned int count,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001099 const HBUINT16 backtrack[],
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001100 match_func_t match_func,
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001101 const void *match_data,
1102 unsigned int *match_start)
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001103{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001104 TRACE_APPLY (nullptr);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -04001105
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001106 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
Behdad Esfahbodb051be52015-01-29 13:40:39 +01001107 skippy_iter.reset (c->buffer->backtrack_len (), count);
Behdad Esfahbod607feb72013-02-14 07:43:13 -05001108 skippy_iter.set_match_func (match_func, match_data, backtrack);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001109
Behdad Esfahbod4d3aeb82012-01-16 16:43:26 -05001110 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -05001111 if (!skippy_iter.prev ())
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001112 return_trace (false);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001113
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001114 *match_start = skippy_iter.idx;
1115
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001116 return_trace (true);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001117}
1118
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001119static inline bool match_lookahead (hb_ot_apply_context_t *c,
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001120 unsigned int count,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001121 const HBUINT16 lookahead[],
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001122 match_func_t match_func,
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04001123 const void *match_data,
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001124 unsigned int offset,
1125 unsigned int *end_index)
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001126{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001127 TRACE_APPLY (nullptr);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -04001128
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001129 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
Behdad Esfahbodb051be52015-01-29 13:40:39 +01001130 skippy_iter.reset (c->buffer->idx + offset - 1, count);
Behdad Esfahbod607feb72013-02-14 07:43:13 -05001131 skippy_iter.set_match_func (match_func, match_data, lookahead);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001132
Behdad Esfahbod370f03e2012-01-16 17:03:55 -05001133 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -05001134 if (!skippy_iter.next ())
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001135 return_trace (false);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001136
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001137 *end_index = skippy_iter.idx + 1;
1138
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001139 return_trace (true);
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001140}
1141
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04001142
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001143
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001144struct LookupRecord
1145{
Qunxin Liu0b39c482019-10-22 16:00:43 -07001146 LookupRecord* copy (hb_serialize_context_t *c,
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001147 const hb_map_t *lookup_map) const
Qunxin Liu0b39c482019-10-22 16:00:43 -07001148 {
1149 TRACE_SERIALIZE (this);
1150 auto *out = c->embed (*this);
1151 if (unlikely (!out)) return_trace (nullptr);
1152
1153 out->lookupListIndex = hb_map_get (lookup_map, lookupListIndex);
1154 return_trace (out);
1155 }
1156
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301157 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001158 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001159 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001160 return_trace (c->check_struct (this));
Behdad Esfahbodcd3827e2009-08-04 02:09:34 -04001161 }
1162
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001163 HBUINT16 sequenceIndex; /* Index into current glyph
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001164 * sequence--first glyph = 0 */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001165 HBUINT16 lookupListIndex; /* Lookup to apply to that
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001166 * position--zero--based */
Behdad Esfahbod569da922010-05-10 16:38:32 -04001167 public:
1168 DEFINE_SIZE_STATIC (4);
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001169};
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001170
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001171template <typename context_t>
1172static inline void recurse_lookups (context_t *c,
1173 unsigned int lookupCount,
1174 const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001175{
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001176 for (unsigned int i = 0; i < lookupCount; i++)
Behdad Esfahbod86522e42013-07-22 19:07:53 -04001177 c->recurse (lookupRecord[i].lookupListIndex);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001178}
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04001179
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001180static inline bool apply_lookup (hb_ot_apply_context_t *c,
Behdad Esfahbode072c242009-05-18 03:47:31 -04001181 unsigned int count, /* Including the first glyph */
Behdad Esfahbod5ba45042015-11-02 15:43:08 -08001182 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
Behdad Esfahbode072c242009-05-18 03:47:31 -04001183 unsigned int lookupCount,
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001184 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
1185 unsigned int match_length)
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001186{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001187 TRACE_APPLY (nullptr);
Behdad Esfahbod902cc8a2012-11-23 15:06:59 -05001188
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001189 hb_buffer_t *buffer = c->buffer;
jfkthame44f7d6e2017-02-17 03:03:24 +00001190 int end;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001191
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001192 /* All positions are distance from beginning of *output* buffer.
1193 * Adjust. */
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001194 {
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001195 unsigned int bl = buffer->backtrack_len ();
1196 end = bl + match_length;
Behdad Esfahbod8751de52013-07-18 16:29:50 -04001197
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001198 int delta = bl - buffer->idx;
1199 /* Convert positions to new indexing. */
1200 for (unsigned int j = 0; j < count; j++)
1201 match_positions[j] += delta;
Behdad Esfahbod8820bb22013-02-14 07:41:03 -05001202 }
Behdad Esfahbode73a0c22009-05-18 04:15:25 -04001203
Behdad Esfahbod7185b272018-05-31 20:03:00 -07001204 for (unsigned int i = 0; i < lookupCount && buffer->successful; i++)
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001205 {
1206 unsigned int idx = lookupRecord[i].sequenceIndex;
1207 if (idx >= count)
1208 continue;
1209
Behdad Esfahbod9cc1ed42015-11-19 12:39:09 -08001210 /* Don't recurse to ourself at same position.
1211 * Note that this test is too naive, it doesn't catch longer loops. */
1212 if (idx == 0 && lookupRecord[i].lookupListIndex == c->lookup_index)
1213 continue;
1214
Behdad Esfahbode5930722017-11-14 15:47:55 -08001215 if (unlikely (!buffer->move_to (match_positions[idx])))
1216 break;
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001217
Behdad Esfahbodbaf77792017-11-14 21:53:48 -08001218 if (unlikely (buffer->max_ops <= 0))
1219 break;
1220
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001221 unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
1222 if (!c->recurse (lookupRecord[i].lookupListIndex))
1223 continue;
1224
1225 unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len ();
1226 int delta = new_len - orig_len;
1227
1228 if (!delta)
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03301229 continue;
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001230
Behdad Esfahbod9ac9af72017-03-05 13:51:01 -08001231 /* Recursed lookup changed buffer len. Adjust.
1232 *
1233 * TODO:
1234 *
1235 * Right now, if buffer length increased by n, we assume n new glyphs
1236 * were added right after the current position, and if buffer length
1237 * was decreased by n, we assume n match positions after the current
1238 * one where removed. The former (buffer length increased) case is
1239 * fine, but the decrease case can be improved in at least two ways,
1240 * both of which are significant:
1241 *
1242 * - If recursed-to lookup is MultipleSubst and buffer length
1243 * decreased, then it's current match position that was deleted,
1244 * NOT the one after it.
1245 *
1246 * - If buffer length was decreased by n, it does not necessarily
1247 * mean that n match positions where removed, as there might
1248 * have been marks and default-ignorables in the sequence. We
1249 * should instead drop match positions between current-position
1250 * and current-position + n instead.
1251 *
1252 * It should be possible to construct tests for both of these cases.
1253 */
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001254
jfkthame44f7d6e2017-02-17 03:03:24 +00001255 end += delta;
Behdad Esfahbod47e7a182017-03-10 13:23:02 -08001256 if (end <= int (match_positions[idx]))
Behdad Esfahbod359dead2016-05-06 16:19:19 +01001257 {
Behdad Esfahbod4b4a1b92016-12-21 23:10:43 -06001258 /* End might end up being smaller than match_positions[idx] if the recursed
Behdad Esfahbod47e7a182017-03-10 13:23:02 -08001259 * lookup ended up removing many items, more than we have had matched.
Behdad Esfahbod4b4a1b92016-12-21 23:10:43 -06001260 * Just never rewind end back and get out of here.
1261 * https://bugs.chromium.org/p/chromium/issues/detail?id=659496 */
1262 end = match_positions[idx];
Behdad Esfahbod47e7a182017-03-10 13:23:02 -08001263 /* There can't be any further changes. */
Behdad Esfahbod359dead2016-05-06 16:19:19 +01001264 break;
1265 }
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001266
1267 unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */
1268
1269 if (delta > 0)
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001270 {
Behdad Esfahbod5ba45042015-11-02 15:43:08 -08001271 if (unlikely (delta + count > HB_MAX_CONTEXT_LENGTH))
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001272 break;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001273 }
1274 else
1275 {
Behdad Esfahbod47e7a182017-03-10 13:23:02 -08001276 /* NOTE: delta is negative. */
Behdad Esfahbod41248cc2019-05-07 20:54:31 -07001277 delta = hb_max (delta, (int) next - (int) count);
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001278 next -= delta;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001279 }
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001280
1281 /* Shift! */
1282 memmove (match_positions + next + delta, match_positions + next,
1283 (count - next) * sizeof (match_positions[0]));
1284 next += delta;
1285 count += delta;
1286
1287 /* Fill in new entries. */
1288 for (unsigned int j = idx + 1; j < next; j++)
1289 match_positions[j] = match_positions[j - 1] + 1;
1290
1291 /* And fixup the rest. */
1292 for (; next < count; next++)
1293 match_positions[next] += delta;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001294 }
1295
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001296 buffer->move_to (end);
1297
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001298 return_trace (true);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001299}
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001300
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04001301
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001302
1303/* Contextual lookups */
1304
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001305struct ContextClosureLookupContext
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001306{
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001307 ContextClosureFuncs funcs;
1308 const void *intersects_data;
1309};
1310
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001311struct ContextCollectGlyphsLookupContext
1312{
1313 ContextCollectGlyphsFuncs funcs;
1314 const void *collect_data;
1315};
1316
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001317struct ContextApplyLookupContext
1318{
1319 ContextApplyFuncs funcs;
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04001320 const void *match_data;
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001321};
1322
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001323static inline bool context_intersects (const hb_set_t *glyphs,
1324 unsigned int inputCount, /* Including the first glyph (not matched) */
1325 const HBUINT16 input[], /* Array of input values--start with second glyph */
1326 ContextClosureLookupContext &lookup_context)
1327{
Qunxin Liu44d88cf2020-05-08 15:33:34 -07001328 return array_is_subset_of (glyphs,
1329 inputCount ? inputCount - 1 : 0, input,
1330 lookup_context.funcs.intersects, lookup_context.intersects_data);
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001331}
1332
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001333static inline void context_closure_lookup (hb_closure_context_t *c,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001334 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001335 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001336 unsigned int lookupCount,
1337 const LookupRecord lookupRecord[],
1338 ContextClosureLookupContext &lookup_context)
1339{
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001340 if (context_intersects (c->glyphs,
1341 inputCount, input,
1342 lookup_context))
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001343 recurse_lookups (c,
1344 lookupCount, lookupRecord);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001345}
1346
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001347static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
1348 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001349 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001350 unsigned int lookupCount,
1351 const LookupRecord lookupRecord[],
1352 ContextCollectGlyphsLookupContext &lookup_context)
1353{
Behdad Esfahbod83035932012-12-04 17:08:41 -05001354 collect_array (c, c->input,
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001355 inputCount ? inputCount - 1 : 0, input,
1356 lookup_context.funcs.collect, lookup_context.collect_data);
1357 recurse_lookups (c,
1358 lookupCount, lookupRecord);
1359}
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001360
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001361static inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
1362 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001363 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbod0beb66e2012-12-05 18:46:04 -05001364 unsigned int lookupCount HB_UNUSED,
1365 const LookupRecord lookupRecord[] HB_UNUSED,
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001366 ContextApplyLookupContext &lookup_context)
1367{
1368 return would_match_input (c,
1369 inputCount, input,
1370 lookup_context.funcs.match, lookup_context.match_data);
1371}
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001372static inline bool context_apply_lookup (hb_ot_apply_context_t *c,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001373 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001374 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001375 unsigned int lookupCount,
1376 const LookupRecord lookupRecord[],
1377 ContextApplyLookupContext &lookup_context)
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001378{
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001379 unsigned int match_length = 0;
Behdad Esfahbod5ba45042015-11-02 15:43:08 -08001380 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001381 return match_input (c,
Behdad Esfahbod41697102010-05-05 01:37:58 -04001382 inputCount, input,
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001383 lookup_context.funcs.match, lookup_context.match_data,
1384 &match_length, match_positions)
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001385 && (c->buffer->unsafe_to_break (c->buffer->idx, c->buffer->idx + match_length),
1386 apply_lookup (c,
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001387 inputCount, match_positions,
1388 lookupCount, lookupRecord,
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001389 match_length));
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001390}
1391
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001392struct Rule
1393{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301394 bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001395 {
1396 return context_intersects (glyphs,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001397 inputCount, inputZ.arrayZ,
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001398 lookup_context);
1399 }
1400
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301401 void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001402 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04301403 if (unlikely (c->lookup_limit_exceeded ())) return;
Garret Rieger014e0382020-03-31 16:29:29 -07001404
Ebrahim Byagowi92588782019-04-30 13:05:10 -07001405 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
Behdad Esfahbod0382b712018-11-02 12:23:26 -04001406 (inputZ.as_array ((inputCount ? inputCount - 1 : 0)));
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001407 context_closure_lookup (c,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001408 inputCount, inputZ.arrayZ,
1409 lookupCount, lookupRecord.arrayZ,
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001410 lookup_context);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001411 }
1412
Qunxin Liu0b39c482019-10-22 16:00:43 -07001413 void closure_lookups (hb_closure_lookups_context_t *c) const
1414 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04301415 if (unlikely (c->lookup_limit_exceeded ())) return;
Garret Rieger014e0382020-03-31 16:29:29 -07001416
Qunxin Liu0b39c482019-10-22 16:00:43 -07001417 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
1418 (inputZ.as_array (inputCount ? inputCount - 1 : 0));
1419 recurse_lookups (c, lookupCount, lookupRecord.arrayZ);
1420 }
1421
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301422 void collect_glyphs (hb_collect_glyphs_context_t *c,
1423 ContextCollectGlyphsLookupContext &lookup_context) const
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001424 {
Ebrahim Byagowi92588782019-04-30 13:05:10 -07001425 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
Behdad Esfahbod0382b712018-11-02 12:23:26 -04001426 (inputZ.as_array (inputCount ? inputCount - 1 : 0));
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001427 context_collect_glyphs_lookup (c,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001428 inputCount, inputZ.arrayZ,
1429 lookupCount, lookupRecord.arrayZ,
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001430 lookup_context);
1431 }
1432
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301433 bool would_apply (hb_would_apply_context_t *c,
1434 ContextApplyLookupContext &lookup_context) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001435 {
Ebrahim Byagowi92588782019-04-30 13:05:10 -07001436 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
Behdad Esfahbod0382b712018-11-02 12:23:26 -04001437 (inputZ.as_array (inputCount ? inputCount - 1 : 0));
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07001438 return context_would_apply_lookup (c,
1439 inputCount, inputZ.arrayZ,
1440 lookupCount, lookupRecord.arrayZ,
1441 lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001442 }
1443
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301444 bool apply (hb_ot_apply_context_t *c,
1445 ContextApplyLookupContext &lookup_context) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001446 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001447 TRACE_APPLY (this);
Ebrahim Byagowi92588782019-04-30 13:05:10 -07001448 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
Behdad Esfahbod0382b712018-11-02 12:23:26 -04001449 (inputZ.as_array (inputCount ? inputCount - 1 : 0));
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001450 return_trace (context_apply_lookup (c, inputCount, inputZ.arrayZ, lookupCount, lookupRecord.arrayZ, lookup_context));
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001451 }
1452
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001453 bool serialize (hb_serialize_context_t *c,
1454 const hb_map_t *input_mapping, /* old->new glyphid or class mapping */
1455 const hb_map_t *lookup_map) const
1456 {
1457 TRACE_SERIALIZE (this);
1458 auto *out = c->start_embed (this);
1459 if (unlikely (!c->extend_min (out))) return_trace (false);
1460
1461 out->inputCount = inputCount;
1462 out->lookupCount = lookupCount;
1463
1464 const hb_array_t<const HBUINT16> input = inputZ.as_array (inputCount - 1);
1465 for (const auto org : input)
1466 {
1467 HBUINT16 d;
1468 d = input_mapping->get (org);
1469 c->copy (d);
1470 }
1471
1472 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
1473 (inputZ.as_array ((inputCount ? inputCount - 1 : 0)));
1474 for (unsigned i = 0; i < (unsigned) lookupCount; i++)
1475 c->copy (lookupRecord[i], lookup_map);
1476
1477 return_trace (true);
1478 }
1479
1480 bool subset (hb_subset_context_t *c,
1481 const hb_map_t *lookup_map,
1482 const hb_map_t *klass_map = nullptr) const
1483 {
1484 TRACE_SUBSET (this);
1485
1486 const hb_array_t<const HBUINT16> input = inputZ.as_array ((inputCount ? inputCount - 1 : 0));
1487 if (!input.length) return_trace (false);
1488
1489 const hb_map_t *mapping = klass_map == nullptr ? c->plan->glyph_map : klass_map;
1490 if (!hb_all (input, mapping)) return_trace (false);
1491 return_trace (serialize (c->serializer, mapping, lookup_map));
1492 }
1493
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001494 public:
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301495 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001496 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001497 TRACE_SANITIZE (this);
Behdad Esfahbod5aad8192017-11-03 17:16:26 -04001498 return_trace (inputCount.sanitize (c) &&
1499 lookupCount.sanitize (c) &&
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001500 c->check_range (inputZ.arrayZ,
Behdad Esfahbod9c6921c2018-11-30 15:16:57 -05001501 inputZ.item_size * (inputCount ? inputCount - 1 : 0) +
Behdad Esfahbod6d7c6e12018-02-07 14:09:56 -06001502 LookupRecord::static_size * lookupCount));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001503 }
1504
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001505 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001506 HBUINT16 inputCount; /* Total number of glyphs in input
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001507 * glyph sequence--includes the first
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001508 * glyph */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001509 HBUINT16 lookupCount; /* Number of LookupRecords */
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001510 UnsizedArrayOf<HBUINT16>
Ebrahim Byagowice114d62019-12-31 15:53:02 +03301511 inputZ; /* Array of match inputs--start with
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001512 * second glyph */
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001513/*UnsizedArrayOf<LookupRecord>
1514 lookupRecordX;*/ /* Array of LookupRecords--in
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001515 * design order */
Behdad Esfahbod569da922010-05-10 16:38:32 -04001516 public:
Behdad Esfahbod6d7c6e12018-02-07 14:09:56 -06001517 DEFINE_SIZE_ARRAY (4, inputZ);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001518};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001519
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001520struct RuleSet
1521{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301522 bool intersects (const hb_set_t *glyphs,
1523 ContextClosureLookupContext &lookup_context) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001524 {
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001525 return
1526 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07001527 | hb_map (hb_add (this))
1528 | hb_map ([&] (const Rule &_) { return _.intersects (glyphs, lookup_context); })
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001529 | hb_any
1530 ;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001531 }
1532
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301533 void closure (hb_closure_context_t *c,
1534 ContextClosureLookupContext &lookup_context) const
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001535 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04301536 if (unlikely (c->lookup_limit_exceeded ())) return;
Garret Rieger014e0382020-03-31 16:29:29 -07001537
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001538 return
1539 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07001540 | hb_map (hb_add (this))
1541 | hb_apply ([&] (const Rule &_) { _.closure (c, lookup_context); })
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001542 ;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001543 }
1544
Qunxin Liu0b39c482019-10-22 16:00:43 -07001545 void closure_lookups (hb_closure_lookups_context_t *c) const
1546 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04301547 if (unlikely (c->lookup_limit_exceeded ())) return;
Garret Rieger014e0382020-03-31 16:29:29 -07001548
Qunxin Liu0b39c482019-10-22 16:00:43 -07001549 return
1550 + hb_iter (rule)
1551 | hb_map (hb_add (this))
1552 | hb_apply ([&] (const Rule &_) { _.closure_lookups (c); })
1553 ;
1554 }
1555
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301556 void collect_glyphs (hb_collect_glyphs_context_t *c,
1557 ContextCollectGlyphsLookupContext &lookup_context) const
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001558 {
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001559 return
1560 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07001561 | hb_map (hb_add (this))
1562 | hb_apply ([&] (const Rule &_) { _.collect_glyphs (c, lookup_context); })
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001563 ;
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001564 }
1565
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301566 bool would_apply (hb_would_apply_context_t *c,
1567 ContextApplyLookupContext &lookup_context) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001568 {
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001569 return
1570 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07001571 | hb_map (hb_add (this))
1572 | hb_map ([&] (const Rule &_) { return _.would_apply (c, lookup_context); })
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001573 | hb_any
1574 ;
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001575 }
1576
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301577 bool apply (hb_ot_apply_context_t *c,
1578 ContextApplyLookupContext &lookup_context) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001579 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001580 TRACE_APPLY (this);
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001581 return_trace (
1582 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07001583 | hb_map (hb_add (this))
1584 | hb_map ([&] (const Rule &_) { return _.apply (c, lookup_context); })
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001585 | hb_any
1586 )
1587 ;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001588 }
1589
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001590 bool subset (hb_subset_context_t *c,
1591 const hb_map_t *lookup_map,
1592 const hb_map_t *klass_map = nullptr) const
1593 {
1594 TRACE_SUBSET (this);
1595
1596 auto snap = c->serializer->snapshot ();
1597 auto *out = c->serializer->start_embed (*this);
1598 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
1599
1600 for (const OffsetTo<Rule>& _ : rule)
1601 {
1602 if (!_) continue;
1603 auto *o = out->rule.serialize_append (c->serializer);
1604 if (unlikely (!o)) continue;
1605
1606 auto o_snap = c->serializer->snapshot ();
1607 if (!o->serialize_subset (c, _, this, lookup_map, klass_map))
1608 {
1609 out->rule.pop ();
1610 c->serializer->revert (o_snap);
1611 }
1612 }
1613
1614 bool ret = bool (out->rule);
1615 if (!ret) c->serializer->revert (snap);
1616
1617 return_trace (ret);
1618 }
1619
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301620 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001621 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001622 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001623 return_trace (rule.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001624 }
1625
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001626 protected:
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001627 OffsetArrayOf<Rule>
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001628 rule; /* Array of Rule tables
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001629 * ordered by preference */
Behdad Esfahboded074222010-05-10 18:08:46 -04001630 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04001631 DEFINE_SIZE_ARRAY (2, rule);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001632};
1633
1634
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001635struct ContextFormat1
1636{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301637 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001638 {
1639 struct ContextClosureLookupContext lookup_context = {
1640 {intersects_glyph},
1641 nullptr
1642 };
Behdad Esfahbod05f21302019-03-29 22:40:13 -07001643
1644 return
1645 + hb_zip (this+coverage, ruleSet)
1646 | hb_filter (*glyphs, hb_first)
1647 | hb_map (hb_second)
Behdad Esfahbod23768672019-05-15 21:57:26 -07001648 | hb_map (hb_add (this))
1649 | hb_map ([&] (const RuleSet &_) { return _.intersects (glyphs, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07001650 | hb_any
1651 ;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001652 }
1653
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301654 void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001655 {
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001656 struct ContextClosureLookupContext lookup_context = {
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001657 {intersects_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001658 nullptr
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001659 };
Behdad Esfahbod05f21302019-03-29 22:40:13 -07001660
1661 + hb_zip (this+coverage, ruleSet)
1662 | hb_filter (*c->glyphs, hb_first)
1663 | hb_map (hb_second)
Behdad Esfahbod23768672019-05-15 21:57:26 -07001664 | hb_map (hb_add (this))
1665 | hb_apply ([&] (const RuleSet &_) { _.closure (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07001666 ;
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001667 }
1668
Qunxin Liu0b39c482019-10-22 16:00:43 -07001669 void closure_lookups (hb_closure_lookups_context_t *c) const
1670 {
1671 + hb_iter (ruleSet)
1672 | hb_map (hb_add (this))
1673 | hb_apply ([&] (const RuleSet &_) { _.closure_lookups (c); })
1674 ;
1675 }
1676
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301677 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001678 {
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07001679 (this+coverage).collect_coverage (c->input);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001680
1681 struct ContextCollectGlyphsLookupContext lookup_context = {
1682 {collect_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001683 nullptr
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001684 };
1685
Behdad Esfahbod05f21302019-03-29 22:40:13 -07001686 + hb_iter (ruleSet)
Behdad Esfahbod23768672019-05-15 21:57:26 -07001687 | hb_map (hb_add (this))
1688 | hb_apply ([&] (const RuleSet &_) { _.collect_glyphs (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07001689 ;
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001690 }
1691
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301692 bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001693 {
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05001694 const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001695 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001696 {match_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001697 nullptr
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001698 };
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07001699 return rule_set.would_apply (c, lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001700 }
1701
Ebrahim Byagowie4120082018-12-17 21:31:01 +03301702 const Coverage &get_coverage () const { return this+coverage; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001703
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301704 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001705 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001706 TRACE_APPLY (this);
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05001707 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -04001708 if (likely (index == NOT_COVERED))
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001709 return_trace (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04001710
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001711 const RuleSet &rule_set = this+ruleSet[index];
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001712 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001713 {match_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001714 nullptr
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001715 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001716 return_trace (rule_set.apply (c, lookup_context));
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001717 }
1718
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301719 bool subset (hb_subset_context_t *c) const
Behdad Esfahbod339d3602018-09-03 17:33:34 -07001720 {
1721 TRACE_SUBSET (this);
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001722 const hb_set_t &glyphset = *c->plan->glyphset ();
1723 const hb_map_t &glyph_map = *c->plan->glyph_map;
1724
1725 auto *out = c->serializer->start_embed (*this);
1726 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
1727 out->format = format;
1728
1729 const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
1730 hb_sorted_vector_t<hb_codepoint_t> new_coverage;
1731 + hb_zip (this+coverage, ruleSet)
1732 | hb_filter (glyphset, hb_first)
1733 | hb_filter (subset_offset_array (c, out->ruleSet, this, lookup_map), hb_second)
1734 | hb_map (hb_first)
1735 | hb_map (glyph_map)
1736 | hb_sink (new_coverage)
1737 ;
1738
1739 out->coverage.serialize (c->serializer, out)
1740 .serialize (c->serializer, new_coverage.iter ());
1741 return_trace (bool (new_coverage));
Behdad Esfahbod339d3602018-09-03 17:33:34 -07001742 }
1743
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301744 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001745 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001746 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001747 return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001748 }
1749
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001750 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001751 HBUINT16 format; /* Format identifier--format = 1 */
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001752 OffsetTo<Coverage>
1753 coverage; /* Offset to Coverage table--from
1754 * beginning of table */
1755 OffsetArrayOf<RuleSet>
1756 ruleSet; /* Array of RuleSet tables
1757 * ordered by Coverage Index */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04001758 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04001759 DEFINE_SIZE_ARRAY (6, ruleSet);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001760};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001761
1762
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001763struct ContextFormat2
1764{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301765 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001766 {
1767 if (!(this+coverage).intersects (glyphs))
1768 return false;
1769
1770 const ClassDef &class_def = this+classDef;
1771
1772 struct ContextClosureLookupContext lookup_context = {
1773 {intersects_class},
1774 &class_def
1775 };
1776
Behdad Esfahbod668d2d52019-03-29 22:48:38 -07001777 return
1778 + hb_enumerate (ruleSet)
Behdad Esfahbod78d35f02019-05-15 18:15:05 -07001779 | hb_map ([&] (const hb_pair_t<unsigned, const OffsetTo<RuleSet> &> p)
Behdad Esfahbode5306922019-03-29 23:31:07 -07001780 { return class_def.intersects_class (glyphs, p.first) &&
1781 (this+p.second).intersects (glyphs, lookup_context); })
Behdad Esfahbod668d2d52019-03-29 22:48:38 -07001782 | hb_any
1783 ;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001784 }
1785
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301786 void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001787 {
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001788 if (!(this+coverage).intersects (c->glyphs))
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001789 return;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001790
1791 const ClassDef &class_def = this+classDef;
1792
1793 struct ContextClosureLookupContext lookup_context = {
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001794 {intersects_class},
Behdad Esfahbod11fba792013-01-02 23:36:37 -06001795 &class_def
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001796 };
1797
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07001798 return
1799 + hb_enumerate (ruleSet)
Behdad Esfahbod78d35f02019-05-15 18:15:05 -07001800 | hb_filter ([&] (unsigned _)
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07001801 { return class_def.intersects_class (c->glyphs, _); },
1802 hb_first)
1803 | hb_map (hb_second)
Behdad Esfahbod23768672019-05-15 21:57:26 -07001804 | hb_map (hb_add (this))
1805 | hb_apply ([&] (const RuleSet &_) { _.closure (c, lookup_context); })
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07001806 ;
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001807 }
1808
Qunxin Liu0b39c482019-10-22 16:00:43 -07001809 void closure_lookups (hb_closure_lookups_context_t *c) const
1810 {
1811 + hb_iter (ruleSet)
1812 | hb_map (hb_add (this))
1813 | hb_apply ([&] (const RuleSet &_) { _.closure_lookups (c); })
1814 ;
1815 }
1816
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301817 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001818 {
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07001819 (this+coverage).collect_coverage (c->input);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001820
Behdad Esfahbod11fba792013-01-02 23:36:37 -06001821 const ClassDef &class_def = this+classDef;
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001822 struct ContextCollectGlyphsLookupContext lookup_context = {
1823 {collect_class},
Behdad Esfahbod11fba792013-01-02 23:36:37 -06001824 &class_def
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001825 };
1826
Behdad Esfahbod05f21302019-03-29 22:40:13 -07001827 + hb_iter (ruleSet)
Behdad Esfahbod23768672019-05-15 21:57:26 -07001828 | hb_map (hb_add (this))
1829 | hb_apply ([&] (const RuleSet &_) { _.collect_glyphs (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07001830 ;
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001831 }
1832
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301833 bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001834 {
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001835 const ClassDef &class_def = this+classDef;
Behdad Esfahbod2dc11412012-11-24 19:16:34 -05001836 unsigned int index = class_def.get_class (c->glyphs[0]);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001837 const RuleSet &rule_set = this+ruleSet[index];
1838 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001839 {match_class},
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001840 &class_def
1841 };
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07001842 return rule_set.would_apply (c, lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001843 }
1844
Ebrahim Byagowie4120082018-12-17 21:31:01 +03301845 const Coverage &get_coverage () const { return this+coverage; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001846
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301847 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001848 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001849 TRACE_APPLY (this);
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05001850 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001851 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04001852
1853 const ClassDef &class_def = this+classDef;
Behdad Esfahbod2dc11412012-11-24 19:16:34 -05001854 index = class_def.get_class (c->buffer->cur().codepoint);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001855 const RuleSet &rule_set = this+ruleSet[index];
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001856 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001857 {match_class},
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04001858 &class_def
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001859 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001860 return_trace (rule_set.apply (c, lookup_context));
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001861 }
1862
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301863 bool subset (hb_subset_context_t *c) const
Behdad Esfahbod339d3602018-09-03 17:33:34 -07001864 {
1865 TRACE_SUBSET (this);
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001866 auto *out = c->serializer->start_embed (*this);
1867 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
1868 out->format = format;
1869 if (unlikely (!out->coverage.serialize_subset (c, coverage, this)))
1870 return_trace (false);
1871
1872 hb_map_t klass_map;
1873 out->classDef.serialize_subset (c, classDef, this, &klass_map);
1874
1875 const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
1876 bool ret = true;
1877 unsigned non_zero_index = 0, index = 0;
1878 for (const hb_pair_t<unsigned, const OffsetTo<RuleSet>&>& _ : + hb_enumerate (ruleSet)
1879 | hb_filter (klass_map, hb_first))
1880 {
1881 auto *o = out->ruleSet.serialize_append (c->serializer);
1882 if (unlikely (!o))
1883 {
1884 ret = false;
1885 break;
1886 }
1887
1888 if (o->serialize_subset (c, _.second, this, lookup_map, &klass_map))
1889 non_zero_index = index;
1890
1891 index++;
1892 }
1893
1894 if (!ret) return_trace (ret);
1895
1896 //prune empty trailing ruleSets
1897 --index;
1898 while (index > non_zero_index)
1899 {
1900 out->ruleSet.pop ();
1901 index--;
1902 }
1903
1904 return_trace (bool (out->ruleSet));
Behdad Esfahbod339d3602018-09-03 17:33:34 -07001905 }
1906
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301907 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001908 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001909 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001910 return_trace (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001911 }
1912
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001913 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001914 HBUINT16 format; /* Format identifier--format = 2 */
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001915 OffsetTo<Coverage>
1916 coverage; /* Offset to Coverage table--from
1917 * beginning of table */
1918 OffsetTo<ClassDef>
1919 classDef; /* Offset to glyph ClassDef table--from
1920 * beginning of table */
1921 OffsetArrayOf<RuleSet>
1922 ruleSet; /* Array of RuleSet tables
1923 * ordered by class */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04001924 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04001925 DEFINE_SIZE_ARRAY (8, ruleSet);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001926};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001927
1928
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001929struct ContextFormat3
1930{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301931 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001932 {
Behdad Esfahbodfb059082018-11-30 20:45:40 -05001933 if (!(this+coverageZ[0]).intersects (glyphs))
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001934 return false;
1935
1936 struct ContextClosureLookupContext lookup_context = {
1937 {intersects_coverage},
1938 this
1939 };
1940 return context_intersects (glyphs,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001941 glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001942 lookup_context);
1943 }
1944
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301945 void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001946 {
Behdad Esfahbodfb059082018-11-30 20:45:40 -05001947 if (!(this+coverageZ[0]).intersects (c->glyphs))
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001948 return;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001949
Behdad Esfahbod0382b712018-11-02 12:23:26 -04001950 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001951 struct ContextClosureLookupContext lookup_context = {
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001952 {intersects_coverage},
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001953 this
1954 };
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001955 context_closure_lookup (c,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001956 glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001957 lookupCount, lookupRecord,
1958 lookup_context);
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001959 }
1960
Qunxin Liu0b39c482019-10-22 16:00:43 -07001961 void closure_lookups (hb_closure_lookups_context_t *c) const
1962 {
1963 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
1964 recurse_lookups (c, lookupCount, lookupRecord);
1965 }
1966
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301967 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001968 {
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07001969 (this+coverageZ[0]).collect_coverage (c->input);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001970
Behdad Esfahbod0382b712018-11-02 12:23:26 -04001971 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001972 struct ContextCollectGlyphsLookupContext lookup_context = {
1973 {collect_coverage},
Behdad Esfahbode75943d2012-11-30 08:38:24 +02001974 this
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001975 };
1976
1977 context_collect_glyphs_lookup (c,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001978 glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001979 lookupCount, lookupRecord,
1980 lookup_context);
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001981 }
1982
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301983 bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001984 {
Behdad Esfahbod0382b712018-11-02 12:23:26 -04001985 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001986 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001987 {match_coverage},
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001988 this
1989 };
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07001990 return context_would_apply_lookup (c,
1991 glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
1992 lookupCount, lookupRecord,
1993 lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001994 }
1995
Ebrahim Byagowie4120082018-12-17 21:31:01 +03301996 const Coverage &get_coverage () const { return this+coverageZ[0]; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001997
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301998 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001999 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002000 TRACE_APPLY (this);
Behdad Esfahbodfb059082018-11-30 20:45:40 -05002001 unsigned int index = (this+coverageZ[0]).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002002 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04002003
Behdad Esfahbod0382b712018-11-02 12:23:26 -04002004 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002005 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002006 {match_coverage},
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04002007 this
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002008 };
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02002009 return_trace (context_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, lookup_context));
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002010 }
2011
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302012 bool subset (hb_subset_context_t *c) const
Behdad Esfahbod339d3602018-09-03 17:33:34 -07002013 {
2014 TRACE_SUBSET (this);
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002015 auto *out = c->serializer->start_embed (this);
2016 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
2017
2018 out->format = format;
2019 out->glyphCount = glyphCount;
2020 out->lookupCount = lookupCount;
2021
2022 const hb_array_t<const OffsetTo<Coverage>> coverages = coverageZ.as_array (glyphCount);
2023
2024 for (const OffsetTo<Coverage>& offset : coverages)
2025 {
2026 auto *o = c->serializer->allocate_size<OffsetTo<Coverage>> (OffsetTo<Coverage>::static_size);
2027 if (unlikely (!o)) return_trace (false);
2028 if (!o->serialize_subset (c, offset, this)) return_trace (false);
2029 }
2030
2031 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
2032 const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
2033 for (unsigned i = 0; i < (unsigned) lookupCount; i++)
2034 c->serializer->copy (lookupRecord[i], lookup_map);
2035
2036 return_trace (true);
Behdad Esfahbod339d3602018-09-03 17:33:34 -07002037 }
2038
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302039 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002040 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002041 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002042 if (!c->check_struct (this)) return_trace (false);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002043 unsigned int count = glyphCount;
Behdad Esfahbodfb059082018-11-30 20:45:40 -05002044 if (!count) return_trace (false); /* We want to access coverageZ[0] freely. */
Behdad Esfahbod9507b052018-09-10 23:18:07 +02002045 if (!c->check_array (coverageZ.arrayZ, count)) return_trace (false);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002046 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002047 if (!coverageZ[i].sanitize (c, this)) return_trace (false);
Behdad Esfahbod0382b712018-11-02 12:23:26 -04002048 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
Behdad Esfahbod9507b052018-09-10 23:18:07 +02002049 return_trace (c->check_array (lookupRecord, lookupCount));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002050 }
2051
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002052 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002053 HBUINT16 format; /* Format identifier--format = 3 */
2054 HBUINT16 glyphCount; /* Number of glyphs in the input glyph
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002055 * sequence */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002056 HBUINT16 lookupCount; /* Number of LookupRecords */
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002057 UnsizedArrayOf<OffsetTo<Coverage>>
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02002058 coverageZ; /* Array of offsets to Coverage
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002059 * table in glyph sequence order */
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02002060/*UnsizedArrayOf<LookupRecord>
2061 lookupRecordX;*/ /* Array of LookupRecords--in
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002062 * design order */
Behdad Esfahbod569da922010-05-10 16:38:32 -04002063 public:
Behdad Esfahbod6d7c6e12018-02-07 14:09:56 -06002064 DEFINE_SIZE_ARRAY (6, coverageZ);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002065};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002066
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002067struct Context
2068{
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -07002069 template <typename context_t, typename ...Ts>
Behdad Esfahbod83e3eab2019-05-07 20:58:43 -07002070 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002071 {
Behdad Esfahbod00f6a8e2014-12-12 20:36:49 -08002072 TRACE_DISPATCH (this, u.format);
Behdad Esfahbodf396fbb2015-10-09 12:25:55 -04002073 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002074 switch (u.format) {
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -07002075 case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
2076 case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
2077 case 3: return_trace (c->dispatch (u.format3, hb_forward<Ts> (ds)...));
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002078 default:return_trace (c->default_return_value ());
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002079 }
2080 }
2081
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002082 protected:
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002083 union {
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002084 HBUINT16 format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -04002085 ContextFormat1 format1;
2086 ContextFormat2 format2;
2087 ContextFormat3 format3;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002088 } u;
2089};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002090
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002091
2092/* Chaining Contextual lookups */
2093
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002094struct ChainContextClosureLookupContext
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002095{
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002096 ContextClosureFuncs funcs;
2097 const void *intersects_data[3];
2098};
2099
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002100struct ChainContextCollectGlyphsLookupContext
2101{
2102 ContextCollectGlyphsFuncs funcs;
2103 const void *collect_data[3];
2104};
2105
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002106struct ChainContextApplyLookupContext
2107{
2108 ContextApplyFuncs funcs;
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04002109 const void *match_data[3];
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04002110};
2111
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002112static inline bool chain_context_intersects (const hb_set_t *glyphs,
2113 unsigned int backtrackCount,
2114 const HBUINT16 backtrack[],
2115 unsigned int inputCount, /* Including the first glyph (not matched) */
2116 const HBUINT16 input[], /* Array of input values--start with second glyph */
2117 unsigned int lookaheadCount,
2118 const HBUINT16 lookahead[],
2119 ChainContextClosureLookupContext &lookup_context)
2120{
Qunxin Liu44d88cf2020-05-08 15:33:34 -07002121 return array_is_subset_of (glyphs,
2122 backtrackCount, backtrack,
2123 lookup_context.funcs.intersects, lookup_context.intersects_data[0])
2124 && array_is_subset_of (glyphs,
2125 inputCount ? inputCount - 1 : 0, input,
2126 lookup_context.funcs.intersects, lookup_context.intersects_data[1])
2127 && array_is_subset_of (glyphs,
2128 lookaheadCount, lookahead,
2129 lookup_context.funcs.intersects, lookup_context.intersects_data[2]);
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002130}
2131
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002132static inline void chain_context_closure_lookup (hb_closure_context_t *c,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002133 unsigned int backtrackCount,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002134 const HBUINT16 backtrack[],
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002135 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002136 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002137 unsigned int lookaheadCount,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002138 const HBUINT16 lookahead[],
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002139 unsigned int lookupCount,
2140 const LookupRecord lookupRecord[],
2141 ChainContextClosureLookupContext &lookup_context)
2142{
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002143 if (chain_context_intersects (c->glyphs,
2144 backtrackCount, backtrack,
2145 inputCount, input,
2146 lookaheadCount, lookahead,
2147 lookup_context))
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05002148 recurse_lookups (c,
2149 lookupCount, lookupRecord);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002150}
2151
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002152static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03302153 unsigned int backtrackCount,
2154 const HBUINT16 backtrack[],
2155 unsigned int inputCount, /* Including the first glyph (not matched) */
2156 const HBUINT16 input[], /* Array of input values--start with second glyph */
2157 unsigned int lookaheadCount,
2158 const HBUINT16 lookahead[],
2159 unsigned int lookupCount,
2160 const LookupRecord lookupRecord[],
2161 ChainContextCollectGlyphsLookupContext &lookup_context)
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002162{
Behdad Esfahbod83035932012-12-04 17:08:41 -05002163 collect_array (c, c->before,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002164 backtrackCount, backtrack,
2165 lookup_context.funcs.collect, lookup_context.collect_data[0]);
Behdad Esfahbod83035932012-12-04 17:08:41 -05002166 collect_array (c, c->input,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002167 inputCount ? inputCount - 1 : 0, input,
2168 lookup_context.funcs.collect, lookup_context.collect_data[1]);
Behdad Esfahbod83035932012-12-04 17:08:41 -05002169 collect_array (c, c->after,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002170 lookaheadCount, lookahead,
2171 lookup_context.funcs.collect, lookup_context.collect_data[2]);
2172 recurse_lookups (c,
2173 lookupCount, lookupRecord);
2174}
2175
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002176static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c,
2177 unsigned int backtrackCount,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002178 const HBUINT16 backtrack[] HB_UNUSED,
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002179 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002180 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002181 unsigned int lookaheadCount,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002182 const HBUINT16 lookahead[] HB_UNUSED,
Behdad Esfahbod0beb66e2012-12-05 18:46:04 -05002183 unsigned int lookupCount HB_UNUSED,
2184 const LookupRecord lookupRecord[] HB_UNUSED,
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002185 ChainContextApplyLookupContext &lookup_context)
2186{
Behdad Esfahbodd9b204d2012-08-23 16:22:28 -04002187 return (c->zero_context ? !backtrackCount && !lookaheadCount : true)
Behdad Esfahbod1f2bb172012-08-23 16:10:37 -04002188 && would_match_input (c,
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002189 inputCount, input,
2190 lookup_context.funcs.match, lookup_context.match_data[1]);
2191}
2192
Behdad Esfahbodfd034492018-01-17 16:46:51 -08002193static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002194 unsigned int backtrackCount,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002195 const HBUINT16 backtrack[],
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002196 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002197 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002198 unsigned int lookaheadCount,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002199 const HBUINT16 lookahead[],
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002200 unsigned int lookupCount,
2201 const LookupRecord lookupRecord[],
2202 ChainContextApplyLookupContext &lookup_context)
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04002203{
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02002204 unsigned int start_index = 0, match_length = 0, end_index = 0;
Behdad Esfahbod5ba45042015-11-02 15:43:08 -08002205 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
Behdad Esfahbodf19e0b02012-06-09 02:26:57 -04002206 return match_input (c,
Behdad Esfahbod41697102010-05-05 01:37:58 -04002207 inputCount, input,
2208 lookup_context.funcs.match, lookup_context.match_data[1],
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02002209 &match_length, match_positions)
Behdad Esfahbodf19e0b02012-06-09 02:26:57 -04002210 && match_backtrack (c,
2211 backtrackCount, backtrack,
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02002212 lookup_context.funcs.match, lookup_context.match_data[0],
2213 &start_index)
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04002214 && match_lookahead (c,
Behdad Esfahbod41697102010-05-05 01:37:58 -04002215 lookaheadCount, lookahead,
2216 lookup_context.funcs.match, lookup_context.match_data[2],
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02002217 match_length, &end_index)
2218 && (c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index),
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03302219 apply_lookup (c,
2220 inputCount, match_positions,
2221 lookupCount, lookupRecord,
2222 match_length));
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04002223}
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04002224
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002225struct ChainRule
2226{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302227 bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002228 {
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002229 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
2230 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002231 return chain_context_intersects (glyphs,
2232 backtrack.len, backtrack.arrayZ,
Behdad Esfahbodeffc7ce2018-09-13 20:21:54 +02002233 input.lenP1, input.arrayZ,
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002234 lookahead.len, lookahead.arrayZ,
2235 lookup_context);
2236 }
2237
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302238 void closure (hb_closure_context_t *c,
2239 ChainContextClosureLookupContext &lookup_context) const
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002240 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04302241 if (unlikely (c->lookup_limit_exceeded ())) return;
Garret Rieger4ad686b2020-03-25 23:32:28 -07002242
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002243 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
2244 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
2245 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002246 chain_context_closure_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002247 backtrack.len, backtrack.arrayZ,
Behdad Esfahbodeffc7ce2018-09-13 20:21:54 +02002248 input.lenP1, input.arrayZ,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002249 lookahead.len, lookahead.arrayZ,
2250 lookup.len, lookup.arrayZ,
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002251 lookup_context);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002252 }
2253
Qunxin Liu0b39c482019-10-22 16:00:43 -07002254 void closure_lookups (hb_closure_lookups_context_t *c) const
2255 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04302256 if (unlikely (c->lookup_limit_exceeded ())) return;
Garret Rieger4ad686b2020-03-25 23:32:28 -07002257
Qunxin Liu0b39c482019-10-22 16:00:43 -07002258 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
2259 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
2260 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
2261 recurse_lookups (c, lookup.len, lookup.arrayZ);
2262 }
2263
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302264 void collect_glyphs (hb_collect_glyphs_context_t *c,
2265 ChainContextCollectGlyphsLookupContext &lookup_context) const
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002266 {
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002267 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
2268 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
2269 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002270 chain_context_collect_glyphs_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002271 backtrack.len, backtrack.arrayZ,
Behdad Esfahbodeffc7ce2018-09-13 20:21:54 +02002272 input.lenP1, input.arrayZ,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002273 lookahead.len, lookahead.arrayZ,
2274 lookup.len, lookup.arrayZ,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002275 lookup_context);
2276 }
2277
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302278 bool would_apply (hb_would_apply_context_t *c,
2279 ChainContextApplyLookupContext &lookup_context) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002280 {
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002281 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
2282 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
2283 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07002284 return chain_context_would_apply_lookup (c,
2285 backtrack.len, backtrack.arrayZ,
2286 input.lenP1, input.arrayZ,
2287 lookahead.len, lookahead.arrayZ, lookup.len,
2288 lookup.arrayZ, lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002289 }
2290
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302291 bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002292 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002293 TRACE_APPLY (this);
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002294 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
2295 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
2296 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002297 return_trace (chain_context_apply_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002298 backtrack.len, backtrack.arrayZ,
Behdad Esfahbodeffc7ce2018-09-13 20:21:54 +02002299 input.lenP1, input.arrayZ,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002300 lookahead.len, lookahead.arrayZ, lookup.len,
2301 lookup.arrayZ, lookup_context));
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002302 }
2303
Qunxin Liub66094a2019-09-30 16:19:18 -07002304 template<typename Iterator,
2305 hb_requires (hb_is_iterator (Iterator))>
2306 void serialize_array (hb_serialize_context_t *c,
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04302307 HBUINT16 len,
2308 Iterator it) const
Qunxin Liub66094a2019-09-30 16:19:18 -07002309 {
2310 c->copy (len);
2311 for (const auto g : it)
2312 {
2313 HBUINT16 gid;
2314 gid = g;
2315 c->copy (gid);
2316 }
2317 }
2318
2319 ChainRule* copy (hb_serialize_context_t *c,
2320 const hb_map_t *backtrack_map,
2321 const hb_map_t *input_map = nullptr,
2322 const hb_map_t *lookahead_map = nullptr) const
2323 {
2324 TRACE_SERIALIZE (this);
2325 auto *out = c->start_embed (this);
2326 if (unlikely (!out)) return_trace (nullptr);
2327
2328 const hb_map_t *mapping = backtrack_map;
2329 serialize_array (c, backtrack.len, + backtrack.iter ()
2330 | hb_map (mapping));
2331
2332 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
2333 if (input_map) mapping = input_map;
2334 serialize_array (c, input.lenP1, + input.iter ()
2335 | hb_map (mapping));
2336
2337 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
2338 if (lookahead_map) mapping = lookahead_map;
2339 serialize_array (c, lookahead.len, + lookahead.iter ()
2340 | hb_map (mapping));
2341
2342 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
2343 c->copy (lookup);
2344
2345 return_trace (out);
2346 }
2347
2348 bool subset (hb_subset_context_t *c,
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04302349 const hb_map_t *backtrack_map = nullptr,
2350 const hb_map_t *input_map = nullptr,
2351 const hb_map_t *lookahead_map = nullptr) const
Qunxin Liub66094a2019-09-30 16:19:18 -07002352 {
2353 TRACE_SUBSET (this);
2354
Qunxin Liub2fcca62019-10-24 15:15:26 -07002355 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
2356 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
2357
Qunxin Liub66094a2019-09-30 16:19:18 -07002358 if (!backtrack_map)
2359 {
2360 const hb_set_t &glyphset = *c->plan->glyphset ();
2361 if (!hb_all (backtrack, glyphset) ||
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04302362 !hb_all (input, glyphset) ||
2363 !hb_all (lookahead, glyphset))
2364 return_trace (false);
Qunxin Liub66094a2019-09-30 16:19:18 -07002365
2366 copy (c->serializer, c->plan->glyph_map);
2367 }
2368 else
2369 {
2370 if (!hb_all (backtrack, backtrack_map) ||
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04302371 !hb_all (input, input_map) ||
2372 !hb_all (lookahead, lookahead_map))
2373 return_trace (false);
Ebrahim Byagowiaca63902019-10-22 00:06:46 +03302374
Qunxin Liub66094a2019-09-30 16:19:18 -07002375 copy (c->serializer, backtrack_map, input_map, lookahead_map);
2376 }
2377
2378 return_trace (true);
2379 }
2380
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302381 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002382 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002383 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002384 if (!backtrack.sanitize (c)) return_trace (false);
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002385 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002386 if (!input.sanitize (c)) return_trace (false);
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002387 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002388 if (!lookahead.sanitize (c)) return_trace (false);
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002389 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002390 return_trace (lookup.sanitize (c));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002391 }
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002392
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002393 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002394 ArrayOf<HBUINT16>
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04002395 backtrack; /* Array of backtracking values
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002396 * (to be matched before the input
2397 * sequence) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002398 HeadlessArrayOf<HBUINT16>
Behdad Esfahbode8cbaaf2009-05-18 02:03:58 -04002399 inputX; /* Array of input values (start with
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002400 * second glyph) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002401 ArrayOf<HBUINT16>
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04002402 lookaheadX; /* Array of lookahead values's (to be
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04002403 * matched after the input sequence) */
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04002404 ArrayOf<LookupRecord>
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04002405 lookupX; /* Array of LookupRecords--in
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002406 * design order) */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04002407 public:
Behdad Esfahbodbea34c72010-05-10 17:28:16 -04002408 DEFINE_SIZE_MIN (8);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002409};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002410
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002411struct ChainRuleSet
2412{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302413 bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002414 {
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002415 return
2416 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002417 | hb_map (hb_add (this))
2418 | hb_map ([&] (const ChainRule &_) { return _.intersects (glyphs, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002419 | hb_any
2420 ;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002421 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302422 void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002423 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04302424 if (unlikely (c->lookup_limit_exceeded ())) return;
Garret Rieger4ad686b2020-03-25 23:32:28 -07002425
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002426 return
2427 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002428 | hb_map (hb_add (this))
2429 | hb_apply ([&] (const ChainRule &_) { _.closure (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002430 ;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002431 }
2432
Qunxin Liu0b39c482019-10-22 16:00:43 -07002433 void closure_lookups (hb_closure_lookups_context_t *c) const
2434 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04302435 if (unlikely (c->lookup_limit_exceeded ())) return;
Garret Rieger4ad686b2020-03-25 23:32:28 -07002436
Qunxin Liu0b39c482019-10-22 16:00:43 -07002437 return
2438 + hb_iter (rule)
2439 | hb_map (hb_add (this))
2440 | hb_apply ([&] (const ChainRule &_) { _.closure_lookups (c); })
2441 ;
2442 }
2443
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302444 void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002445 {
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002446 return
2447 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002448 | hb_map (hb_add (this))
2449 | hb_apply ([&] (const ChainRule &_) { _.collect_glyphs (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002450 ;
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002451 }
2452
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302453 bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002454 {
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002455 return
2456 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002457 | hb_map (hb_add (this))
2458 | hb_map ([&] (const ChainRule &_) { return _.would_apply (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002459 | hb_any
2460 ;
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002461 }
2462
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302463 bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002464 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002465 TRACE_APPLY (this);
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002466 return_trace (
2467 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002468 | hb_map (hb_add (this))
2469 | hb_map ([&] (const ChainRule &_) { return _.apply (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002470 | hb_any
2471 )
2472 ;
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04002473 }
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002474
Qunxin Liub66094a2019-09-30 16:19:18 -07002475 bool subset (hb_subset_context_t *c,
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04302476 const hb_map_t *backtrack_klass_map = nullptr,
2477 const hb_map_t *input_klass_map = nullptr,
2478 const hb_map_t *lookahead_klass_map = nullptr) const
Qunxin Liub66094a2019-09-30 16:19:18 -07002479 {
2480 TRACE_SUBSET (this);
2481
2482 auto snap = c->serializer->snapshot ();
2483 auto *out = c->serializer->start_embed (*this);
2484 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
2485
2486 for (const OffsetTo<ChainRule>& _ : rule)
2487 {
2488 if (!_) continue;
2489 auto *o = out->rule.serialize_append (c->serializer);
2490 if (unlikely (!o)) continue;
Ebrahim Byagowiaca63902019-10-22 00:06:46 +03302491
Qunxin Liub66094a2019-09-30 16:19:18 -07002492 auto o_snap = c->serializer->snapshot ();
ariza188a0a42020-03-07 11:02:36 -08002493 if (!o->serialize_subset (c, _, this,
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04302494 backtrack_klass_map,
2495 input_klass_map,
2496 lookahead_klass_map))
Qunxin Liub66094a2019-09-30 16:19:18 -07002497 {
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04302498 out->rule.pop ();
2499 c->serializer->revert (o_snap);
Qunxin Liub66094a2019-09-30 16:19:18 -07002500 }
2501 }
2502
2503 bool ret = bool (out->rule);
2504 if (!ret) c->serializer->revert (snap);
Ebrahim Byagowiaca63902019-10-22 00:06:46 +03302505
Qunxin Liub66094a2019-09-30 16:19:18 -07002506 return_trace (ret);
2507 }
2508
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302509 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002510 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002511 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002512 return_trace (rule.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002513 }
2514
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002515 protected:
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04002516 OffsetArrayOf<ChainRule>
2517 rule; /* Array of ChainRule tables
2518 * ordered by preference */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04002519 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04002520 DEFINE_SIZE_ARRAY (2, rule);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002521};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002522
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002523struct ChainContextFormat1
2524{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302525 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002526 {
2527 struct ChainContextClosureLookupContext lookup_context = {
2528 {intersects_glyph},
2529 {nullptr, nullptr, nullptr}
2530 };
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002531
2532 return
2533 + hb_zip (this+coverage, ruleSet)
2534 | hb_filter (*glyphs, hb_first)
2535 | hb_map (hb_second)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002536 | hb_map (hb_add (this))
2537 | hb_map ([&] (const ChainRuleSet &_) { return _.intersects (glyphs, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002538 | hb_any
2539 ;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002540 }
2541
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302542 void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002543 {
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002544 struct ChainContextClosureLookupContext lookup_context = {
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002545 {intersects_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02002546 {nullptr, nullptr, nullptr}
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002547 };
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002548
2549 + hb_zip (this+coverage, ruleSet)
2550 | hb_filter (*c->glyphs, hb_first)
2551 | hb_map (hb_second)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002552 | hb_map (hb_add (this))
2553 | hb_apply ([&] (const ChainRuleSet &_) { _.closure (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002554 ;
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002555 }
2556
Qunxin Liu0b39c482019-10-22 16:00:43 -07002557 void closure_lookups (hb_closure_lookups_context_t *c) const
2558 {
2559 + hb_iter (ruleSet)
2560 | hb_map (hb_add (this))
2561 | hb_apply ([&] (const ChainRuleSet &_) { _.closure_lookups (c); })
2562 ;
2563 }
2564
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302565 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002566 {
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07002567 (this+coverage).collect_coverage (c->input);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002568
2569 struct ChainContextCollectGlyphsLookupContext lookup_context = {
2570 {collect_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02002571 {nullptr, nullptr, nullptr}
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002572 };
2573
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002574 + hb_iter (ruleSet)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002575 | hb_map (hb_add (this))
2576 | hb_apply ([&] (const ChainRuleSet &_) { _.collect_glyphs (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002577 ;
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002578 }
2579
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302580 bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002581 {
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05002582 const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002583 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002584 {match_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02002585 {nullptr, nullptr, nullptr}
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002586 };
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07002587 return rule_set.would_apply (c, lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002588 }
2589
Ebrahim Byagowie4120082018-12-17 21:31:01 +03302590 const Coverage &get_coverage () const { return this+coverage; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002591
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302592 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002593 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002594 TRACE_APPLY (this);
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05002595 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002596 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002597
2598 const ChainRuleSet &rule_set = this+ruleSet[index];
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002599 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002600 {match_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02002601 {nullptr, nullptr, nullptr}
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002602 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002603 return_trace (rule_set.apply (c, lookup_context));
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002604 }
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002605
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302606 bool subset (hb_subset_context_t *c) const
Behdad Esfahbod339d3602018-09-03 17:33:34 -07002607 {
2608 TRACE_SUBSET (this);
Qunxin Liub66094a2019-09-30 16:19:18 -07002609 const hb_set_t &glyphset = *c->plan->glyphset ();
2610 const hb_map_t &glyph_map = *c->plan->glyph_map;
2611
2612 auto *out = c->serializer->start_embed (*this);
2613 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
2614 out->format = format;
2615
2616 hb_sorted_vector_t<hb_codepoint_t> new_coverage;
2617 + hb_zip (this+coverage, ruleSet)
2618 | hb_filter (glyphset, hb_first)
ariza188a0a42020-03-07 11:02:36 -08002619 | hb_filter (subset_offset_array (c, out->ruleSet, this), hb_second)
Qunxin Liub66094a2019-09-30 16:19:18 -07002620 | hb_map (hb_first)
2621 | hb_map (glyph_map)
2622 | hb_sink (new_coverage)
2623 ;
2624
2625 out->coverage.serialize (c->serializer, out)
2626 .serialize (c->serializer, new_coverage.iter ());
2627 return_trace (bool (new_coverage));
Behdad Esfahbod339d3602018-09-03 17:33:34 -07002628 }
2629
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302630 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002631 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002632 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002633 return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002634 }
2635
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002636 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002637 HBUINT16 format; /* Format identifier--format = 1 */
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04002638 OffsetTo<Coverage>
2639 coverage; /* Offset to Coverage table--from
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002640 * beginning of table */
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002641 OffsetArrayOf<ChainRuleSet>
2642 ruleSet; /* Array of ChainRuleSet tables
2643 * ordered by Coverage Index */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04002644 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04002645 DEFINE_SIZE_ARRAY (6, ruleSet);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002646};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002647
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002648struct ChainContextFormat2
2649{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302650 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002651 {
2652 if (!(this+coverage).intersects (glyphs))
2653 return false;
2654
2655 const ClassDef &backtrack_class_def = this+backtrackClassDef;
2656 const ClassDef &input_class_def = this+inputClassDef;
2657 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2658
2659 struct ChainContextClosureLookupContext lookup_context = {
2660 {intersects_class},
2661 {&backtrack_class_def,
2662 &input_class_def,
2663 &lookahead_class_def}
2664 };
2665
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07002666 return
2667 + hb_enumerate (ruleSet)
Behdad Esfahbod78d35f02019-05-15 18:15:05 -07002668 | hb_map ([&] (const hb_pair_t<unsigned, const OffsetTo<ChainRuleSet> &> p)
2669 { return input_class_def.intersects_class (glyphs, p.first) &&
2670 (this+p.second).intersects (glyphs, lookup_context); })
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07002671 | hb_any
2672 ;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002673 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302674 void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002675 {
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002676 if (!(this+coverage).intersects (c->glyphs))
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002677 return;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002678
2679 const ClassDef &backtrack_class_def = this+backtrackClassDef;
2680 const ClassDef &input_class_def = this+inputClassDef;
2681 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2682
2683 struct ChainContextClosureLookupContext lookup_context = {
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002684 {intersects_class},
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002685 {&backtrack_class_def,
2686 &input_class_def,
2687 &lookahead_class_def}
2688 };
2689
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07002690 return
2691 + hb_enumerate (ruleSet)
Behdad Esfahbod78d35f02019-05-15 18:15:05 -07002692 | hb_filter ([&] (unsigned _)
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07002693 { return input_class_def.intersects_class (c->glyphs, _); },
2694 hb_first)
2695 | hb_map (hb_second)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002696 | hb_map (hb_add (this))
2697 | hb_apply ([&] (const ChainRuleSet &_) { _.closure (c, lookup_context); })
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07002698 ;
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002699 }
2700
Qunxin Liu0b39c482019-10-22 16:00:43 -07002701 void closure_lookups (hb_closure_lookups_context_t *c) const
2702 {
2703 + hb_iter (ruleSet)
2704 | hb_map (hb_add (this))
2705 | hb_apply ([&] (const ChainRuleSet &_) { _.closure_lookups (c); })
2706 ;
2707 }
2708
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302709 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002710 {
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07002711 (this+coverage).collect_coverage (c->input);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002712
Behdad Esfahbod11fba792013-01-02 23:36:37 -06002713 const ClassDef &backtrack_class_def = this+backtrackClassDef;
2714 const ClassDef &input_class_def = this+inputClassDef;
2715 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2716
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002717 struct ChainContextCollectGlyphsLookupContext lookup_context = {
2718 {collect_class},
Behdad Esfahbod11fba792013-01-02 23:36:37 -06002719 {&backtrack_class_def,
2720 &input_class_def,
2721 &lookahead_class_def}
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002722 };
2723
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002724 + hb_iter (ruleSet)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002725 | hb_map (hb_add (this))
2726 | hb_apply ([&] (const ChainRuleSet &_) { _.collect_glyphs (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002727 ;
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002728 }
2729
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302730 bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002731 {
Behdad Esfahbod11fba792013-01-02 23:36:37 -06002732 const ClassDef &backtrack_class_def = this+backtrackClassDef;
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002733 const ClassDef &input_class_def = this+inputClassDef;
Behdad Esfahbod11fba792013-01-02 23:36:37 -06002734 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002735
Behdad Esfahbod2dc11412012-11-24 19:16:34 -05002736 unsigned int index = input_class_def.get_class (c->glyphs[0]);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002737 const ChainRuleSet &rule_set = this+ruleSet[index];
2738 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002739 {match_class},
Behdad Esfahbod11fba792013-01-02 23:36:37 -06002740 {&backtrack_class_def,
2741 &input_class_def,
2742 &lookahead_class_def}
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002743 };
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07002744 return rule_set.would_apply (c, lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002745 }
2746
Ebrahim Byagowie4120082018-12-17 21:31:01 +03302747 const Coverage &get_coverage () const { return this+coverage; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002748
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302749 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002750 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002751 TRACE_APPLY (this);
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05002752 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002753 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002754
2755 const ClassDef &backtrack_class_def = this+backtrackClassDef;
2756 const ClassDef &input_class_def = this+inputClassDef;
2757 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2758
Behdad Esfahbod2dc11412012-11-24 19:16:34 -05002759 index = input_class_def.get_class (c->buffer->cur().codepoint);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002760 const ChainRuleSet &rule_set = this+ruleSet[index];
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002761 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002762 {match_class},
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04002763 {&backtrack_class_def,
2764 &input_class_def,
2765 &lookahead_class_def}
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002766 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002767 return_trace (rule_set.apply (c, lookup_context));
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002768 }
2769
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302770 bool subset (hb_subset_context_t *c) const
Behdad Esfahbod339d3602018-09-03 17:33:34 -07002771 {
2772 TRACE_SUBSET (this);
Qunxin Liub66094a2019-09-30 16:19:18 -07002773 auto *out = c->serializer->start_embed (*this);
2774 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
2775 out->format = format;
ariza188a0a42020-03-07 11:02:36 -08002776 out->coverage.serialize_subset (c, coverage, this);
Qunxin Liub66094a2019-09-30 16:19:18 -07002777
2778 hb_map_t backtrack_klass_map;
ariza188a0a42020-03-07 11:02:36 -08002779 out->backtrackClassDef.serialize_subset (c, backtrackClassDef, this, &backtrack_klass_map);
Ebrahim Byagowiaca63902019-10-22 00:06:46 +03302780
Qunxin Liub66094a2019-09-30 16:19:18 -07002781 // subset inputClassDef based on glyphs survived in Coverage subsetting
2782 hb_map_t input_klass_map;
ariza188a0a42020-03-07 11:02:36 -08002783 out->inputClassDef.serialize_subset (c, inputClassDef, this, &input_klass_map);
Qunxin Liub66094a2019-09-30 16:19:18 -07002784
2785 hb_map_t lookahead_klass_map;
ariza188a0a42020-03-07 11:02:36 -08002786 out->lookaheadClassDef.serialize_subset (c, lookaheadClassDef, this, &lookahead_klass_map);
Qunxin Liub66094a2019-09-30 16:19:18 -07002787
2788 hb_vector_t<unsigned> rulesets;
2789 bool ret = true;
2790 for (const OffsetTo<ChainRuleSet>& _ : + hb_enumerate (ruleSet)
2791 | hb_filter (input_klass_map, hb_first)
2792 | hb_map (hb_second))
2793 {
2794 auto *o = out->ruleSet.serialize_append (c->serializer);
2795 if (unlikely (!o))
2796 {
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04302797 ret = false;
2798 break;
Qunxin Liub66094a2019-09-30 16:19:18 -07002799 }
ariza188a0a42020-03-07 11:02:36 -08002800 if (!o->serialize_subset (c, _, this,
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04302801 &backtrack_klass_map,
2802 &input_klass_map,
2803 &lookahead_klass_map))
Qunxin Liub66094a2019-09-30 16:19:18 -07002804 {
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04302805 rulesets.push (0);
Qunxin Liub66094a2019-09-30 16:19:18 -07002806 }
2807 else rulesets.push (1);
2808 }
2809
2810 if (!ret) return_trace (ret);
2811
2812 //prune empty trailing ruleSets
2813 unsigned count = rulesets.length;
2814 while (count > 0 && rulesets[count-1] == 0)
2815 {
2816 out->ruleSet.pop ();
2817 count--;
2818 }
2819
2820 return_trace (bool (out->ruleSet));
Behdad Esfahbod339d3602018-09-03 17:33:34 -07002821 }
2822
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302823 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002824 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002825 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002826 return_trace (coverage.sanitize (c, this) &&
2827 backtrackClassDef.sanitize (c, this) &&
2828 inputClassDef.sanitize (c, this) &&
2829 lookaheadClassDef.sanitize (c, this) &&
2830 ruleSet.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002831 }
2832
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002833 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002834 HBUINT16 format; /* Format identifier--format = 2 */
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002835 OffsetTo<Coverage>
2836 coverage; /* Offset to Coverage table--from
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002837 * beginning of table */
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002838 OffsetTo<ClassDef>
2839 backtrackClassDef; /* Offset to glyph ClassDef table
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002840 * containing backtrack sequence
2841 * data--from beginning of table */
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002842 OffsetTo<ClassDef>
2843 inputClassDef; /* Offset to glyph ClassDef
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002844 * table containing input sequence
2845 * data--from beginning of table */
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002846 OffsetTo<ClassDef>
2847 lookaheadClassDef; /* Offset to glyph ClassDef table
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002848 * containing lookahead sequence
2849 * data--from beginning of table */
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002850 OffsetArrayOf<ChainRuleSet>
2851 ruleSet; /* Array of ChainRuleSet tables
2852 * ordered by class */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04002853 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04002854 DEFINE_SIZE_ARRAY (12, ruleSet);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002855};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002856
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002857struct ChainContextFormat3
2858{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302859 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002860 {
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002861 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002862
2863 if (!(this+input[0]).intersects (glyphs))
2864 return false;
2865
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002866 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002867 struct ChainContextClosureLookupContext lookup_context = {
2868 {intersects_coverage},
2869 {this, this, this}
2870 };
2871 return chain_context_intersects (glyphs,
2872 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2873 input.len, (const HBUINT16 *) input.arrayZ + 1,
2874 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2875 lookup_context);
2876 }
2877
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302878 void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002879 {
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002880 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002881
2882 if (!(this+input[0]).intersects (c->glyphs))
2883 return;
2884
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002885 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
2886 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002887 struct ChainContextClosureLookupContext lookup_context = {
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002888 {intersects_coverage},
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002889 {this, this, this}
2890 };
2891 chain_context_closure_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002892 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2893 input.len, (const HBUINT16 *) input.arrayZ + 1,
2894 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2895 lookup.len, lookup.arrayZ,
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002896 lookup_context);
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002897 }
2898
Qunxin Liu0b39c482019-10-22 16:00:43 -07002899 void closure_lookups (hb_closure_lookups_context_t *c) const
2900 {
2901 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
2902 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
2903 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
2904 recurse_lookups (c, lookup.len, lookup.arrayZ);
2905 }
2906
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302907 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002908 {
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002909 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002910
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07002911 (this+input[0]).collect_coverage (c->input);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002912
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002913 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
2914 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002915 struct ChainContextCollectGlyphsLookupContext lookup_context = {
2916 {collect_coverage},
2917 {this, this, this}
2918 };
2919 chain_context_collect_glyphs_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002920 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2921 input.len, (const HBUINT16 *) input.arrayZ + 1,
2922 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2923 lookup.len, lookup.arrayZ,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002924 lookup_context);
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002925 }
2926
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302927 bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002928 {
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002929 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
2930 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
2931 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002932 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002933 {match_coverage},
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002934 {this, this, this}
2935 };
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07002936 return chain_context_would_apply_lookup (c,
2937 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2938 input.len, (const HBUINT16 *) input.arrayZ + 1,
2939 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2940 lookup.len, lookup.arrayZ, lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002941 }
2942
Ebrahim Byagowie4120082018-12-17 21:31:01 +03302943 const Coverage &get_coverage () const
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002944 {
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002945 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002946 return this+input[0];
2947 }
2948
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302949 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002950 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002951 TRACE_APPLY (this);
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002952 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04002953
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05002954 unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002955 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002956
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002957 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
2958 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002959 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002960 {match_coverage},
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04002961 {this, this, this}
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04002962 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002963 return_trace (chain_context_apply_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002964 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2965 input.len, (const HBUINT16 *) input.arrayZ + 1,
2966 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2967 lookup.len, lookup.arrayZ, lookup_context));
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002968 }
2969
Qunxin Liub66094a2019-09-30 16:19:18 -07002970 template<typename Iterator,
2971 hb_requires (hb_is_iterator (Iterator))>
Ebrahim Byagowi07acd1a2020-03-08 23:39:24 +03302972 bool serialize_coverage_offsets (hb_subset_context_t *c, Iterator it, const void* base) const
Qunxin Liub66094a2019-09-30 16:19:18 -07002973 {
2974 TRACE_SERIALIZE (this);
2975 auto *out = c->serializer->start_embed<OffsetArrayOf<Coverage>> ();
2976
2977 if (unlikely (!c->serializer->allocate_size<HBUINT16> (HBUINT16::static_size))) return_trace (false);
2978
2979 + it
Ebrahim Byagowi07acd1a2020-03-08 23:39:24 +03302980 | hb_apply (subset_offset_array (c, *out, base))
Qunxin Liub66094a2019-09-30 16:19:18 -07002981 ;
2982
2983 return_trace (out->len);
2984 }
2985
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302986 bool subset (hb_subset_context_t *c) const
Behdad Esfahbod339d3602018-09-03 17:33:34 -07002987 {
2988 TRACE_SUBSET (this);
Qunxin Liub66094a2019-09-30 16:19:18 -07002989
2990 auto *out = c->serializer->start_embed (this);
2991 if (unlikely (!out)) return_trace (false);
2992 if (unlikely (!c->serializer->embed (this->format))) return_trace (false);
2993
ariza188a0a42020-03-07 11:02:36 -08002994 if (!serialize_coverage_offsets (c, backtrack.iter (), this))
Qunxin Liub66094a2019-09-30 16:19:18 -07002995 return_trace (false);
Ebrahim Byagowiaca63902019-10-22 00:06:46 +03302996
Qunxin Liub66094a2019-09-30 16:19:18 -07002997 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
ariza188a0a42020-03-07 11:02:36 -08002998 if (!serialize_coverage_offsets (c, input.iter (), this))
Qunxin Liub66094a2019-09-30 16:19:18 -07002999 return_trace (false);
3000
3001 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
ariza188a0a42020-03-07 11:02:36 -08003002 if (!serialize_coverage_offsets (c, lookahead.iter (), this))
Qunxin Liub66094a2019-09-30 16:19:18 -07003003 return_trace (false);
Ebrahim Byagowiaca63902019-10-22 00:06:46 +03303004
Qunxin Liub66094a2019-09-30 16:19:18 -07003005 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
3006 return_trace (c->serializer->copy (lookup));
Behdad Esfahbod339d3602018-09-03 17:33:34 -07003007 }
3008
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303009 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03003010 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05003011 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003012 if (!backtrack.sanitize (c, this)) return_trace (false);
Ebrahim Byagowi92588782019-04-30 13:05:10 -07003013 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003014 if (!input.sanitize (c, this)) return_trace (false);
3015 if (!input.len) return_trace (false); /* To be consistent with Context. */
Ebrahim Byagowi92588782019-04-30 13:05:10 -07003016 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003017 if (!lookahead.sanitize (c, this)) return_trace (false);
Ebrahim Byagowi92588782019-04-30 13:05:10 -07003018 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003019 return_trace (lookup.sanitize (c));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04003020 }
3021
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04003022 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01003023 HBUINT16 format; /* Format identifier--format = 3 */
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04003024 OffsetArrayOf<Coverage>
Behdad Esfahbod13ed4402009-05-18 02:14:37 -04003025 backtrack; /* Array of coverage tables
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003026 * in backtracking sequence, in glyph
3027 * sequence order */
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04003028 OffsetArrayOf<Coverage>
Behdad Esfahbod13ed4402009-05-18 02:14:37 -04003029 inputX ; /* Array of coverage
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003030 * tables in input sequence, in glyph
3031 * sequence order */
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04003032 OffsetArrayOf<Coverage>
Behdad Esfahbod13ed4402009-05-18 02:14:37 -04003033 lookaheadX; /* Array of coverage tables
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003034 * in lookahead sequence, in glyph
3035 * sequence order */
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04003036 ArrayOf<LookupRecord>
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04003037 lookupX; /* Array of LookupRecords--in
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04003038 * design order) */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04003039 public:
Behdad Esfahbodbea34c72010-05-10 17:28:16 -04003040 DEFINE_SIZE_MIN (10);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003041};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003042
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04003043struct ChainContext
3044{
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -07003045 template <typename context_t, typename ...Ts>
Behdad Esfahbod83e3eab2019-05-07 20:58:43 -07003046 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04003047 {
Behdad Esfahbod00f6a8e2014-12-12 20:36:49 -08003048 TRACE_DISPATCH (this, u.format);
Behdad Esfahbodf396fbb2015-10-09 12:25:55 -04003049 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04003050 switch (u.format) {
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -07003051 case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
3052 case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
3053 case 3: return_trace (c->dispatch (u.format3, hb_forward<Ts> (ds)...));
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003054 default:return_trace (c->default_return_value ());
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003055 }
3056 }
3057
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04003058 protected:
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003059 union {
Behdad Esfahbod6b191782018-01-10 03:07:30 +01003060 HBUINT16 format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -04003061 ChainContextFormat1 format1;
3062 ChainContextFormat2 format2;
3063 ChainContextFormat3 format3;
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003064 } u;
3065};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003066
3067
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003068template <typename T>
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003069struct ExtensionFormat1
3070{
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303071 unsigned int get_type () const { return extensionLookupType; }
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003072
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003073 template <typename X>
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303074 const X& get_subtable () const
Behdad Esfahbod858b6272019-12-10 13:18:32 -06003075 { return this + reinterpret_cast<const LOffsetTo<typename T::SubTable> &> (extensionOffset); }
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003076
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -07003077 template <typename context_t, typename ...Ts>
Behdad Esfahbod83e3eab2019-05-07 20:58:43 -07003078 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003079 {
3080 TRACE_DISPATCH (this, format);
Behdad Esfahbodf396fbb2015-10-09 12:25:55 -04003081 if (unlikely (!c->may_dispatch (this, this))) return_trace (c->no_dispatch_return_value ());
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -07003082 return_trace (get_subtable<typename T::SubTable> ().dispatch (c, get_type (), hb_forward<Ts> (ds)...));
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003083 }
3084
3085 /* This is called from may_dispatch() above with hb_sanitize_context_t. */
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303086 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03003087 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05003088 TRACE_SANITIZE (this);
Behdad Esfahbod949f6af2018-01-15 20:44:10 -05003089 return_trace (c->check_struct (this) &&
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07003090 extensionLookupType != T::SubTable::Extension);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04003091 }
3092
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04003093 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01003094 HBUINT16 format; /* Format identifier. Set to 1. */
3095 HBUINT16 extensionLookupType; /* Lookup type of subtable referenced
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003096 * by ExtensionOffset (i.e. the
3097 * extension subtable). */
Behdad Esfahbodcd9bc732019-05-10 13:17:41 -07003098 Offset32 extensionOffset; /* Offset to the extension subtable,
Behdad Esfahbod81f2af42010-04-22 00:58:49 -04003099 * of lookup type subtable. */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04003100 public:
3101 DEFINE_SIZE_STATIC (8);
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003102};
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003103
Behdad Esfahbod653eeb22012-11-23 16:57:36 -05003104template <typename T>
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003105struct Extension
3106{
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303107 unsigned int get_type () const
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003108 {
3109 switch (u.format) {
Behdad Esfahboddacebca2010-05-10 19:45:41 -04003110 case 1: return u.format1.get_type ();
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003111 default:return 0;
3112 }
3113 }
Behdad Esfahbod7dddd4e2012-11-23 17:04:55 -05003114 template <typename X>
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303115 const X& get_subtable () const
Behdad Esfahbod7dddd4e2012-11-23 17:04:55 -05003116 {
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003117 switch (u.format) {
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07003118 case 1: return u.format1.template get_subtable<typename T::SubTable> ();
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04303119 default:return Null (typename T::SubTable);
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003120 }
Behdad Esfahbod7dddd4e2012-11-23 17:04:55 -05003121 }
3122
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -07003123 template <typename context_t, typename ...Ts>
Behdad Esfahbod83e3eab2019-05-07 20:58:43 -07003124 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
Behdad Esfahbod653eeb22012-11-23 16:57:36 -05003125 {
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003126 TRACE_DISPATCH (this, u.format);
Behdad Esfahbodf396fbb2015-10-09 12:25:55 -04003127 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04003128 switch (u.format) {
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -07003129 case 1: return_trace (u.format1.dispatch (c, hb_forward<Ts> (ds)...));
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003130 default:return_trace (c->default_return_value ());
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04003131 }
3132 }
3133
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04003134 protected:
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003135 union {
Behdad Esfahbod6b191782018-01-10 03:07:30 +01003136 HBUINT16 format; /* Format identifier */
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003137 ExtensionFormat1<T> format1;
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003138 } u;
3139};
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003140
3141
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04003142/*
3143 * GSUB/GPOS Common
3144 */
3145
Behdad Esfahbod97e59132018-10-10 11:41:05 -04003146struct hb_ot_layout_lookup_accelerator_t
3147{
3148 template <typename TLookup>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303149 void init (const TLookup &lookup)
Behdad Esfahbod97e59132018-10-10 11:41:05 -04003150 {
3151 digest.init ();
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07003152 lookup.collect_coverage (&digest);
Behdad Esfahbod78c09bf2018-10-10 11:50:46 -04003153
3154 subtables.init ();
3155 OT::hb_get_subtables_context_t c_get_subtables (subtables);
3156 lookup.dispatch (&c_get_subtables);
Behdad Esfahbod97e59132018-10-10 11:41:05 -04003157 }
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303158 void fini () { subtables.fini (); }
Behdad Esfahbod97e59132018-10-10 11:41:05 -04003159
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303160 bool may_have (hb_codepoint_t g) const
Behdad Esfahbod97e59132018-10-10 11:41:05 -04003161 { return digest.may_have (g); }
3162
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303163 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbode78549e2018-10-10 11:54:48 -04003164 {
Behdad Esfahbod474a1202018-12-21 18:46:51 -05003165 for (unsigned int i = 0; i < subtables.length; i++)
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03303166 if (subtables[i].apply (c))
3167 return true;
3168 return false;
Behdad Esfahbode78549e2018-10-10 11:54:48 -04003169 }
3170
3171 private:
Behdad Esfahbod97e59132018-10-10 11:41:05 -04003172 hb_set_digest_t digest;
Behdad Esfahbod78c09bf2018-10-10 11:50:46 -04003173 hb_get_subtables_context_t::array_t subtables;
Behdad Esfahbod97e59132018-10-10 11:41:05 -04003174};
3175
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04003176struct GSUBGPOS
3177{
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303178 bool has_data () const { return version.to_int (); }
3179 unsigned int get_script_count () const
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04003180 { return (this+scriptList).len; }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303181 const Tag& get_script_tag (unsigned int i) const
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04003182 { return (this+scriptList).get_tag (i); }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303183 unsigned int get_script_tags (unsigned int start_offset,
3184 unsigned int *script_count /* IN/OUT */,
3185 hb_tag_t *script_tags /* OUT */) const
Behdad Esfahbode21899b2009-11-04 16:36:14 -05003186 { return (this+scriptList).get_tags (start_offset, script_count, script_tags); }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303187 const Script& get_script (unsigned int i) const
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04003188 { return (this+scriptList)[i]; }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303189 bool find_script_index (hb_tag_t tag, unsigned int *index) const
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04003190 { return (this+scriptList).find_index (tag, index); }
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04003191
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303192 unsigned int get_feature_count () const
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04003193 { return (this+featureList).len; }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303194 hb_tag_t get_feature_tag (unsigned int i) const
Jonathan Kewda132932014-04-27 14:05:24 +01003195 { return i == Index::NOT_FOUND_INDEX ? HB_TAG_NONE : (this+featureList).get_tag (i); }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303196 unsigned int get_feature_tags (unsigned int start_offset,
3197 unsigned int *feature_count /* IN/OUT */,
3198 hb_tag_t *feature_tags /* OUT */) const
Behdad Esfahbode21899b2009-11-04 16:36:14 -05003199 { return (this+featureList).get_tags (start_offset, feature_count, feature_tags); }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303200 const Feature& get_feature (unsigned int i) const
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04003201 { return (this+featureList)[i]; }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303202 bool find_feature_index (hb_tag_t tag, unsigned int *index) const
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04003203 { return (this+featureList).find_index (tag, index); }
3204
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303205 unsigned int get_lookup_count () const
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04003206 { return (this+lookupList).len; }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303207 const Lookup& get_lookup (unsigned int i) const
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04003208 { return (this+lookupList)[i]; }
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04003209
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303210 bool find_variations_index (const int *coords, unsigned int num_coords,
3211 unsigned int *index) const
Behdad Esfahboda8498732019-06-19 19:26:22 -07003212 {
Qunxin Liu0b39c482019-10-22 16:00:43 -07003213#ifdef HB_NO_VAR
Ebrahim Byagowi2e1bf612020-03-26 22:59:26 +04303214 *index = FeatureVariations::NOT_FOUND_INDEX;
Behdad Esfahboda8498732019-06-19 19:26:22 -07003215 return false;
3216#endif
Ebrahim Byagowi071e2e32020-03-26 12:01:53 +04303217 return (version.to_int () >= 0x00010001u ? this+featureVars : Null (FeatureVariations))
Behdad Esfahboda8498732019-06-19 19:26:22 -07003218 .find_index (coords, num_coords, index);
3219 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303220 const Feature& get_feature_variation (unsigned int feature_index,
Behdad Esfahbod3d9a6e62019-01-22 12:02:06 +01003221 unsigned int variations_index) const
Behdad Esfahbodec87ba92016-09-10 03:53:11 -07003222 {
Behdad Esfahboda8498732019-06-19 19:26:22 -07003223#ifndef HB_NO_VAR
Behdad Esfahbodec87ba92016-09-10 03:53:11 -07003224 if (FeatureVariations::NOT_FOUND_INDEX != variations_index &&
3225 version.to_int () >= 0x00010001u)
3226 {
Behdad Esfahbod4ebbeb72016-09-10 04:52:34 -07003227 const Feature *feature = (this+featureVars).find_substitute (variations_index,
3228 feature_index);
Behdad Esfahbodec87ba92016-09-10 03:53:11 -07003229 if (feature)
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03303230 return *feature;
Behdad Esfahbodec87ba92016-09-10 03:53:11 -07003231 }
Behdad Esfahboda8498732019-06-19 19:26:22 -07003232#endif
Behdad Esfahbodec87ba92016-09-10 03:53:11 -07003233 return get_feature (feature_index);
3234 }
Behdad Esfahbod59055b52016-09-10 01:24:28 -07003235
Qunxin Liu0b39c482019-10-22 16:00:43 -07003236 void feature_variation_collect_lookups (const hb_set_t *feature_indexes,
3237 hb_set_t *lookup_indexes /* OUT */) const
3238 {
3239#ifndef HB_NO_VAR
3240 if (version.to_int () >= 0x00010001u)
3241 (this+featureVars).collect_lookups (feature_indexes, lookup_indexes);
3242#endif
3243 }
3244
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07003245 template <typename TLookup>
Qunxin Liue565d1f2019-11-01 10:21:36 -07003246 bool subset (hb_subset_layout_context_t *c) const
Behdad Esfahbodbfa72a92018-09-01 18:34:50 -07003247 {
3248 TRACE_SUBSET (this);
Qunxin Liue565d1f2019-11-01 10:21:36 -07003249 auto *out = c->subset_context->serializer->embed (*this);
Behdad Esfahbodbfa72a92018-09-01 18:34:50 -07003250 if (unlikely (!out)) return_trace (false);
Behdad Esfahbod1b6d0c42018-12-13 18:10:48 -05003251
Qunxin Liue565d1f2019-11-01 10:21:36 -07003252 typedef LookupOffsetList<TLookup> TLookupList;
Behdad Esfahbod858b6272019-12-10 13:18:32 -06003253 reinterpret_cast<OffsetTo<TLookupList> &> (out->lookupList)
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04303254 .serialize_subset (c->subset_context,
Qunxin Liue565d1f2019-11-01 10:21:36 -07003255 reinterpret_cast<const OffsetTo<TLookupList> &> (lookupList),
3256 this,
Qunxin Liue565d1f2019-11-01 10:21:36 -07003257 c);
3258
3259 reinterpret_cast<OffsetTo<RecordListOfFeature> &> (out->featureList)
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04303260 .serialize_subset (c->subset_context,
Qunxin Liue565d1f2019-11-01 10:21:36 -07003261 reinterpret_cast<const OffsetTo<RecordListOfFeature> &> (featureList),
3262 this,
Qunxin Liue565d1f2019-11-01 10:21:36 -07003263 c);
3264
3265 out->scriptList.serialize_subset (c->subset_context,
3266 scriptList,
3267 this,
Qunxin Liue565d1f2019-11-01 10:21:36 -07003268 c);
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07003269
Behdad Esfahboda8498732019-06-19 19:26:22 -07003270#ifndef HB_NO_VAR
Behdad Esfahbodbfa72a92018-09-01 18:34:50 -07003271 if (version.to_int () >= 0x00010001u)
Qunxin Liue565d1f2019-11-01 10:21:36 -07003272 {
ariza188a0a42020-03-07 11:02:36 -08003273 bool ret = out->featureVars.serialize_subset (c->subset_context, featureVars, this, c);
Qunxin Liue565d1f2019-11-01 10:21:36 -07003274 if (!ret)
3275 {
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04303276 out->version.major = 1;
3277 out->version.minor = 0;
Qunxin Liue565d1f2019-11-01 10:21:36 -07003278 }
3279 }
Behdad Esfahboda8498732019-06-19 19:26:22 -07003280#endif
Behdad Esfahbod1b6d0c42018-12-13 18:10:48 -05003281
Behdad Esfahbodbfa72a92018-09-01 18:34:50 -07003282 return_trace (true);
3283 }
3284
Qunxin Liu8ffc9ad2019-10-31 15:59:02 -07003285 void closure_features (const hb_map_t *lookup_indexes, /* IN */
3286 hb_set_t *feature_indexes /* OUT */) const
3287 {
Garret Rieger414529e2020-02-28 15:15:55 -08003288 unsigned int feature_count = hb_min (get_feature_count (), (unsigned) HB_MAX_FEATURES);
Garret Rieger75622b02020-02-28 14:11:48 -08003289 for (unsigned i = 0; i < feature_count; i++)
Qunxin Liu8ffc9ad2019-10-31 15:59:02 -07003290 {
3291 if (get_feature (i).intersects_lookup_indexes (lookup_indexes))
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04303292 feature_indexes->add (i);
Qunxin Liu8ffc9ad2019-10-31 15:59:02 -07003293 }
3294#ifndef HB_NO_VAR
3295 if (version.to_int () >= 0x00010001u)
3296 (this+featureVars).closure_features (lookup_indexes, feature_indexes);
3297#endif
3298 }
3299
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303300 unsigned int get_size () const
Behdad Esfahbodbfa72a92018-09-01 18:34:50 -07003301 {
3302 return min_size +
3303 (version.to_int () >= 0x00010001u ? featureVars.static_size : 0);
3304 }
3305
Behdad Esfahbod6d618522018-09-03 16:41:28 -07003306 template <typename TLookup>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303307 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03003308 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05003309 TRACE_SANITIZE (this);
Behdad Esfahbod6d618522018-09-03 16:41:28 -07003310 typedef OffsetListOf<TLookup> TLookupList;
Behdad Esfahbod8e3cde62019-06-19 19:58:24 -07003311 if (unlikely (!(version.sanitize (c) &&
3312 likely (version.major == 1) &&
3313 scriptList.sanitize (c, this) &&
3314 featureList.sanitize (c, this) &&
Behdad Esfahbod858b6272019-12-10 13:18:32 -06003315 reinterpret_cast<const OffsetTo<TLookupList> &> (lookupList).sanitize (c, this))))
Behdad Esfahbod8e3cde62019-06-19 19:58:24 -07003316 return_trace (false);
3317
Behdad Esfahboda8498732019-06-19 19:26:22 -07003318#ifndef HB_NO_VAR
Behdad Esfahbod8e3cde62019-06-19 19:58:24 -07003319 if (unlikely (!(version.to_int () < 0x00010001u || featureVars.sanitize (c, this))))
3320 return_trace (false);
Behdad Esfahboda8498732019-06-19 19:26:22 -07003321#endif
Behdad Esfahbod8e3cde62019-06-19 19:58:24 -07003322
3323 return_trace (true);
Behdad Esfahbodcd3827e2009-08-04 02:09:34 -04003324 }
3325
Behdad Esfahbod963413f2018-08-26 00:47:55 -07003326 template <typename T>
3327 struct accelerator_t
3328 {
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303329 void init (hb_face_t *face)
Behdad Esfahbod963413f2018-08-26 00:47:55 -07003330 {
Ebrahim Byagowiba22df32020-03-10 10:42:20 +03303331 this->table = hb_sanitize_context_t ().reference_table<T> (face);
Behdad Esfahbod574d8882018-11-25 16:51:22 -05003332 if (unlikely (this->table->is_blacklisted (this->table.get_blob (), face)))
3333 {
3334 hb_blob_destroy (this->table.get_blob ());
3335 this->table = hb_blob_get_empty ();
3336 }
Behdad Esfahbod963413f2018-08-26 00:47:55 -07003337
Behdad Esfahbodb9291002018-08-26 01:15:47 -07003338 this->lookup_count = table->get_lookup_count ();
Behdad Esfahbod963413f2018-08-26 00:47:55 -07003339
3340 this->accels = (hb_ot_layout_lookup_accelerator_t *) calloc (this->lookup_count, sizeof (hb_ot_layout_lookup_accelerator_t));
3341 if (unlikely (!this->accels))
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03303342 this->lookup_count = 0;
Behdad Esfahbod963413f2018-08-26 00:47:55 -07003343
3344 for (unsigned int i = 0; i < this->lookup_count; i++)
Behdad Esfahbodb9291002018-08-26 01:15:47 -07003345 this->accels[i].init (table->get_lookup (i));
Behdad Esfahbod963413f2018-08-26 00:47:55 -07003346 }
3347
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303348 void fini ()
Behdad Esfahbod963413f2018-08-26 00:47:55 -07003349 {
Behdad Esfahbodb9291002018-08-26 01:15:47 -07003350 for (unsigned int i = 0; i < this->lookup_count; i++)
3351 this->accels[i].fini ();
3352 free (this->accels);
Behdad Esfahbodda6aa3b2018-11-11 11:40:57 -05003353 this->table.destroy ();
Behdad Esfahbod963413f2018-08-26 00:47:55 -07003354 }
3355
Behdad Esfahbod5d0078a2018-11-10 23:52:15 -05003356 hb_blob_ptr_t<T> table;
Behdad Esfahbodb9291002018-08-26 01:15:47 -07003357 unsigned int lookup_count;
3358 hb_ot_layout_lookup_accelerator_t *accels;
Behdad Esfahbod963413f2018-08-26 00:47:55 -07003359 };
3360
Behdad Esfahbod212aba62009-05-24 00:50:27 -04003361 protected:
Behdad Esfahbod9a13ed42016-02-22 11:44:45 +09003362 FixedVersion<>version; /* Version of the GSUB/GPOS table--initially set
Behdad Esfahbod76271002014-07-11 14:54:42 -04003363 * to 0x00010000u */
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04003364 OffsetTo<ScriptList>
Ebrahim Byagowice114d62019-12-31 15:53:02 +03303365 scriptList; /* ScriptList table */
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04003366 OffsetTo<FeatureList>
Ebrahim Byagowice114d62019-12-31 15:53:02 +03303367 featureList; /* FeatureList table */
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04003368 OffsetTo<LookupList>
Ebrahim Byagowice114d62019-12-31 15:53:02 +03303369 lookupList; /* LookupList table */
Behdad Esfahbod5e156fa2017-01-22 20:28:56 -08003370 LOffsetTo<FeatureVariations>
Behdad Esfahbod59055b52016-09-10 01:24:28 -07003371 featureVars; /* Offset to Feature Variations
3372 table--from beginning of table
3373 * (may be NULL). Introduced
3374 * in version 0x00010001. */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04003375 public:
Behdad Esfahbod59055b52016-09-10 01:24:28 -07003376 DEFINE_SIZE_MIN (10);
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04003377};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04003378
Behdad Esfahbod6f20f722009-05-17 20:28:01 -04003379
Behdad Esfahbod7d52e662012-11-16 18:49:54 -08003380} /* namespace OT */
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -04003381
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04003382
Behdad Esfahbodc77ae402018-08-25 22:36:36 -07003383#endif /* HB_OT_LAYOUT_GSUBGPOS_HH */