blob: 8ba555c886ca065d7abbbf4fd63da2395a997199 [file] [log] [blame]
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001/*
Behdad Esfahbod2409d5f2011-04-21 17:14:28 -04002 * Copyright © 2007,2008,2009,2010 Red Hat, Inc.
Behdad Esfahbod5b93e8d2012-04-23 22:26:13 -04003 * Copyright © 2010,2012 Google, Inc.
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04004 *
Behdad Esfahbodc755cb32010-04-22 00:11:43 -04005 * This is part of HarfBuzz, a text shaping library.
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04006 *
7 * Permission is hereby granted, without written agreement and without
8 * license or royalty fees, to use, copy, modify, and distribute this
9 * software and its documentation for any purpose, provided that the
10 * above copyright notice and the following two paragraphs appear in
11 * all copies of this software.
12 *
13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
17 * DAMAGE.
18 *
19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24 *
25 * Red Hat Author(s): Behdad Esfahbod
Behdad Esfahbod98370e82010-10-27 17:39:01 -040026 * Google Author(s): Behdad Esfahbod
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -040027 */
28
Behdad Esfahbodc77ae402018-08-25 22:36:36 -070029#ifndef HB_OT_LAYOUT_GSUBGPOS_HH
30#define HB_OT_LAYOUT_GSUBGPOS_HH
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -040031
Behdad Esfahbodc77ae402018-08-25 22:36:36 -070032#include "hb.hh"
33#include "hb-buffer.hh"
34#include "hb-map.hh"
Behdad Esfahbodc77ae402018-08-25 22:36:36 -070035#include "hb-set.hh"
Behdad Esfahbod71c9f842018-09-10 22:37:19 +020036#include "hb-ot-map.hh"
Behdad Esfahbodb9291002018-08-26 01:15:47 -070037#include "hb-ot-layout-common.hh"
38#include "hb-ot-layout-gdef-table.hh"
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -040039
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -040040
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -040041namespace OT {
42
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -040043
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -070044struct hb_intersects_context_t :
Behdad Esfahbod8d0a90a2020-06-18 16:53:54 -070045 hb_dispatch_context_t<hb_intersects_context_t, bool>
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -070046{
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -070047 template <typename T>
Behdad Esfahbodc14efb82019-05-05 09:54:58 -070048 return_t dispatch (const T &obj) { return obj.intersects (this->glyphs); }
Ebrahim Byagowie4120082018-12-17 21:31:01 +033049 static return_t default_return_value () { return false; }
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -070050 bool stop_sublookup_iteration (return_t r) const { return r; }
51
52 const hb_set_t *glyphs;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -070053
54 hb_intersects_context_t (const hb_set_t *glyphs_) :
Qunxin Liu56ca4352021-01-28 15:21:26 -080055 glyphs (glyphs_) {}
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -070056};
57
Qunxin Liub4fc5932020-12-09 10:44:18 -080058struct hb_have_non_1to1_context_t :
59 hb_dispatch_context_t<hb_have_non_1to1_context_t, bool>
60{
61 template <typename T>
62 return_t dispatch (const T &obj) { return obj.may_have_non_1to1 (); }
63 static return_t default_return_value () { return false; }
64 bool stop_sublookup_iteration (return_t r) const { return r; }
65};
66
Behdad Esfahbod77a1a2b2015-10-09 12:20:58 -040067struct hb_closure_context_t :
Behdad Esfahbod25aec022020-06-18 16:58:01 -070068 hb_dispatch_context_t<hb_closure_context_t>
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -040069{
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -080070 typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *covered_seq_indicies, unsigned seq_index, unsigned end_index);
Behdad Esfahbod44fc2372012-11-21 23:33:13 -050071 template <typename T>
Behdad Esfahbod7df3ecf2019-05-10 20:43:26 -070072 return_t dispatch (const T &obj) { obj.closure (this); return hb_empty_t (); }
73 static return_t default_return_value () { return hb_empty_t (); }
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -080074 void recurse (unsigned lookup_index, hb_set_t *covered_seq_indicies, unsigned seq_index, unsigned end_index)
Behdad Esfahbod44fc2372012-11-21 23:33:13 -050075 {
Behdad Esfahbod9b346772012-11-23 17:55:40 -050076 if (unlikely (nesting_level_left == 0 || !recurse_func))
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -070077 return;
Behdad Esfahbod44fc2372012-11-21 23:33:13 -050078
79 nesting_level_left--;
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -080080 recurse_func (this, lookup_index, covered_seq_indicies, seq_index, end_index);
Behdad Esfahbod44fc2372012-11-21 23:33:13 -050081 nesting_level_left++;
Behdad Esfahbod44fc2372012-11-21 23:33:13 -050082 }
83
Garret Riegerd6702572021-12-10 13:52:05 -080084 void reset_lookup_visit_count ()
85 { lookup_count = 0; }
86
Garret Rieger4ad686b2020-03-25 23:32:28 -070087 bool lookup_limit_exceeded ()
Qunxin Liu706014f2021-12-01 20:20:12 -080088 { return lookup_count > HB_MAX_LOOKUP_VISIT_COUNT; }
Garret Rieger4ad686b2020-03-25 23:32:28 -070089
Behdad Esfahbodba0ea562018-06-11 23:24:41 -040090 bool should_visit_lookup (unsigned int lookup_index)
Garret Rieger45186b92018-06-05 17:14:42 -070091 {
Qunxin Liu706014f2021-12-01 20:20:12 -080092 if (lookup_count++ > HB_MAX_LOOKUP_VISIT_COUNT)
Garret Rieger834a2242020-03-12 03:02:36 -070093 return false;
94
Garret Rieger45186b92018-06-05 17:14:42 -070095 if (is_lookup_done (lookup_index))
96 return false;
Garret Rieger834a2242020-03-12 03:02:36 -070097
Garret Rieger45186b92018-06-05 17:14:42 -070098 return true;
99 }
100
101 bool is_lookup_done (unsigned int lookup_index)
102 {
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -0800103 if (done_lookups_glyph_count->in_error () ||
104 done_lookups_glyph_set->in_error ())
Garret Rieger1e4fe102020-08-12 13:06:37 -0700105 return true;
106
Behdad Esfahbodc38bd402018-07-24 09:43:27 -0700107 /* Have we visited this lookup with the current set of glyphs? */
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -0800108 if (done_lookups_glyph_count->get (lookup_index) != glyphs->get_population ())
109 {
110 done_lookups_glyph_count->set (lookup_index, glyphs->get_population ());
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -0800111
Garret Riegerc6adb902021-03-29 16:08:44 -0700112 if (!done_lookups_glyph_set->get (lookup_index))
113 {
Behdad Esfahbod9ed5f042021-03-29 18:14:30 -0600114 hb_set_t* empty_set = hb_set_create ();
115 if (unlikely (!done_lookups_glyph_set->set (lookup_index, empty_set)))
116 {
117 hb_set_destroy (empty_set);
118 return true;
119 }
Garret Riegerc6adb902021-03-29 16:08:44 -0700120 }
Garret Rieger52df6b92021-03-29 16:17:27 -0700121
Garret Rieger9f77a0c2021-03-30 14:10:45 -0700122 hb_set_clear (done_lookups_glyph_set->get (lookup_index));
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -0800123 }
124
125 hb_set_t *covered_glyph_set = done_lookups_glyph_set->get (lookup_index);
Garret Rieger8b686af2021-04-06 11:33:38 -0700126 if (unlikely (covered_glyph_set->in_error ()))
Garret Rieger64122b52021-04-05 12:53:08 -0700127 return true;
Garret Riegerf3c1f4f2022-01-28 11:50:22 -0800128 if (parent_active_glyphs ().is_subset (*covered_glyph_set))
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -0800129 return true;
Garret Riegerc6adb902021-03-29 16:08:44 -0700130
Garret Riegerf3c1f4f2022-01-28 11:50:22 -0800131 covered_glyph_set->union_ (parent_active_glyphs ());
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -0800132 return false;
Garret Rieger45186b92018-06-05 17:14:42 -0700133 }
134
Garret Rieger4e2f4092022-01-31 12:20:32 -0800135 const hb_set_t& previous_parent_active_glyphs () {
136 if (active_glyphs_stack.length <= 1)
137 return *glyphs;
138
139 return active_glyphs_stack[active_glyphs_stack.length - 2];
140 }
141
Garret Riegerf3c1f4f2022-01-28 11:50:22 -0800142 const hb_set_t& parent_active_glyphs ()
Qunxin Liub4fc5932020-12-09 10:44:18 -0800143 {
Garret Riegerf3c1f4f2022-01-28 11:50:22 -0800144 if (!active_glyphs_stack)
145 return *glyphs;
Garret Riegerc6adb902021-03-29 16:08:44 -0700146
Qunxin Liub4fc5932020-12-09 10:44:18 -0800147 return active_glyphs_stack.tail ();
148 }
149
Garret Riegerf3c1f4f2022-01-28 11:50:22 -0800150 hb_set_t& push_cur_active_glyphs ()
Qunxin Liub4fc5932020-12-09 10:44:18 -0800151 {
Garret Riegerf3c1f4f2022-01-28 11:50:22 -0800152 return *active_glyphs_stack.push ();
Qunxin Liub4fc5932020-12-09 10:44:18 -0800153 }
154
155 bool pop_cur_done_glyphs ()
156 {
157 if (active_glyphs_stack.length < 1)
158 return false;
159
160 active_glyphs_stack.pop ();
161 return true;
162 }
163
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400164 hb_face_t *face;
Behdad Esfahbod6a9be5b2012-04-23 22:23:17 -0400165 hb_set_t *glyphs;
Behdad Esfahbodede1a712019-01-09 10:45:53 -0800166 hb_set_t output[1];
Garret Riegerf3c1f4f2022-01-28 11:50:22 -0800167 hb_vector_t<hb_set_t> active_glyphs_stack;
Behdad Esfahbod44fc2372012-11-21 23:33:13 -0500168 recurse_func_t recurse_func;
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400169 unsigned int nesting_level_left;
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400170
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400171 hb_closure_context_t (hb_face_t *face_,
Behdad Esfahbod6a9be5b2012-04-23 22:23:17 -0400172 hb_set_t *glyphs_,
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -0800173 hb_map_t *done_lookups_glyph_count_,
Behdad Esfahbod394f7722021-11-19 11:49:23 -0700174 hb_hashmap_t<unsigned, hb_set_t *> *done_lookups_glyph_set_,
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330175 unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400176 face (face_),
177 glyphs (glyphs_),
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200178 recurse_func (nullptr),
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400179 nesting_level_left (nesting_level_left_),
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -0800180 done_lookups_glyph_count (done_lookups_glyph_count_),
181 done_lookups_glyph_set (done_lookups_glyph_set_),
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +0430182 lookup_count (0)
Garret Riegerf3c1f4f2022-01-28 11:50:22 -0800183 {}
Behdad Esfahbod9b346772012-11-23 17:55:40 -0500184
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330185 ~hb_closure_context_t () { flush (); }
Behdad Esfahbodc38bd402018-07-24 09:43:27 -0700186
Behdad Esfahbod9b346772012-11-23 17:55:40 -0500187 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
Garret Rieger45186b92018-06-05 17:14:42 -0700188
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330189 void flush ()
Behdad Esfahbodc38bd402018-07-24 09:43:27 -0700190 {
Garret Riegerf3c1f4f2022-01-28 11:50:22 -0800191 output->del_range (face->get_num_glyphs (), HB_SET_VALUE_INVALID); /* Remove invalid glyphs. */
192 glyphs->union_ (*output);
193 output->clear ();
Qunxin Liub4fc5932020-12-09 10:44:18 -0800194 active_glyphs_stack.pop ();
Garret Riegerf3c1f4f2022-01-28 11:50:22 -0800195 active_glyphs_stack.reset ();
Behdad Esfahbodc38bd402018-07-24 09:43:27 -0700196 }
197
Garret Rieger45186b92018-06-05 17:14:42 -0700198 private:
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -0800199 hb_map_t *done_lookups_glyph_count;
Behdad Esfahbod394f7722021-11-19 11:49:23 -0700200 hb_hashmap_t<unsigned, hb_set_t *> *done_lookups_glyph_set;
Garret Rieger834a2242020-03-12 03:02:36 -0700201 unsigned int lookup_count;
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400202};
203
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -0800204
205
Qunxin Liu0b39c482019-10-22 16:00:43 -0700206struct hb_closure_lookups_context_t :
Behdad Esfahbod25aec022020-06-18 16:58:01 -0700207 hb_dispatch_context_t<hb_closure_lookups_context_t>
Qunxin Liu0b39c482019-10-22 16:00:43 -0700208{
Qunxin Liu0b39c482019-10-22 16:00:43 -0700209 typedef return_t (*recurse_func_t) (hb_closure_lookups_context_t *c, unsigned lookup_index);
210 template <typename T>
211 return_t dispatch (const T &obj) { obj.closure_lookups (this); return hb_empty_t (); }
212 static return_t default_return_value () { return hb_empty_t (); }
213 void recurse (unsigned lookup_index)
214 {
215 if (unlikely (nesting_level_left == 0 || !recurse_func))
216 return;
217
218 /* Return if new lookup was recursed to before. */
Garret Rieger77507a12021-12-10 14:10:04 -0800219 if (lookup_limit_exceeded ()
220 || visited_lookups->in_error ()
221 || visited_lookups->has (lookup_index))
222 // Don't increment lookup count here, that will be done in the call to closure_lookups()
223 // made by recurse_func.
Qunxin Liu0b39c482019-10-22 16:00:43 -0700224 return;
225
Qunxin Liu0b39c482019-10-22 16:00:43 -0700226 nesting_level_left--;
227 recurse_func (this, lookup_index);
228 nesting_level_left++;
229 }
230
231 void set_lookup_visited (unsigned lookup_index)
232 { visited_lookups->add (lookup_index); }
233
234 void set_lookup_inactive (unsigned lookup_index)
235 { inactive_lookups->add (lookup_index); }
236
Garret Rieger4ad686b2020-03-25 23:32:28 -0700237 bool lookup_limit_exceeded ()
Qunxin Liu706014f2021-12-01 20:20:12 -0800238 {
239 bool ret = lookup_count > HB_MAX_LOOKUP_VISIT_COUNT;
240 if (ret)
241 DEBUG_MSG (SUBSET, nullptr, "lookup visit count limit exceeded in lookup closure!");
242 return ret; }
Garret Rieger4ad686b2020-03-25 23:32:28 -0700243
Qunxin Liu0b39c482019-10-22 16:00:43 -0700244 bool is_lookup_visited (unsigned lookup_index)
Garret Rieger834a2242020-03-12 03:02:36 -0700245 {
Qunxin Liu706014f2021-12-01 20:20:12 -0800246 if (unlikely (lookup_count++ > HB_MAX_LOOKUP_VISIT_COUNT))
247 {
248 DEBUG_MSG (SUBSET, nullptr, "total visited lookup count %u exceeds max limit, lookup %u is dropped.",
249 lookup_count, lookup_index);
Garret Rieger834a2242020-03-12 03:02:36 -0700250 return true;
Qunxin Liu706014f2021-12-01 20:20:12 -0800251 }
Garret Rieger834a2242020-03-12 03:02:36 -0700252
Behdad Esfahbodd7e2a512021-02-11 10:55:03 -0700253 if (unlikely (visited_lookups->in_error ()))
Garret Rieger95622392020-08-12 13:01:22 -0700254 return true;
255
Garret Rieger834a2242020-03-12 03:02:36 -0700256 return visited_lookups->has (lookup_index);
257 }
Qunxin Liu0b39c482019-10-22 16:00:43 -0700258
259 hb_face_t *face;
260 const hb_set_t *glyphs;
261 recurse_func_t recurse_func;
262 unsigned int nesting_level_left;
Qunxin Liu0b39c482019-10-22 16:00:43 -0700263
264 hb_closure_lookups_context_t (hb_face_t *face_,
265 const hb_set_t *glyphs_,
266 hb_set_t *visited_lookups_,
267 hb_set_t *inactive_lookups_,
268 unsigned nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
269 face (face_),
270 glyphs (glyphs_),
271 recurse_func (nullptr),
272 nesting_level_left (nesting_level_left_),
Qunxin Liu0b39c482019-10-22 16:00:43 -0700273 visited_lookups (visited_lookups_),
Garret Rieger834a2242020-03-12 03:02:36 -0700274 inactive_lookups (inactive_lookups_),
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +0430275 lookup_count (0) {}
Qunxin Liu0b39c482019-10-22 16:00:43 -0700276
277 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
278
279 private:
280 hb_set_t *visited_lookups;
281 hb_set_t *inactive_lookups;
Garret Rieger834a2242020-03-12 03:02:36 -0700282 unsigned int lookup_count;
Qunxin Liu0b39c482019-10-22 16:00:43 -0700283};
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400284
Behdad Esfahbod77a1a2b2015-10-09 12:20:58 -0400285struct hb_would_apply_context_t :
Behdad Esfahbod8d0a90a2020-06-18 16:53:54 -0700286 hb_dispatch_context_t<hb_would_apply_context_t, bool>
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400287{
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500288 template <typename T>
Behdad Esfahbodc14efb82019-05-05 09:54:58 -0700289 return_t dispatch (const T &obj) { return obj.would_apply (this); }
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330290 static return_t default_return_value () { return false; }
Behdad Esfahbod7b912c12013-01-04 01:25:27 -0600291 bool stop_sublookup_iteration (return_t r) const { return r; }
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500292
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400293 hb_face_t *face;
Behdad Esfahbod472f2292012-08-07 22:25:24 -0400294 const hb_codepoint_t *glyphs;
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400295 unsigned int len;
Behdad Esfahbodd9b204d2012-08-23 16:22:28 -0400296 bool zero_context;
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400297
298 hb_would_apply_context_t (hb_face_t *face_,
Behdad Esfahbod472f2292012-08-07 22:25:24 -0400299 const hb_codepoint_t *glyphs_,
300 unsigned int len_,
Behdad Esfahbod2bd9fe32012-09-04 15:15:19 -0400301 bool zero_context_) :
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400302 face (face_),
Behdad Esfahbod472f2292012-08-07 22:25:24 -0400303 glyphs (glyphs_),
304 len (len_),
Behdad Esfahbod70d66962020-06-18 17:09:39 -0700305 zero_context (zero_context_) {}
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400306};
307
Behdad Esfahbod77a1a2b2015-10-09 12:20:58 -0400308struct hb_collect_glyphs_context_t :
Behdad Esfahbod25aec022020-06-18 16:58:01 -0700309 hb_dispatch_context_t<hb_collect_glyphs_context_t>
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800310{
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500311 typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index);
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500312 template <typename T>
Behdad Esfahbod7df3ecf2019-05-10 20:43:26 -0700313 return_t dispatch (const T &obj) { obj.collect_glyphs (this); return hb_empty_t (); }
314 static return_t default_return_value () { return hb_empty_t (); }
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700315 void recurse (unsigned int lookup_index)
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500316 {
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500317 if (unlikely (nesting_level_left == 0 || !recurse_func))
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700318 return;
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500319
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200320 /* Note that GPOS sets recurse_func to nullptr already, so it doesn't get
Behdad Esfahbod1bcfa062012-12-04 16:58:09 -0500321 * past the previous check. For GSUB, we only want to collect the output
Behdad Esfahbod76ea5632013-05-04 16:01:20 -0400322 * glyphs in the recursion. If output is not requested, we can go home now.
323 *
324 * Note further, that the above is not exactly correct. A recursed lookup
325 * is allowed to match input that is not matched in the context, but that's
326 * not how most fonts are built. It's possible to relax that and recurse
327 * with all sets here if it proves to be an issue.
328 */
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500329
330 if (output == hb_set_get_empty ())
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700331 return;
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500332
Behdad Esfahbodfde3e4a2014-10-29 11:23:08 -0700333 /* Return if new lookup was recursed to before. */
Behdad Esfahbod8b9d9b72017-10-22 17:48:06 -0400334 if (recursed_lookups->has (lookup_index))
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700335 return;
Behdad Esfahbodfde3e4a2014-10-29 11:23:08 -0700336
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500337 hb_set_t *old_before = before;
338 hb_set_t *old_input = input;
339 hb_set_t *old_after = after;
340 before = input = after = hb_set_get_empty ();
Behdad Esfahbod1bcfa062012-12-04 16:58:09 -0500341
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500342 nesting_level_left--;
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500343 recurse_func (this, lookup_index);
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500344 nesting_level_left++;
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500345
346 before = old_before;
347 input = old_input;
348 after = old_after;
349
Behdad Esfahbod8b9d9b72017-10-22 17:48:06 -0400350 recursed_lookups->add (lookup_index);
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500351 }
352
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800353 hb_face_t *face;
Behdad Esfahbod83035932012-12-04 17:08:41 -0500354 hb_set_t *before;
355 hb_set_t *input;
356 hb_set_t *after;
357 hb_set_t *output;
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500358 recurse_func_t recurse_func;
Behdad Esfahbod8b9d9b72017-10-22 17:48:06 -0400359 hb_set_t *recursed_lookups;
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500360 unsigned int nesting_level_left;
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800361
362 hb_collect_glyphs_context_t (hb_face_t *face_,
Ebrahim Byagowi63109432018-10-13 14:00:05 +0330363 hb_set_t *glyphs_before, /* OUT. May be NULL */
364 hb_set_t *glyphs_input, /* OUT. May be NULL */
365 hb_set_t *glyphs_after, /* OUT. May be NULL */
366 hb_set_t *glyphs_output, /* OUT. May be NULL */
Behdad Esfahbod5ba45042015-11-02 15:43:08 -0800367 unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800368 face (face_),
Behdad Esfahbod83035932012-12-04 17:08:41 -0500369 before (glyphs_before ? glyphs_before : hb_set_get_empty ()),
370 input (glyphs_input ? glyphs_input : hb_set_get_empty ()),
371 after (glyphs_after ? glyphs_after : hb_set_get_empty ()),
372 output (glyphs_output ? glyphs_output : hb_set_get_empty ()),
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200373 recurse_func (nullptr),
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700374 recursed_lookups (hb_set_create ()),
Behdad Esfahbod70d66962020-06-18 17:09:39 -0700375 nesting_level_left (nesting_level_left_) {}
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330376 ~hb_collect_glyphs_context_t () { hb_set_destroy (recursed_lookups); }
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500377
378 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800379};
380
381
382
Behdad Esfahbod8e36ccf2015-02-17 19:15:34 +0300383template <typename set_t>
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -0700384struct hb_collect_coverage_context_t :
Behdad Esfahbod8d0a90a2020-06-18 16:53:54 -0700385 hb_dispatch_context_t<hb_collect_coverage_context_t<set_t>, const Coverage &>
Behdad Esfahbod2005fa52012-11-22 14:38:10 -0500386{
Behdad Esfahboddc492d72020-06-18 17:03:05 -0700387 typedef const Coverage &return_t; // Stoopid that we have to dupe this here.
Behdad Esfahbod2005fa52012-11-22 14:38:10 -0500388 template <typename T>
Behdad Esfahbodc14efb82019-05-05 09:54:58 -0700389 return_t dispatch (const T &obj) { return obj.get_coverage (); }
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +0430390 static return_t default_return_value () { return Null (Coverage); }
Behdad Esfahbod8e36ccf2015-02-17 19:15:34 +0300391 bool stop_sublookup_iteration (return_t r) const
392 {
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -0700393 r.collect_coverage (set);
Behdad Esfahbod8e36ccf2015-02-17 19:15:34 +0300394 return false;
395 }
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500396
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -0700397 hb_collect_coverage_context_t (set_t *set_) :
Behdad Esfahbod70d66962020-06-18 17:09:39 -0700398 set (set_) {}
Behdad Esfahboda1733db2012-11-23 16:40:04 -0500399
Behdad Esfahbod8e36ccf2015-02-17 19:15:34 +0300400 set_t *set;
Behdad Esfahbod2005fa52012-11-22 14:38:10 -0500401};
402
403
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800404struct hb_ot_apply_context_t :
405 hb_dispatch_context_t<hb_ot_apply_context_t, bool, HB_DEBUG_APPLY>
Behdad Esfahbod1376fb72010-04-29 02:19:21 -0400406{
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500407 struct matcher_t
408 {
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330409 matcher_t () :
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500410 lookup_props (0),
Behdad Esfahbodcfc507c2013-02-14 10:40:12 -0500411 ignore_zwnj (false),
412 ignore_zwj (false),
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500413 mask (-1),
Behdad Esfahbode8f33972022-03-28 12:07:05 -0600414 syllable {0},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200415 match_func (nullptr),
Ebrahim Byagowif7a08cd2018-10-30 11:29:09 +0330416 match_data (nullptr) {}
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500417
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100418 typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500419
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330420 void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; }
421 void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
422 void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
423 void set_mask (hb_mask_t mask_) { mask = mask_; }
424 void set_syllable (uint8_t syllable_) { syllable = syllable_; }
425 void set_match_func (match_func_t match_func_,
Ebrahim Byagowid0e2add2020-07-18 22:14:52 +0430426 const void *match_data_)
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500427 { match_func = match_func_; match_data = match_data_; }
428
Behdad Esfahbod2b2a6e82013-02-21 15:07:03 -0500429 enum may_match_t {
430 MATCH_NO,
431 MATCH_YES,
432 MATCH_MAYBE
433 };
434
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330435 may_match_t may_match (const hb_glyph_info_t &info,
Behdad Esfahbod085793d2019-04-24 10:15:59 -0400436 const HBUINT16 *glyph_data) const
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500437 {
Behdad Esfahbod2b2a6e82013-02-21 15:07:03 -0500438 if (!(info.mask & mask) ||
439 (syllable && syllable != info.syllable ()))
440 return MATCH_NO;
441
442 if (match_func)
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330443 return match_func (info.codepoint, *glyph_data, match_data) ? MATCH_YES : MATCH_NO;
Behdad Esfahbod2b2a6e82013-02-21 15:07:03 -0500444
445 return MATCH_MAYBE;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500446 }
447
448 enum may_skip_t {
449 SKIP_NO,
450 SKIP_YES,
451 SKIP_MAYBE
452 };
453
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330454 may_skip_t may_skip (const hb_ot_apply_context_t *c,
455 const hb_glyph_info_t &info) const
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500456 {
Behdad Esfahbodb98c5db2014-07-16 13:44:01 -0400457 if (!c->check_glyph_property (&info, lookup_props))
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500458 return SKIP_YES;
459
Khaled Hosny06cfe3f2017-05-17 21:32:47 +0300460 if (unlikely (_hb_glyph_info_is_default_ignorable_and_not_hidden (&info) &&
Behdad Esfahbod0b454792013-02-14 10:46:52 -0500461 (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) &&
Behdad Esfahbod4ba796b2015-07-22 17:41:31 +0100462 (ignore_zwj || !_hb_glyph_info_is_zwj (&info))))
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500463 return SKIP_MAYBE;
464
465 return SKIP_NO;
466 }
467
468 protected:
469 unsigned int lookup_props;
470 bool ignore_zwnj;
Behdad Esfahbod0b454792013-02-14 10:46:52 -0500471 bool ignore_zwj;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500472 hb_mask_t mask;
473 uint8_t syllable;
474 match_func_t match_func;
475 const void *match_data;
476 };
477
Behdad Esfahbod69626692015-01-29 13:08:41 +0100478 struct skipping_iterator_t
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500479 {
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330480 void init (hb_ot_apply_context_t *c_, bool context_match = false)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500481 {
Behdad Esfahbod514564f2015-01-29 13:48:48 +0100482 c = c_;
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200483 match_glyph_data = nullptr;
484 matcher.set_match_func (nullptr, nullptr);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500485 matcher.set_lookup_props (c->lookup_props);
Behdad Esfahbod3583fb02018-09-23 22:33:38 -0400486 /* Ignore ZWNJ if we are matching GPOS, or matching GSUB context and asked to. */
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100487 matcher.set_ignore_zwnj (c->table_index == 1 || (context_match && c->auto_zwnj));
Behdad Esfahbod3583fb02018-09-23 22:33:38 -0400488 /* Ignore ZWJ if we are matching context, or asked to. */
489 matcher.set_ignore_zwj (context_match || c->auto_zwj);
Behdad Esfahbod514564f2015-01-29 13:48:48 +0100490 matcher.set_mask (context_match ? -1 : c->lookup_mask);
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500491 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330492 void set_lookup_props (unsigned int lookup_props)
Behdad Esfahbod514564f2015-01-29 13:48:48 +0100493 {
494 matcher.set_lookup_props (lookup_props);
495 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330496 void set_match_func (matcher_t::match_func_t match_func_,
497 const void *match_data_,
498 const HBUINT16 glyph_data[])
Behdad Esfahbodc074ebc2013-02-13 11:22:42 -0500499 {
Behdad Esfahbod4a6b1ee2015-10-21 11:20:55 -0200500 matcher.set_match_func (match_func_, match_data_);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500501 match_glyph_data = glyph_data;
Behdad Esfahbodc074ebc2013-02-13 11:22:42 -0500502 }
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500503
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330504 void reset (unsigned int start_index_,
Ebrahim Byagowi08428a12020-04-24 23:45:17 +0430505 unsigned int num_items_)
Behdad Esfahbodb051be52015-01-29 13:40:39 +0100506 {
507 idx = start_index_;
508 num_items = num_items_;
509 end = c->buffer->len;
510 matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
511 }
512
Ebrahim Byagowi64a45be2019-11-09 12:25:33 +0330513 void reject ()
514 {
515 num_items++;
516 if (match_glyph_data) match_glyph_data--;
517 }
Behdad Esfahbod69626692015-01-29 13:08:41 +0100518
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330519 matcher_t::may_skip_t
520 may_skip (const hb_glyph_info_t &info) const
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330521 { return matcher.may_skip (c, info); }
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200522
Behdad Esfahbod3122c2c2021-12-04 19:50:33 -0800523 bool next (unsigned *unsafe_to = nullptr)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500524 {
Behdad Esfahbod506ffeb2012-01-18 16:07:53 -0500525 assert (num_items > 0);
Behdad Esfahbod37d13ac2015-01-29 11:38:01 +0100526 while (idx + num_items < end)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500527 {
Behdad Esfahboda4a48fe2012-01-17 18:08:41 -0500528 idx++;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500529 const hb_glyph_info_t &info = c->buffer->info[idx];
530
Behdad Esfahbodff93ac82013-02-21 14:51:40 -0500531 matcher_t::may_skip_t skip = matcher.may_skip (c, info);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500532 if (unlikely (skip == matcher_t::SKIP_YES))
533 continue;
534
Behdad Esfahbod2b2a6e82013-02-21 15:07:03 -0500535 matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
Behdad Esfahbod722e8b82013-02-21 15:37:51 -0500536 if (match == matcher_t::MATCH_YES ||
537 (match == matcher_t::MATCH_MAYBE &&
538 skip == matcher_t::SKIP_NO))
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500539 {
540 num_items--;
Ebrahim Byagowiaca63902019-10-22 00:06:46 +0330541 if (match_glyph_data) match_glyph_data++;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500542 return true;
543 }
544
545 if (skip == matcher_t::SKIP_NO)
Behdad Esfahbod3122c2c2021-12-04 19:50:33 -0800546 {
547 if (unsafe_to)
548 *unsafe_to = idx + 1;
Behdad Esfahbod722e8b82013-02-21 15:37:51 -0500549 return false;
Behdad Esfahbod3122c2c2021-12-04 19:50:33 -0800550 }
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500551 }
Behdad Esfahbod3122c2c2021-12-04 19:50:33 -0800552 if (unsafe_to)
553 *unsafe_to = end;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500554 return false;
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500555 }
Behdad Esfahbod3122c2c2021-12-04 19:50:33 -0800556 bool prev (unsigned *unsafe_from = nullptr)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500557 {
Behdad Esfahbod506ffeb2012-01-18 16:07:53 -0500558 assert (num_items > 0);
Behdad Esfahbod18a06f82018-07-05 14:03:48 +0430559 while (idx > num_items - 1)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500560 {
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500561 idx--;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500562 const hb_glyph_info_t &info = c->buffer->out_info[idx];
563
Behdad Esfahbodff93ac82013-02-21 14:51:40 -0500564 matcher_t::may_skip_t skip = matcher.may_skip (c, info);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500565 if (unlikely (skip == matcher_t::SKIP_YES))
566 continue;
567
Behdad Esfahbod2b2a6e82013-02-21 15:07:03 -0500568 matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
Behdad Esfahbod722e8b82013-02-21 15:37:51 -0500569 if (match == matcher_t::MATCH_YES ||
570 (match == matcher_t::MATCH_MAYBE &&
571 skip == matcher_t::SKIP_NO))
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500572 {
573 num_items--;
Ebrahim Byagowiaca63902019-10-22 00:06:46 +0330574 if (match_glyph_data) match_glyph_data++;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500575 return true;
576 }
577
578 if (skip == matcher_t::SKIP_NO)
Behdad Esfahbod3122c2c2021-12-04 19:50:33 -0800579 {
580 if (unsafe_from)
581 *unsafe_from = hb_max (1u, idx) - 1u;
Behdad Esfahbod722e8b82013-02-21 15:37:51 -0500582 return false;
Behdad Esfahbod3122c2c2021-12-04 19:50:33 -0800583 }
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500584 }
Behdad Esfahbod3122c2c2021-12-04 19:50:33 -0800585 if (unsafe_from)
586 *unsafe_from = 0;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500587 return false;
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500588 }
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500589
590 unsigned int idx;
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400591 protected:
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800592 hb_ot_apply_context_t *c;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500593 matcher_t matcher;
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100594 const HBUINT16 *match_glyph_data;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500595
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500596 unsigned int num_items;
Behdad Esfahbod69626692015-01-29 13:08:41 +0100597 unsigned int end;
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500598 };
599
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100600
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330601 const char *get_name () { return "APPLY"; }
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800602 typedef return_t (*recurse_func_t) (hb_ot_apply_context_t *c, unsigned int lookup_index);
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100603 template <typename T>
Behdad Esfahbodc14efb82019-05-05 09:54:58 -0700604 return_t dispatch (const T &obj) { return obj.apply (this); }
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330605 static return_t default_return_value () { return false; }
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100606 bool stop_sublookup_iteration (return_t r) const { return r; }
Behdad Esfahbod12757b62018-01-26 18:14:05 -0800607 return_t recurse (unsigned int sub_lookup_index)
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100608 {
Behdad Esfahbodbaf77792017-11-14 21:53:48 -0800609 if (unlikely (nesting_level_left == 0 || !recurse_func || buffer->max_ops-- <= 0))
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100610 return default_return_value ();
611
612 nesting_level_left--;
Behdad Esfahbod12757b62018-01-26 18:14:05 -0800613 bool ret = recurse_func (this, sub_lookup_index);
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100614 nesting_level_left++;
615 return ret;
616 }
617
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100618 skipping_iterator_t iter_input, iter_context;
619
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100620 hb_font_t *font;
621 hb_face_t *face;
622 hb_buffer_t *buffer;
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100623 recurse_func_t recurse_func;
624 const GDEF &gdef;
625 const VariationStore &var_store;
626
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100627 hb_direction_t direction;
628 hb_mask_t lookup_mask;
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100629 unsigned int table_index; /* GSUB/GPOS */
Behdad Esfahbod2c8b3b22015-08-18 14:36:43 +0100630 unsigned int lookup_index;
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100631 unsigned int lookup_props;
632 unsigned int nesting_level_left;
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100633
Behdad Esfahbod80de4bc2018-09-10 16:24:52 +0200634 bool has_glyph_classes;
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100635 bool auto_zwnj;
636 bool auto_zwj;
David Corbettc2a75e02018-01-25 14:22:03 -0500637 bool random;
Behdad Esfahbod80de4bc2018-09-10 16:24:52 +0200638
Behdad Esfahbodcfdea882018-09-11 10:57:48 +0200639 uint32_t random_state;
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100640
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100641
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800642 hb_ot_apply_context_t (unsigned int table_index_,
Ebrahim Byagowid0e2add2020-07-18 22:14:52 +0430643 hb_font_t *font_,
644 hb_buffer_t *buffer_) :
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100645 iter_input (), iter_context (),
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100646 font (font_), face (font->face), buffer (buffer_),
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200647 recurse_func (nullptr),
Behdad Esfahbod7dcf8e12019-06-26 13:44:10 -0700648 gdef (
649#ifndef HB_NO_OT_LAYOUT
650 *face->table.GDEF->table
651#else
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +0430652 Null (GDEF)
Behdad Esfahbod7dcf8e12019-06-26 13:44:10 -0700653#endif
654 ),
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100655 var_store (gdef.get_var_store ()),
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100656 direction (buffer_->props.direction),
657 lookup_mask (1),
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100658 table_index (table_index_),
Behdad Esfahbod2c8b3b22015-08-18 14:36:43 +0100659 lookup_index ((unsigned int) -1),
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100660 lookup_props (0),
661 nesting_level_left (HB_MAX_NESTING_LEVEL),
Behdad Esfahbod80de4bc2018-09-10 16:24:52 +0200662 has_glyph_classes (gdef.has_glyph_classes ()),
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100663 auto_zwnj (true),
664 auto_zwj (true),
David Corbettc2a75e02018-01-25 14:22:03 -0500665 random (false),
Behdad Esfahbodd748dc72018-09-24 18:30:50 -0400666 random_state (1) { init_iters (); }
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100667
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330668 void init_iters ()
Behdad Esfahbod365576d2015-01-29 13:59:42 +0100669 {
Behdad Esfahbod365576d2015-01-29 13:59:42 +0100670 iter_input.init (this, false);
671 iter_context.init (this, true);
672 }
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100673
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330674 void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; init_iters (); }
675 void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; init_iters (); }
676 void set_auto_zwnj (bool auto_zwnj_) { auto_zwnj = auto_zwnj_; init_iters (); }
677 void set_random (bool random_) { random = random_; }
678 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
679 void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; }
680 void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; init_iters (); }
Behdad Esfahbod9516cbd2018-09-23 22:00:34 -0400681
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330682 uint32_t random_number ()
Behdad Esfahbod08260c72018-09-11 10:51:19 +0200683 {
Behdad Esfahbodcfdea882018-09-11 10:57:48 +0200684 /* http://www.cplusplus.com/reference/random/minstd_rand/ */
685 random_state = random_state * 48271 % 2147483647;
686 return random_state;
Behdad Esfahbod08260c72018-09-11 10:51:19 +0200687 }
688
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330689 bool match_properties_mark (hb_codepoint_t glyph,
690 unsigned int glyph_props,
691 unsigned int match_props) const
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400692 {
693 /* If using mark filtering sets, the high short of
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700694 * match_props has the set index.
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400695 */
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700696 if (match_props & LookupFlag::UseMarkFilteringSet)
697 return gdef.mark_set_covers (match_props >> 16, glyph);
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400698
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700699 /* The second byte of match_props has the meaning
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400700 * "ignore marks of attachment type different than
701 * the attachment type specified."
702 */
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700703 if (match_props & LookupFlag::MarkAttachmentType)
704 return (match_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400705
706 return true;
707 }
708
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330709 bool check_glyph_property (const hb_glyph_info_t *info,
710 unsigned int match_props) const
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400711 {
Behdad Esfahbodb98c5db2014-07-16 13:44:01 -0400712 hb_codepoint_t glyph = info->codepoint;
713 unsigned int glyph_props = _hb_glyph_info_get_glyph_props (info);
714
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400715 /* Not covered, if, for example, glyph class is ligature and
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700716 * match_props includes LookupFlags::IgnoreLigatures
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400717 */
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700718 if (glyph_props & match_props & LookupFlag::IgnoreFlags)
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400719 return false;
720
Behdad Esfahbod5a08ecf2012-11-16 13:34:29 -0800721 if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK))
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700722 return match_properties_mark (glyph, glyph_props, match_props);
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400723
724 return true;
725 }
726
Behdad Esfahbodfa12f1a2022-01-12 15:08:34 -0700727 void _set_glyph_class (hb_codepoint_t glyph_index,
Ebrahim Byagowi9748ae72020-08-11 17:52:48 +0430728 unsigned int class_guess = 0,
729 bool ligature = false,
730 bool component = false) const
Behdad Esfahbod60da7632012-07-16 16:13:32 -0400731 {
Behdad Esfahbod9408e0d2022-01-12 15:07:34 -0700732 unsigned int props = _hb_glyph_info_get_glyph_props (&buffer->cur());
733 props |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED;
Behdad Esfahbod09675a82013-10-18 01:05:58 +0200734 if (ligature)
Behdad Esfahbod832a6f92014-06-04 16:57:42 -0400735 {
Behdad Esfahbod9408e0d2022-01-12 15:07:34 -0700736 props |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED;
Behdad Esfahbod832a6f92014-06-04 16:57:42 -0400737 /* In the only place that the MULTIPLIED bit is used, Uniscribe
738 * seems to only care about the "last" transformation between
Bruce Mitchener257d0e52018-10-19 22:49:21 +0700739 * Ligature and Multiple substitutions. Ie. if you ligate, expand,
Behdad Esfahbod832a6f92014-06-04 16:57:42 -0400740 * and ligate again, it forgives the multiplication and acts as
741 * if only ligation happened. As such, clear MULTIPLIED bit.
742 */
Behdad Esfahbod9408e0d2022-01-12 15:07:34 -0700743 props &= ~HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
Behdad Esfahbod832a6f92014-06-04 16:57:42 -0400744 }
745 if (component)
Behdad Esfahbod9408e0d2022-01-12 15:07:34 -0700746 props |= HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
Behdad Esfahbod2fca1422012-07-30 18:46:41 -0400747 if (likely (has_glyph_classes))
Behdad Esfahbod96c969c2022-01-12 15:06:40 -0700748 {
Behdad Esfahbod9408e0d2022-01-12 15:07:34 -0700749 props &= HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE;
750 _hb_glyph_info_set_glyph_props (&buffer->cur(), props | gdef.get_glyph_props (glyph_index));
Behdad Esfahbod96c969c2022-01-12 15:06:40 -0700751 }
Behdad Esfahbod05bd1b62012-07-30 19:30:01 -0400752 else if (class_guess)
Behdad Esfahbod96c969c2022-01-12 15:06:40 -0700753 {
Behdad Esfahbod9408e0d2022-01-12 15:07:34 -0700754 props &= HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE;
755 _hb_glyph_info_set_glyph_props (&buffer->cur(), props | class_guess);
Behdad Esfahbod96c969c2022-01-12 15:06:40 -0700756 }
757 else
Behdad Esfahbod9408e0d2022-01-12 15:07:34 -0700758 _hb_glyph_info_set_glyph_props (&buffer->cur(), props);
Behdad Esfahbod60da7632012-07-16 16:13:32 -0400759 }
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500760
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330761 void replace_glyph (hb_codepoint_t glyph_index) const
Behdad Esfahbod3ec77d62012-06-08 21:44:06 -0400762 {
Behdad Esfahbodfa12f1a2022-01-12 15:08:34 -0700763 _set_glyph_class (glyph_index);
Behdad Esfahbod3f1998a2021-03-15 13:33:44 -0600764 (void) buffer->replace_glyph (glyph_index);
Behdad Esfahbod98370e82010-10-27 17:39:01 -0400765 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330766 void replace_glyph_inplace (hb_codepoint_t glyph_index) const
Behdad Esfahbod7fbbf862012-07-30 18:36:42 -0400767 {
Behdad Esfahbodfa12f1a2022-01-12 15:08:34 -0700768 _set_glyph_class (glyph_index);
Behdad Esfahbod7fbbf862012-07-30 18:36:42 -0400769 buffer->cur().codepoint = glyph_index;
770 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330771 void replace_glyph_with_ligature (hb_codepoint_t glyph_index,
Behdad Esfahbodf4cd99f2020-04-22 14:45:57 -0700772 unsigned int class_guess) const
Behdad Esfahboda0161742013-10-18 00:06:30 +0200773 {
Behdad Esfahbodfa12f1a2022-01-12 15:08:34 -0700774 _set_glyph_class (glyph_index, class_guess, true);
Behdad Esfahbod3f1998a2021-03-15 13:33:44 -0600775 (void) buffer->replace_glyph (glyph_index);
Behdad Esfahboda0161742013-10-18 00:06:30 +0200776 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330777 void output_glyph_for_component (hb_codepoint_t glyph_index,
Behdad Esfahbodf4cd99f2020-04-22 14:45:57 -0700778 unsigned int class_guess) const
Behdad Esfahboda0161742013-10-18 00:06:30 +0200779 {
Behdad Esfahbodfa12f1a2022-01-12 15:08:34 -0700780 _set_glyph_class (glyph_index, class_guess, false, true);
Behdad Esfahbod34a12042021-03-15 14:39:06 -0600781 (void) buffer->output_glyph (glyph_index);
Behdad Esfahboda0161742013-10-18 00:06:30 +0200782 }
Behdad Esfahbod1376fb72010-04-29 02:19:21 -0400783};
784
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -0400785
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400786struct hb_get_subtables_context_t :
Behdad Esfahbod25aec022020-06-18 16:58:01 -0700787 hb_dispatch_context_t<hb_get_subtables_context_t>
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400788{
789 template <typename Type>
Behdad Esfahboda061e472019-12-10 13:31:50 -0600790 static inline bool apply_to (const void *obj, OT::hb_ot_apply_context_t *c)
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400791 {
792 const Type *typed_obj = (const Type *) obj;
793 return typed_obj->apply (c);
794 }
795
796 typedef bool (*hb_apply_func_t) (const void *obj, OT::hb_ot_apply_context_t *c);
797
798 struct hb_applicable_t
799 {
800 template <typename T>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330801 void init (const T &obj_, hb_apply_func_t apply_func_)
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400802 {
803 obj = &obj_;
804 apply_func = apply_func_;
805 digest.init ();
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -0700806 obj_.get_coverage ().collect_coverage (&digest);
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400807 }
808
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330809 bool apply (OT::hb_ot_apply_context_t *c) const
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400810 {
811 return digest.may_have (c->buffer->cur().codepoint) && apply_func (obj, c);
812 }
813
814 private:
815 const void *obj;
816 hb_apply_func_t apply_func;
817 hb_set_digest_t digest;
818 };
819
Behdad Esfahbodfa333e32018-12-27 17:56:22 -0500820 typedef hb_vector_t<hb_applicable_t> array_t;
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400821
822 /* Dispatch interface. */
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400823 template <typename T>
Behdad Esfahbodc14efb82019-05-05 09:54:58 -0700824 return_t dispatch (const T &obj)
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400825 {
826 hb_applicable_t *entry = array.push();
827 entry->init (obj, apply_to<T>);
Behdad Esfahbod7df3ecf2019-05-10 20:43:26 -0700828 return hb_empty_t ();
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400829 }
Behdad Esfahbod7df3ecf2019-05-10 20:43:26 -0700830 static return_t default_return_value () { return hb_empty_t (); }
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400831
832 hb_get_subtables_context_t (array_t &array_) :
Behdad Esfahbod15354402020-06-19 08:30:59 -0700833 array (array_) {}
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400834
835 array_t &array;
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400836};
837
838
839
Behdad Esfahbod94a23aa2010-05-05 01:13:09 -0400840
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700841typedef bool (*intersects_func_t) (const hb_set_t *glyphs, const HBUINT16 &value, const void *data);
Qunxin Liub8a58a02021-01-10 15:50:04 -0800842typedef void (*intersected_glyphs_func_t) (const hb_set_t *glyphs, const void *data, unsigned value, hb_set_t *intersected_glyphs);
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100843typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const HBUINT16 &value, const void *data);
844typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -0400845
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400846struct ContextClosureFuncs
847{
848 intersects_func_t intersects;
Qunxin Liub8a58a02021-01-10 15:50:04 -0800849 intersected_glyphs_func_t intersected_glyphs;
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400850};
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500851struct ContextCollectGlyphsFuncs
852{
853 collect_glyphs_func_t collect;
854};
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400855struct ContextApplyFuncs
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400856{
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -0400857 match_func_t match;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -0400858};
859
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500860
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700861static inline bool intersects_glyph (const hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400862{
863 return glyphs->has (value);
864}
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700865static inline bool intersects_class (const hb_set_t *glyphs, const HBUINT16 &value, const void *data)
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400866{
867 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
868 return class_def.intersects_class (glyphs, value);
869}
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700870static inline bool intersects_coverage (const hb_set_t *glyphs, const HBUINT16 &value, const void *data)
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400871{
Behdad Esfahbod9b4b5842021-03-31 13:27:21 -0600872 const Offset16To<Coverage> &coverage = (const Offset16To<Coverage>&)value;
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400873 return (data+coverage).intersects (glyphs);
874}
875
Qunxin Liub8a58a02021-01-10 15:50:04 -0800876
877static inline void intersected_glyph (const hb_set_t *glyphs HB_UNUSED, const void *data, unsigned value, hb_set_t *intersected_glyphs)
878{
879 unsigned g = reinterpret_cast<const HBUINT16 *>(data)[value];
880 intersected_glyphs->add (g);
881}
882static inline void intersected_class_glyphs (const hb_set_t *glyphs, const void *data, unsigned value, hb_set_t *intersected_glyphs)
883{
884 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
885 class_def.intersected_class_glyphs (glyphs, value, intersected_glyphs);
886}
887static inline void intersected_coverage_glyphs (const hb_set_t *glyphs, const void *data, unsigned value, hb_set_t *intersected_glyphs)
888{
Behdad Esfahbodad28f972021-03-31 12:49:14 -0600889 Offset16To<Coverage> coverage;
Qunxin Liub8a58a02021-01-10 15:50:04 -0800890 coverage = value;
891 (data+coverage).intersected_coverage_glyphs (glyphs, intersected_glyphs);
892}
893
894
Qunxin Liu44d88cf2020-05-08 15:33:34 -0700895static inline bool array_is_subset_of (const hb_set_t *glyphs,
896 unsigned int count,
897 const HBUINT16 values[],
898 intersects_func_t intersects_func,
899 const void *intersects_data)
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400900{
Garret Rieger95ab1102019-10-21 13:15:46 -0700901 for (const HBUINT16 &_ : + hb_iter (values, count))
Qunxin Liu44d88cf2020-05-08 15:33:34 -0700902 if (!intersects_func (glyphs, _, intersects_data)) return false;
903 return true;
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400904}
905
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -0400906
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100907static inline void collect_glyph (hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500908{
909 glyphs->add (value);
910}
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100911static inline void collect_class (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500912{
913 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
Behdad Esfahbod89ad3c62020-04-23 10:57:30 -0700914 class_def.collect_class (glyphs, value);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500915}
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100916static inline void collect_coverage (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500917{
Behdad Esfahbod9b4b5842021-03-31 13:27:21 -0600918 const Offset16To<Coverage> &coverage = (const Offset16To<Coverage>&)value;
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -0700919 (data+coverage).collect_coverage (glyphs);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500920}
Behdad Esfahbod0beb66e2012-12-05 18:46:04 -0500921static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -0500922 hb_set_t *glyphs,
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500923 unsigned int count,
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100924 const HBUINT16 values[],
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500925 collect_glyphs_func_t collect_func,
926 const void *collect_data)
927{
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -0700928 return
929 + hb_iter (values, count)
930 | hb_apply ([&] (const HBUINT16 &_) { collect_func (glyphs, _, collect_data); })
931 ;
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500932}
933
934
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100935static inline bool match_glyph (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data HB_UNUSED)
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400936{
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -0400937 return glyph_id == value;
938}
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100939static inline bool match_class (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data)
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400940{
Behdad Esfahbod2b5a59c2009-08-04 11:38:50 -0400941 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -0400942 return class_def.get_class (glyph_id) == value;
943}
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100944static inline bool match_coverage (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data)
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400945{
Behdad Esfahbod9b4b5842021-03-31 13:27:21 -0600946 const Offset16To<Coverage> &coverage = (const Offset16To<Coverage>&)value;
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400947 return (data+coverage).get_coverage (glyph_id) != NOT_COVERED;
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -0400948}
949
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400950static inline bool would_match_input (hb_would_apply_context_t *c,
951 unsigned int count, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100952 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400953 match_func_t match_func,
954 const void *match_data)
955{
956 if (count != c->len)
957 return false;
958
959 for (unsigned int i = 1; i < count; i++)
Behdad Esfahbod472f2292012-08-07 22:25:24 -0400960 if (likely (!match_func (c->glyphs[i], input[i - 1], match_data)))
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400961 return false;
962
963 return true;
964}
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800965static inline bool match_input (hb_ot_apply_context_t *c,
Behdad Esfahbode072c242009-05-18 03:47:31 -0400966 unsigned int count, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100967 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -0400968 match_func_t match_func,
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -0400969 const void *match_data,
Behdad Esfahbod78481b32021-11-21 16:50:34 -0700970 unsigned int *end_position,
Behdad Esfahbod5ba45042015-11-02 15:43:08 -0800971 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200972 unsigned int *p_total_component_count = nullptr)
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -0400973{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200974 TRACE_APPLY (nullptr);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400975
Behdad Esfahbod5ba45042015-11-02 15:43:08 -0800976 if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return_trace (false);
Behdad Esfahbod6b65a762013-10-14 18:51:39 +0200977
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200978 hb_buffer_t *buffer = c->buffer;
979
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800980 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
Behdad Esfahbodb051be52015-01-29 13:40:39 +0100981 skippy_iter.reset (buffer->idx, count - 1);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500982 skippy_iter.set_match_func (match_func, match_data, input);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400983
Behdad Esfahbod191fa882012-08-28 22:58:55 -0400984 /*
985 * This is perhaps the trickiest part of OpenType... Remarks:
986 *
987 * - If all components of the ligature were marks, we call this a mark ligature.
988 *
989 * - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize
990 * it as a ligature glyph.
991 *
992 * - Ligatures cannot be formed across glyphs attached to different components
993 * of previous ligatures. Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and
994 * LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother.
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200995 * However, it would be wrong to ligate that SHADDA,FATHA sequence.
996 * There are a couple of exceptions to this:
997 *
998 * o If a ligature tries ligating with marks that belong to it itself, go ahead,
999 * assuming that the font designer knows what they are doing (otherwise it can
1000 * break Indic stuff when a matra wants to ligate with a conjunct,
1001 *
1002 * o If two marks want to ligate and they belong to different components of the
1003 * same ligature glyph, and said ligature glyph is to be ignored according to
1004 * mark-filtering rules, then allow.
ebraminio7c6937e2017-11-20 14:49:22 -05001005 * https://github.com/harfbuzz/harfbuzz/issues/545
Behdad Esfahbod191fa882012-08-28 22:58:55 -04001006 */
1007
Behdad Esfahbod93814ca2012-08-28 22:24:51 -04001008 unsigned int total_component_count = 0;
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +02001009 total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur());
Behdad Esfahbod93814ca2012-08-28 22:24:51 -04001010
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +02001011 unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
1012 unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001013
Behdad Esfahbod621c49c2017-10-04 15:06:48 +02001014 enum {
1015 LIGBASE_NOT_CHECKED,
1016 LIGBASE_MAY_NOT_SKIP,
1017 LIGBASE_MAY_SKIP
1018 } ligbase = LIGBASE_NOT_CHECKED;
1019
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +02001020 match_positions[0] = buffer->idx;
Behdad Esfahbod370f03e2012-01-16 17:03:55 -05001021 for (unsigned int i = 1; i < count; i++)
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001022 {
Behdad Esfahbod3122c2c2021-12-04 19:50:33 -08001023 unsigned unsafe_to;
1024 if (!skippy_iter.next (&unsafe_to))
1025 {
Behdad Esfahbod78481b32021-11-21 16:50:34 -07001026 *end_position = unsafe_to;
Behdad Esfahbod3122c2c2021-12-04 19:50:33 -08001027 return_trace (false);
1028 }
Behdad Esfahbod6cc136f2013-10-17 13:55:48 +02001029
1030 match_positions[i] = skippy_iter.idx;
Behdad Esfahbod93814ca2012-08-28 22:24:51 -04001031
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +02001032 unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]);
1033 unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -04001034
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +02001035 if (first_lig_id && first_lig_comp)
1036 {
Behdad Esfahbod93814ca2012-08-28 22:24:51 -04001037 /* If first component was attached to a previous ligature component,
1038 * all subsequent components should be attached to the same ligature
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +02001039 * component, otherwise we shouldn't ligate them... */
Behdad Esfahbod93814ca2012-08-28 22:24:51 -04001040 if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +02001041 {
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03301042 /* ...unless, we are attached to a base ligature and that base
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +02001043 * ligature is ignorable. */
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03301044 if (ligbase == LIGBASE_NOT_CHECKED)
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +02001045 {
Behdad Esfahbod621c49c2017-10-04 15:06:48 +02001046 bool found = false;
Behdad Esfahbod4d677432019-05-10 16:35:31 -07001047 const auto *out = buffer->out_info;
Behdad Esfahbod621c49c2017-10-04 15:06:48 +02001048 unsigned int j = buffer->out_len;
1049 while (j && _hb_glyph_info_get_lig_id (&out[j - 1]) == first_lig_id)
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +02001050 {
Behdad Esfahbod621c49c2017-10-04 15:06:48 +02001051 if (_hb_glyph_info_get_lig_comp (&out[j - 1]) == 0)
1052 {
1053 j--;
1054 found = true;
1055 break;
1056 }
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +02001057 j--;
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +02001058 }
Behdad Esfahbod621c49c2017-10-04 15:06:48 +02001059
Behdad Esfahbod12757b62018-01-26 18:14:05 -08001060 if (found && skippy_iter.may_skip (out[j]) == hb_ot_apply_context_t::matcher_t::SKIP_YES)
Behdad Esfahbod621c49c2017-10-04 15:06:48 +02001061 ligbase = LIGBASE_MAY_SKIP;
1062 else
1063 ligbase = LIGBASE_MAY_NOT_SKIP;
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +02001064 }
1065
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03301066 if (ligbase == LIGBASE_MAY_NOT_SKIP)
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +02001067 return_trace (false);
1068 }
1069 }
1070 else
Behdad Esfahbod621c49c2017-10-04 15:06:48 +02001071 {
Behdad Esfahbod93814ca2012-08-28 22:24:51 -04001072 /* If first component was NOT attached to a previous ligature component,
1073 * all subsequent components should also NOT be attached to any ligature
1074 * component, unless they are attached to the first component itself! */
1075 if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id))
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001076 return_trace (false);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -04001077 }
1078
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +02001079 total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001080 }
1081
Behdad Esfahbod78481b32021-11-21 16:50:34 -07001082 *end_position = skippy_iter.idx + 1;
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001083
Behdad Esfahbod191fa882012-08-28 22:58:55 -04001084 if (p_total_component_count)
1085 *p_total_component_count = total_component_count;
1086
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001087 return_trace (true);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001088}
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001089static inline bool ligate_input (hb_ot_apply_context_t *c,
Behdad Esfahbode714fe62013-10-17 13:49:51 +02001090 unsigned int count, /* Including the first glyph */
Bruce Mitchener5a24ea12018-10-20 08:09:52 +07001091 const unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
Behdad Esfahbod78481b32021-11-21 16:50:34 -07001092 unsigned int match_end,
Behdad Esfahboda177d022012-08-28 23:18:22 -04001093 hb_codepoint_t lig_glyph,
Behdad Esfahboda177d022012-08-28 23:18:22 -04001094 unsigned int total_component_count)
1095{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001096 TRACE_APPLY (nullptr);
Behdad Esfahbode714fe62013-10-17 13:49:51 +02001097
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +02001098 hb_buffer_t *buffer = c->buffer;
1099
Behdad Esfahbod78481b32021-11-21 16:50:34 -07001100 buffer->merge_clusters (buffer->idx, match_end);
Behdad Esfahbod607feb72013-02-14 07:43:13 -05001101
Behdad Esfahbod9efddb92018-10-02 16:05:26 +02001102 /* - If a base and one or more marks ligate, consider that as a base, NOT
1103 * ligature, such that all following marks can still attach to it.
1104 * https://github.com/harfbuzz/harfbuzz/issues/1109
1105 *
1106 * - If all components of the ligature were marks, we call this a mark ligature.
Behdad Esfahbod3cca9782018-10-02 15:02:16 +02001107 * If it *is* a mark ligature, we don't allocate a new ligature id, and leave
Behdad Esfahboda177d022012-08-28 23:18:22 -04001108 * the ligature to keep its old ligature id. This will allow it to attach to
1109 * a base ligature in GPOS. Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH,
Behdad Esfahbod3cca9782018-10-02 15:02:16 +02001110 * and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA with a
Behdad Esfahboda177d022012-08-28 23:18:22 -04001111 * ligature id and component value of 2. Then if SHADDA,FATHA form a ligature
1112 * later, we don't want them to lose their ligature id/component, otherwise
1113 * GPOS will fail to correctly position the mark ligature on top of the
1114 * LAM,LAM,HEH ligature. See:
1115 * https://bugzilla.gnome.org/show_bug.cgi?id=676343
1116 *
1117 * - If a ligature is formed of components that some of which are also ligatures
1118 * themselves, and those ligature components had marks attached to *their*
1119 * components, we have to attach the marks to the new ligature component
1120 * positions! Now *that*'s tricky! And these marks may be following the
1121 * last component of the whole sequence, so we should loop forward looking
1122 * for them and update them.
1123 *
1124 * Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a
1125 * 'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature
1126 * id and component == 1. Now, during 'liga', the LAM and the LAM-HEH ligature
1127 * form a LAM-LAM-HEH ligature. We need to reassign the SHADDA and FATHA to
1128 * the new ligature with a component value of 2.
1129 *
1130 * This in fact happened to a font... See:
1131 * https://bugzilla.gnome.org/show_bug.cgi?id=437633
1132 */
1133
Behdad Esfahbod9efddb92018-10-02 16:05:26 +02001134 bool is_base_ligature = _hb_glyph_info_is_base_glyph (&buffer->info[match_positions[0]]);
1135 bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->info[match_positions[0]]);
1136 for (unsigned int i = 1; i < count; i++)
Behdad Esfahbod3cca9782018-10-02 15:02:16 +02001137 if (!_hb_glyph_info_is_mark (&buffer->info[match_positions[i]]))
1138 {
Behdad Esfahbod9efddb92018-10-02 16:05:26 +02001139 is_base_ligature = false;
Behdad Esfahbod3cca9782018-10-02 15:02:16 +02001140 is_mark_ligature = false;
1141 break;
1142 }
Behdad Esfahbod9efddb92018-10-02 16:05:26 +02001143 bool is_ligature = !is_base_ligature && !is_mark_ligature;
Behdad Esfahbod3cca9782018-10-02 15:02:16 +02001144
Behdad Esfahbod9efddb92018-10-02 16:05:26 +02001145 unsigned int klass = is_ligature ? HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE : 0;
1146 unsigned int lig_id = is_ligature ? _hb_allocate_lig_id (buffer) : 0;
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +02001147 unsigned int last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
1148 unsigned int last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
Behdad Esfahboda177d022012-08-28 23:18:22 -04001149 unsigned int components_so_far = last_num_components;
1150
Behdad Esfahbod9efddb92018-10-02 16:05:26 +02001151 if (is_ligature)
Behdad Esfahbod7e08f122013-05-27 14:48:34 -04001152 {
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +02001153 _hb_glyph_info_set_lig_props_for_ligature (&buffer->cur(), lig_id, total_component_count);
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +02001154 if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
Behdad Esfahbod3d436d32013-10-28 21:00:37 +01001155 {
Behdad Esfahbod82596692015-11-02 17:44:05 -08001156 _hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER);
Behdad Esfahbod3d436d32013-10-28 21:00:37 +01001157 }
Behdad Esfahbod7e08f122013-05-27 14:48:34 -04001158 }
Behdad Esfahboda0161742013-10-18 00:06:30 +02001159 c->replace_glyph_with_ligature (lig_glyph, klass);
Behdad Esfahboda177d022012-08-28 23:18:22 -04001160
1161 for (unsigned int i = 1; i < count; i++)
1162 {
Behdad Esfahbod7185b272018-05-31 20:03:00 -07001163 while (buffer->idx < match_positions[i] && buffer->successful)
Behdad Esfahboda177d022012-08-28 23:18:22 -04001164 {
Behdad Esfahbod9efddb92018-10-02 16:05:26 +02001165 if (is_ligature)
1166 {
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03301167 unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
Behdad Esfahbod2f02fc72015-12-17 15:21:14 +00001168 if (this_comp == 0)
Behdad Esfahbod100fbea2015-12-17 15:23:09 +00001169 this_comp = last_num_components;
Behdad Esfahboda177d022012-08-28 23:18:22 -04001170 unsigned int new_lig_comp = components_so_far - last_num_components +
Behdad Esfahbod41248cc2019-05-07 20:54:31 -07001171 hb_min (this_comp, last_num_components);
Behdad Esfahbod2f02fc72015-12-17 15:21:14 +00001172 _hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
Behdad Esfahboda177d022012-08-28 23:18:22 -04001173 }
Behdad Esfahbod8450f432021-03-15 15:18:06 -06001174 (void) buffer->next_glyph ();
Behdad Esfahboda177d022012-08-28 23:18:22 -04001175 }
1176
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +02001177 last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
1178 last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
Behdad Esfahboda177d022012-08-28 23:18:22 -04001179 components_so_far += last_num_components;
1180
1181 /* Skip the base glyph */
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +02001182 buffer->idx++;
Behdad Esfahboda177d022012-08-28 23:18:22 -04001183 }
1184
Ebrahim Byagowicc977b62020-03-26 11:18:02 +04301185 if (!is_mark_ligature && last_lig_id)
1186 {
Behdad Esfahboda177d022012-08-28 23:18:22 -04001187 /* Re-adjust components for any marks following. */
Ebrahim Byagowicc977b62020-03-26 11:18:02 +04301188 for (unsigned i = buffer->idx; i < buffer->len; ++i)
1189 {
1190 if (last_lig_id != _hb_glyph_info_get_lig_id (&buffer->info[i])) break;
1191
1192 unsigned this_comp = _hb_glyph_info_get_lig_comp (&buffer->info[i]);
1193 if (!this_comp) break;
1194
1195 unsigned new_lig_comp = components_so_far - last_num_components +
1196 hb_min (this_comp, last_num_components);
1197 _hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
Behdad Esfahboda177d022012-08-28 23:18:22 -04001198 }
1199 }
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001200 return_trace (true);
Behdad Esfahboda177d022012-08-28 23:18:22 -04001201}
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001202
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001203static inline bool match_backtrack (hb_ot_apply_context_t *c,
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001204 unsigned int count,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001205 const HBUINT16 backtrack[],
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001206 match_func_t match_func,
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001207 const void *match_data,
1208 unsigned int *match_start)
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001209{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001210 TRACE_APPLY (nullptr);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -04001211
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001212 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
Behdad Esfahbodb051be52015-01-29 13:40:39 +01001213 skippy_iter.reset (c->buffer->backtrack_len (), count);
Behdad Esfahbod607feb72013-02-14 07:43:13 -05001214 skippy_iter.set_match_func (match_func, match_data, backtrack);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001215
Behdad Esfahbod4d3aeb82012-01-16 16:43:26 -05001216 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod3122c2c2021-12-04 19:50:33 -08001217 {
1218 unsigned unsafe_from;
1219 if (!skippy_iter.prev (&unsafe_from))
1220 {
Behdad Esfahbod78481b32021-11-21 16:50:34 -07001221 *match_start = unsafe_from;
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001222 return_trace (false);
Behdad Esfahbod3122c2c2021-12-04 19:50:33 -08001223 }
1224 }
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001225
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001226 *match_start = skippy_iter.idx;
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001227 return_trace (true);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001228}
1229
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001230static inline bool match_lookahead (hb_ot_apply_context_t *c,
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001231 unsigned int count,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001232 const HBUINT16 lookahead[],
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001233 match_func_t match_func,
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04001234 const void *match_data,
Behdad Esfahbod78481b32021-11-21 16:50:34 -07001235 unsigned int start_index,
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001236 unsigned int *end_index)
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001237{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001238 TRACE_APPLY (nullptr);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -04001239
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001240 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
Behdad Esfahbod78481b32021-11-21 16:50:34 -07001241 skippy_iter.reset (start_index - 1, count);
Behdad Esfahbod607feb72013-02-14 07:43:13 -05001242 skippy_iter.set_match_func (match_func, match_data, lookahead);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001243
Behdad Esfahbod370f03e2012-01-16 17:03:55 -05001244 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod3122c2c2021-12-04 19:50:33 -08001245 {
1246 unsigned unsafe_to;
1247 if (!skippy_iter.next (&unsafe_to))
1248 {
Behdad Esfahbod78481b32021-11-21 16:50:34 -07001249 *end_index = unsafe_to;
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001250 return_trace (false);
Behdad Esfahbod3122c2c2021-12-04 19:50:33 -08001251 }
1252 }
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001253
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001254 *end_index = skippy_iter.idx + 1;
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001255 return_trace (true);
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001256}
1257
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04001258
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001259
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001260struct LookupRecord
1261{
Qunxin Liu36ed56b2021-09-23 10:51:21 -07001262 bool serialize (hb_serialize_context_t *c,
1263 const hb_map_t *lookup_map) const
Qunxin Liu0b39c482019-10-22 16:00:43 -07001264 {
1265 TRACE_SERIALIZE (this);
1266 auto *out = c->embed (*this);
Qunxin Liu36ed56b2021-09-23 10:51:21 -07001267 if (unlikely (!out)) return_trace (false);
Qunxin Liu0b39c482019-10-22 16:00:43 -07001268
Qunxin Liu36ed56b2021-09-23 10:51:21 -07001269 return_trace (c->check_assign (out->lookupListIndex, lookup_map->get (lookupListIndex), HB_SERIALIZE_ERROR_INT_OVERFLOW));
Qunxin Liu0b39c482019-10-22 16:00:43 -07001270 }
1271
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301272 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001273 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001274 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001275 return_trace (c->check_struct (this));
Behdad Esfahbodcd3827e2009-08-04 02:09:34 -04001276 }
1277
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001278 HBUINT16 sequenceIndex; /* Index into current glyph
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001279 * sequence--first glyph = 0 */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001280 HBUINT16 lookupListIndex; /* Lookup to apply to that
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001281 * position--zero--based */
Behdad Esfahbod569da922010-05-10 16:38:32 -04001282 public:
1283 DEFINE_SIZE_STATIC (4);
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001284};
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001285
Qunxin Liu36ed56b2021-09-23 10:51:21 -07001286static unsigned serialize_lookuprecord_array (hb_serialize_context_t *c,
1287 const hb_array_t<const LookupRecord> lookupRecords,
1288 const hb_map_t *lookup_map)
1289{
1290 unsigned count = 0;
1291 for (const LookupRecord& r : lookupRecords)
1292 {
1293 if (!lookup_map->has (r.lookupListIndex))
1294 continue;
1295
1296 if (!r.serialize (c, lookup_map))
1297 return 0;
1298
1299 count++;
1300 }
1301 return count;
1302}
1303
Qunxin Liub8a58a02021-01-10 15:50:04 -08001304enum ContextFormat { SimpleContext = 1, ClassBasedContext = 2, CoverageBasedContext = 3 };
1305
1306static void context_closure_recurse_lookups (hb_closure_context_t *c,
1307 unsigned inputCount, const HBUINT16 input[],
1308 unsigned lookupCount,
1309 const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */,
1310 unsigned value,
1311 ContextFormat context_format,
1312 const void *data,
1313 intersected_glyphs_func_t intersected_glyphs_func)
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001314{
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08001315 hb_set_t *covered_seq_indicies = hb_set_create ();
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001316 for (unsigned int i = 0; i < lookupCount; i++)
Qunxin Liub8a58a02021-01-10 15:50:04 -08001317 {
1318 unsigned seqIndex = lookupRecord[i].sequenceIndex;
Garret Riegeradca4ce2021-03-30 13:20:50 -07001319 if (seqIndex >= inputCount) continue;
Qunxin Liub8a58a02021-01-10 15:50:04 -08001320
Garret Riegerf3c1f4f2022-01-28 11:50:22 -08001321 bool has_pos_glyphs = false;
1322 hb_set_t pos_glyphs;
Qunxin Liub8a58a02021-01-10 15:50:04 -08001323
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08001324 if (hb_set_is_empty (covered_seq_indicies) || !hb_set_has (covered_seq_indicies, seqIndex))
Qunxin Liub8a58a02021-01-10 15:50:04 -08001325 {
Garret Riegerf3c1f4f2022-01-28 11:50:22 -08001326 has_pos_glyphs = true;
Qunxin Liub8a58a02021-01-10 15:50:04 -08001327 if (seqIndex == 0)
1328 {
1329 switch (context_format) {
1330 case ContextFormat::SimpleContext:
Garret Riegerf3c1f4f2022-01-28 11:50:22 -08001331 pos_glyphs.add (value);
Qunxin Liub8a58a02021-01-10 15:50:04 -08001332 break;
1333 case ContextFormat::ClassBasedContext:
Garret Riegerbc899652022-01-28 13:54:10 -08001334 intersected_glyphs_func (&c->parent_active_glyphs (), data, value, &pos_glyphs);
Qunxin Liub8a58a02021-01-10 15:50:04 -08001335 break;
1336 case ContextFormat::CoverageBasedContext:
Garret Riegerbc899652022-01-28 13:54:10 -08001337 pos_glyphs.set (c->parent_active_glyphs ());
Qunxin Liub8a58a02021-01-10 15:50:04 -08001338 break;
1339 }
1340 }
1341 else
1342 {
1343 const void *input_data = input;
1344 unsigned input_value = seqIndex - 1;
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08001345 if (context_format != ContextFormat::SimpleContext)
Qunxin Liub8a58a02021-01-10 15:50:04 -08001346 {
1347 input_data = data;
1348 input_value = input[seqIndex - 1];
1349 }
Garret Riegerc6adb902021-03-29 16:08:44 -07001350
Garret Riegerf3c1f4f2022-01-28 11:50:22 -08001351 intersected_glyphs_func (c->glyphs, input_data, input_value, &pos_glyphs);
Qunxin Liub8a58a02021-01-10 15:50:04 -08001352 }
1353 }
1354
Garret Riegerf3c1f4f2022-01-28 11:50:22 -08001355 covered_seq_indicies->add (seqIndex);
1356 if (has_pos_glyphs) {
1357 c->push_cur_active_glyphs () = pos_glyphs;
1358 } else {
1359 c->push_cur_active_glyphs ().set (*c->glyphs);
1360 }
Garret Riegerc6adb902021-03-29 16:08:44 -07001361
Qunxin Liub8a58a02021-01-10 15:50:04 -08001362 unsigned endIndex = inputCount;
1363 if (context_format == ContextFormat::CoverageBasedContext)
1364 endIndex += 1;
1365
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08001366 c->recurse (lookupRecord[i].lookupListIndex, covered_seq_indicies, seqIndex, endIndex);
Garret Riegerc6adb902021-03-29 16:08:44 -07001367
Qunxin Liu706014f2021-12-01 20:20:12 -08001368 c->pop_cur_done_glyphs ();
Qunxin Liub8a58a02021-01-10 15:50:04 -08001369 }
Qunxin Liub4fc5932020-12-09 10:44:18 -08001370
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08001371 hb_set_destroy (covered_seq_indicies);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001372}
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04001373
Qunxin Liub8a58a02021-01-10 15:50:04 -08001374template <typename context_t>
1375static inline void recurse_lookups (context_t *c,
1376 unsigned int lookupCount,
1377 const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
1378{
1379 for (unsigned int i = 0; i < lookupCount; i++)
1380 c->recurse (lookupRecord[i].lookupListIndex);
1381}
1382
Behdad Esfahbod78481b32021-11-21 16:50:34 -07001383static inline void apply_lookup (hb_ot_apply_context_t *c,
Behdad Esfahbode072c242009-05-18 03:47:31 -04001384 unsigned int count, /* Including the first glyph */
Behdad Esfahbod5ba45042015-11-02 15:43:08 -08001385 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
Behdad Esfahbode072c242009-05-18 03:47:31 -04001386 unsigned int lookupCount,
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001387 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
Behdad Esfahbod78481b32021-11-21 16:50:34 -07001388 unsigned int match_end)
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001389{
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001390 hb_buffer_t *buffer = c->buffer;
jfkthame44f7d6e2017-02-17 03:03:24 +00001391 int end;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001392
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001393 /* All positions are distance from beginning of *output* buffer.
1394 * Adjust. */
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001395 {
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001396 unsigned int bl = buffer->backtrack_len ();
Behdad Esfahbod78481b32021-11-21 16:50:34 -07001397 end = bl + match_end - buffer->idx;
Behdad Esfahbod8751de52013-07-18 16:29:50 -04001398
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001399 int delta = bl - buffer->idx;
1400 /* Convert positions to new indexing. */
1401 for (unsigned int j = 0; j < count; j++)
1402 match_positions[j] += delta;
Behdad Esfahbod8820bb22013-02-14 07:41:03 -05001403 }
Behdad Esfahbode73a0c22009-05-18 04:15:25 -04001404
Behdad Esfahbod7185b272018-05-31 20:03:00 -07001405 for (unsigned int i = 0; i < lookupCount && buffer->successful; i++)
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001406 {
1407 unsigned int idx = lookupRecord[i].sequenceIndex;
1408 if (idx >= count)
1409 continue;
1410
Behdad Esfahbod9cc1ed42015-11-19 12:39:09 -08001411 /* Don't recurse to ourself at same position.
1412 * Note that this test is too naive, it doesn't catch longer loops. */
Behdad Esfahbod1da75af2021-02-10 00:03:30 -07001413 if (unlikely (idx == 0 && lookupRecord[i].lookupListIndex == c->lookup_index))
Behdad Esfahbod9cc1ed42015-11-19 12:39:09 -08001414 continue;
1415
Behdad Esfahbodccd91612022-03-24 13:10:48 -06001416 unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
1417
1418 /* This can happen if earlier recursed lookups deleted many entries. */
1419 if (unlikely (match_positions[idx] >= orig_len))
1420 continue;
1421
Behdad Esfahbode5930722017-11-14 15:47:55 -08001422 if (unlikely (!buffer->move_to (match_positions[idx])))
1423 break;
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001424
Behdad Esfahbodbaf77792017-11-14 21:53:48 -08001425 if (unlikely (buffer->max_ops <= 0))
1426 break;
1427
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001428 if (!c->recurse (lookupRecord[i].lookupListIndex))
1429 continue;
1430
1431 unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len ();
1432 int delta = new_len - orig_len;
1433
1434 if (!delta)
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03301435 continue;
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001436
Behdad Esfahbod9ac9af72017-03-05 13:51:01 -08001437 /* Recursed lookup changed buffer len. Adjust.
1438 *
1439 * TODO:
1440 *
1441 * Right now, if buffer length increased by n, we assume n new glyphs
1442 * were added right after the current position, and if buffer length
1443 * was decreased by n, we assume n match positions after the current
1444 * one where removed. The former (buffer length increased) case is
1445 * fine, but the decrease case can be improved in at least two ways,
1446 * both of which are significant:
1447 *
1448 * - If recursed-to lookup is MultipleSubst and buffer length
1449 * decreased, then it's current match position that was deleted,
1450 * NOT the one after it.
1451 *
1452 * - If buffer length was decreased by n, it does not necessarily
1453 * mean that n match positions where removed, as there might
1454 * have been marks and default-ignorables in the sequence. We
1455 * should instead drop match positions between current-position
Behdad Esfahbod1da75af2021-02-10 00:03:30 -07001456 * and current-position + n instead. Though, am not sure which
1457 * one is better. Both cases have valid uses. Sigh.
Behdad Esfahbod9ac9af72017-03-05 13:51:01 -08001458 *
1459 * It should be possible to construct tests for both of these cases.
1460 */
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001461
jfkthame44f7d6e2017-02-17 03:03:24 +00001462 end += delta;
Behdad Esfahbodccd91612022-03-24 13:10:48 -06001463 if (end < int (match_positions[idx]))
Behdad Esfahbod359dead2016-05-06 16:19:19 +01001464 {
Behdad Esfahbod4b4a1b92016-12-21 23:10:43 -06001465 /* End might end up being smaller than match_positions[idx] if the recursed
Behdad Esfahbodccd91612022-03-24 13:10:48 -06001466 * lookup ended up removing many items.
1467 * Just never rewind end beyond start of current position, since that is
1468 * not possible in the recursed lookup. Also adjust delta as such.
1469 *
1470 * https://bugs.chromium.org/p/chromium/issues/detail?id=659496
1471 * https://github.com/harfbuzz/harfbuzz/issues/1611
1472 */
1473 delta += match_positions[idx] - end;
Behdad Esfahbod4b4a1b92016-12-21 23:10:43 -06001474 end = match_positions[idx];
Behdad Esfahbod359dead2016-05-06 16:19:19 +01001475 }
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001476
1477 unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */
1478
1479 if (delta > 0)
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001480 {
Behdad Esfahbod5ba45042015-11-02 15:43:08 -08001481 if (unlikely (delta + count > HB_MAX_CONTEXT_LENGTH))
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001482 break;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001483 }
1484 else
1485 {
Behdad Esfahbodbf2a8452022-03-24 13:09:53 -06001486 /* NOTE: delta is non-positive. */
Behdad Esfahbod41248cc2019-05-07 20:54:31 -07001487 delta = hb_max (delta, (int) next - (int) count);
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001488 next -= delta;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001489 }
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001490
1491 /* Shift! */
1492 memmove (match_positions + next + delta, match_positions + next,
1493 (count - next) * sizeof (match_positions[0]));
1494 next += delta;
1495 count += delta;
1496
1497 /* Fill in new entries. */
1498 for (unsigned int j = idx + 1; j < next; j++)
1499 match_positions[j] = match_positions[j - 1] + 1;
1500
1501 /* And fixup the rest. */
1502 for (; next < count; next++)
1503 match_positions[next] += delta;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001504 }
1505
Behdad Esfahbodcac6c862021-03-15 13:46:54 -06001506 (void) buffer->move_to (end);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001507}
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001508
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04001509
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001510
1511/* Contextual lookups */
1512
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001513struct ContextClosureLookupContext
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001514{
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001515 ContextClosureFuncs funcs;
Qunxin Liub8a58a02021-01-10 15:50:04 -08001516 ContextFormat context_format;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001517 const void *intersects_data;
1518};
1519
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001520struct ContextCollectGlyphsLookupContext
1521{
1522 ContextCollectGlyphsFuncs funcs;
1523 const void *collect_data;
1524};
1525
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001526struct ContextApplyLookupContext
1527{
1528 ContextApplyFuncs funcs;
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04001529 const void *match_data;
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001530};
1531
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001532static inline bool context_intersects (const hb_set_t *glyphs,
1533 unsigned int inputCount, /* Including the first glyph (not matched) */
1534 const HBUINT16 input[], /* Array of input values--start with second glyph */
1535 ContextClosureLookupContext &lookup_context)
1536{
Qunxin Liu44d88cf2020-05-08 15:33:34 -07001537 return array_is_subset_of (glyphs,
1538 inputCount ? inputCount - 1 : 0, input,
1539 lookup_context.funcs.intersects, lookup_context.intersects_data);
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001540}
1541
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001542static inline void context_closure_lookup (hb_closure_context_t *c,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001543 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001544 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001545 unsigned int lookupCount,
1546 const LookupRecord lookupRecord[],
Qunxin Liub8a58a02021-01-10 15:50:04 -08001547 unsigned value, /* Index of first glyph in Coverage or Class value in ClassDef table */
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001548 ContextClosureLookupContext &lookup_context)
1549{
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001550 if (context_intersects (c->glyphs,
1551 inputCount, input,
1552 lookup_context))
Qunxin Liub8a58a02021-01-10 15:50:04 -08001553 context_closure_recurse_lookups (c,
1554 inputCount, input,
1555 lookupCount, lookupRecord,
1556 value,
1557 lookup_context.context_format,
1558 lookup_context.intersects_data,
1559 lookup_context.funcs.intersected_glyphs);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001560}
1561
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001562static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
1563 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001564 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001565 unsigned int lookupCount,
1566 const LookupRecord lookupRecord[],
1567 ContextCollectGlyphsLookupContext &lookup_context)
1568{
Behdad Esfahbod83035932012-12-04 17:08:41 -05001569 collect_array (c, c->input,
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001570 inputCount ? inputCount - 1 : 0, input,
1571 lookup_context.funcs.collect, lookup_context.collect_data);
1572 recurse_lookups (c,
1573 lookupCount, lookupRecord);
1574}
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001575
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001576static inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
1577 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001578 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbod0beb66e2012-12-05 18:46:04 -05001579 unsigned int lookupCount HB_UNUSED,
1580 const LookupRecord lookupRecord[] HB_UNUSED,
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001581 ContextApplyLookupContext &lookup_context)
1582{
1583 return would_match_input (c,
1584 inputCount, input,
1585 lookup_context.funcs.match, lookup_context.match_data);
1586}
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001587static inline bool context_apply_lookup (hb_ot_apply_context_t *c,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001588 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001589 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001590 unsigned int lookupCount,
1591 const LookupRecord lookupRecord[],
1592 ContextApplyLookupContext &lookup_context)
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001593{
Behdad Esfahbod78481b32021-11-21 16:50:34 -07001594 unsigned match_end = 0;
1595 unsigned match_positions[HB_MAX_CONTEXT_LENGTH];
1596 if (match_input (c,
1597 inputCount, input,
1598 lookup_context.funcs.match, lookup_context.match_data,
1599 &match_end, match_positions))
1600 {
1601 c->buffer->unsafe_to_break (c->buffer->idx, match_end);
1602 apply_lookup (c,
1603 inputCount, match_positions,
1604 lookupCount, lookupRecord,
1605 match_end);
1606 return true;
1607 }
1608 else
1609 {
1610 c->buffer->unsafe_to_concat (c->buffer->idx, match_end);
1611 return false;
1612 }
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001613}
1614
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001615struct Rule
1616{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301617 bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001618 {
1619 return context_intersects (glyphs,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001620 inputCount, inputZ.arrayZ,
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001621 lookup_context);
1622 }
1623
Qunxin Liub8a58a02021-01-10 15:50:04 -08001624 void closure (hb_closure_context_t *c, unsigned value, ContextClosureLookupContext &lookup_context) const
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001625 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04301626 if (unlikely (c->lookup_limit_exceeded ())) return;
Garret Rieger014e0382020-03-31 16:29:29 -07001627
Ebrahim Byagowi92588782019-04-30 13:05:10 -07001628 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
Behdad Esfahbod0382b712018-11-02 12:23:26 -04001629 (inputZ.as_array ((inputCount ? inputCount - 1 : 0)));
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001630 context_closure_lookup (c,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001631 inputCount, inputZ.arrayZ,
1632 lookupCount, lookupRecord.arrayZ,
Qunxin Liub8a58a02021-01-10 15:50:04 -08001633 value, lookup_context);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001634 }
1635
Garret Rieger9fad5402020-09-28 13:24:25 -07001636 void closure_lookups (hb_closure_lookups_context_t *c,
1637 ContextClosureLookupContext &lookup_context) const
Qunxin Liu0b39c482019-10-22 16:00:43 -07001638 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04301639 if (unlikely (c->lookup_limit_exceeded ())) return;
Garret Rieger9fad5402020-09-28 13:24:25 -07001640 if (!intersects (c->glyphs, lookup_context)) return;
Garret Rieger014e0382020-03-31 16:29:29 -07001641
Qunxin Liu0b39c482019-10-22 16:00:43 -07001642 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
1643 (inputZ.as_array (inputCount ? inputCount - 1 : 0));
1644 recurse_lookups (c, lookupCount, lookupRecord.arrayZ);
1645 }
1646
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301647 void collect_glyphs (hb_collect_glyphs_context_t *c,
1648 ContextCollectGlyphsLookupContext &lookup_context) const
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001649 {
Ebrahim Byagowi92588782019-04-30 13:05:10 -07001650 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
Behdad Esfahbod0382b712018-11-02 12:23:26 -04001651 (inputZ.as_array (inputCount ? inputCount - 1 : 0));
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001652 context_collect_glyphs_lookup (c,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001653 inputCount, inputZ.arrayZ,
1654 lookupCount, lookupRecord.arrayZ,
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001655 lookup_context);
1656 }
1657
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301658 bool would_apply (hb_would_apply_context_t *c,
1659 ContextApplyLookupContext &lookup_context) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001660 {
Ebrahim Byagowi92588782019-04-30 13:05:10 -07001661 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
Behdad Esfahbod0382b712018-11-02 12:23:26 -04001662 (inputZ.as_array (inputCount ? inputCount - 1 : 0));
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07001663 return context_would_apply_lookup (c,
1664 inputCount, inputZ.arrayZ,
1665 lookupCount, lookupRecord.arrayZ,
1666 lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001667 }
1668
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301669 bool apply (hb_ot_apply_context_t *c,
1670 ContextApplyLookupContext &lookup_context) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001671 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001672 TRACE_APPLY (this);
Ebrahim Byagowi92588782019-04-30 13:05:10 -07001673 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
Behdad Esfahbod0382b712018-11-02 12:23:26 -04001674 (inputZ.as_array (inputCount ? inputCount - 1 : 0));
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001675 return_trace (context_apply_lookup (c, inputCount, inputZ.arrayZ, lookupCount, lookupRecord.arrayZ, lookup_context));
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001676 }
1677
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001678 bool serialize (hb_serialize_context_t *c,
1679 const hb_map_t *input_mapping, /* old->new glyphid or class mapping */
1680 const hb_map_t *lookup_map) const
1681 {
1682 TRACE_SERIALIZE (this);
1683 auto *out = c->start_embed (this);
1684 if (unlikely (!c->extend_min (out))) return_trace (false);
1685
1686 out->inputCount = inputCount;
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001687 const hb_array_t<const HBUINT16> input = inputZ.as_array (inputCount - 1);
1688 for (const auto org : input)
1689 {
1690 HBUINT16 d;
1691 d = input_mapping->get (org);
1692 c->copy (d);
1693 }
1694
1695 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
Ebrahim Byagowi5a7cc7f2020-07-29 08:33:32 +04301696 (inputZ.as_array ((inputCount ? inputCount - 1 : 0)));
Garret Riegerf51b48c2021-11-02 16:16:52 -07001697
Qunxin Liu36ed56b2021-09-23 10:51:21 -07001698 unsigned count = serialize_lookuprecord_array (c, lookupRecord.as_array (lookupCount), lookup_map);
1699 return_trace (c->check_assign (out->lookupCount, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001700 }
1701
1702 bool subset (hb_subset_context_t *c,
1703 const hb_map_t *lookup_map,
1704 const hb_map_t *klass_map = nullptr) const
1705 {
1706 TRACE_SUBSET (this);
Qunxin Liue88fc412021-11-18 16:53:36 -08001707 if (unlikely (!inputCount)) return_trace (false);
1708 const hb_array_t<const HBUINT16> input = inputZ.as_array (inputCount - 1);
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001709
1710 const hb_map_t *mapping = klass_map == nullptr ? c->plan->glyph_map : klass_map;
1711 if (!hb_all (input, mapping)) return_trace (false);
1712 return_trace (serialize (c->serializer, mapping, lookup_map));
1713 }
1714
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001715 public:
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301716 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001717 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001718 TRACE_SANITIZE (this);
Behdad Esfahbod5aad8192017-11-03 17:16:26 -04001719 return_trace (inputCount.sanitize (c) &&
1720 lookupCount.sanitize (c) &&
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001721 c->check_range (inputZ.arrayZ,
Behdad Esfahbod9c6921c2018-11-30 15:16:57 -05001722 inputZ.item_size * (inputCount ? inputCount - 1 : 0) +
Behdad Esfahbod6d7c6e12018-02-07 14:09:56 -06001723 LookupRecord::static_size * lookupCount));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001724 }
1725
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001726 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001727 HBUINT16 inputCount; /* Total number of glyphs in input
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001728 * glyph sequence--includes the first
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001729 * glyph */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001730 HBUINT16 lookupCount; /* Number of LookupRecords */
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001731 UnsizedArrayOf<HBUINT16>
Ebrahim Byagowice114d62019-12-31 15:53:02 +03301732 inputZ; /* Array of match inputs--start with
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001733 * second glyph */
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001734/*UnsizedArrayOf<LookupRecord>
1735 lookupRecordX;*/ /* Array of LookupRecords--in
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001736 * design order */
Behdad Esfahbod569da922010-05-10 16:38:32 -04001737 public:
Behdad Esfahbod6d7c6e12018-02-07 14:09:56 -06001738 DEFINE_SIZE_ARRAY (4, inputZ);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001739};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001740
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001741struct RuleSet
1742{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301743 bool intersects (const hb_set_t *glyphs,
1744 ContextClosureLookupContext &lookup_context) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001745 {
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001746 return
1747 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07001748 | hb_map (hb_add (this))
1749 | hb_map ([&] (const Rule &_) { return _.intersects (glyphs, lookup_context); })
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001750 | hb_any
1751 ;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001752 }
1753
Qunxin Liub8a58a02021-01-10 15:50:04 -08001754 void closure (hb_closure_context_t *c, unsigned value,
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301755 ContextClosureLookupContext &lookup_context) const
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001756 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04301757 if (unlikely (c->lookup_limit_exceeded ())) return;
Garret Rieger014e0382020-03-31 16:29:29 -07001758
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001759 return
1760 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07001761 | hb_map (hb_add (this))
Qunxin Liub8a58a02021-01-10 15:50:04 -08001762 | hb_apply ([&] (const Rule &_) { _.closure (c, value, lookup_context); })
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001763 ;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001764 }
1765
Garret Rieger9fad5402020-09-28 13:24:25 -07001766 void closure_lookups (hb_closure_lookups_context_t *c,
1767 ContextClosureLookupContext &lookup_context) const
Qunxin Liu0b39c482019-10-22 16:00:43 -07001768 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04301769 if (unlikely (c->lookup_limit_exceeded ())) return;
Qunxin Liu0b39c482019-10-22 16:00:43 -07001770 + hb_iter (rule)
1771 | hb_map (hb_add (this))
Garret Riegere31c2692020-09-28 16:51:25 -07001772 | hb_apply ([&] (const Rule &_) { _.closure_lookups (c, lookup_context); })
Qunxin Liu0b39c482019-10-22 16:00:43 -07001773 ;
1774 }
1775
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301776 void collect_glyphs (hb_collect_glyphs_context_t *c,
1777 ContextCollectGlyphsLookupContext &lookup_context) const
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001778 {
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001779 return
1780 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07001781 | hb_map (hb_add (this))
1782 | hb_apply ([&] (const Rule &_) { _.collect_glyphs (c, lookup_context); })
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001783 ;
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001784 }
1785
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301786 bool would_apply (hb_would_apply_context_t *c,
1787 ContextApplyLookupContext &lookup_context) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001788 {
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001789 return
1790 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07001791 | hb_map (hb_add (this))
1792 | hb_map ([&] (const Rule &_) { return _.would_apply (c, lookup_context); })
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001793 | hb_any
1794 ;
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001795 }
1796
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301797 bool apply (hb_ot_apply_context_t *c,
1798 ContextApplyLookupContext &lookup_context) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001799 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001800 TRACE_APPLY (this);
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001801 return_trace (
1802 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07001803 | hb_map (hb_add (this))
1804 | hb_map ([&] (const Rule &_) { return _.apply (c, lookup_context); })
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001805 | hb_any
1806 )
1807 ;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001808 }
1809
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001810 bool subset (hb_subset_context_t *c,
1811 const hb_map_t *lookup_map,
1812 const hb_map_t *klass_map = nullptr) const
1813 {
1814 TRACE_SUBSET (this);
1815
1816 auto snap = c->serializer->snapshot ();
1817 auto *out = c->serializer->start_embed (*this);
1818 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
1819
Behdad Esfahbodad28f972021-03-31 12:49:14 -06001820 for (const Offset16To<Rule>& _ : rule)
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001821 {
1822 if (!_) continue;
Garret Riegerc2cc5662021-09-22 14:15:55 -07001823 auto o_snap = c->serializer->snapshot ();
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001824 auto *o = out->rule.serialize_append (c->serializer);
1825 if (unlikely (!o)) continue;
1826
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001827 if (!o->serialize_subset (c, _, this, lookup_map, klass_map))
1828 {
Ebrahim Byagowi5a7cc7f2020-07-29 08:33:32 +04301829 out->rule.pop ();
1830 c->serializer->revert (o_snap);
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001831 }
1832 }
1833
1834 bool ret = bool (out->rule);
1835 if (!ret) c->serializer->revert (snap);
1836
1837 return_trace (ret);
1838 }
1839
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301840 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001841 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001842 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001843 return_trace (rule.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001844 }
1845
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001846 protected:
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06001847 Array16OfOffset16To<Rule>
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001848 rule; /* Array of Rule tables
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001849 * ordered by preference */
Behdad Esfahboded074222010-05-10 18:08:46 -04001850 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04001851 DEFINE_SIZE_ARRAY (2, rule);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001852};
1853
1854
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001855struct ContextFormat1
1856{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301857 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001858 {
1859 struct ContextClosureLookupContext lookup_context = {
Qunxin Liub8a58a02021-01-10 15:50:04 -08001860 {intersects_glyph, intersected_glyph},
1861 ContextFormat::SimpleContext,
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001862 nullptr
1863 };
Behdad Esfahbod05f21302019-03-29 22:40:13 -07001864
1865 return
1866 + hb_zip (this+coverage, ruleSet)
1867 | hb_filter (*glyphs, hb_first)
1868 | hb_map (hb_second)
Behdad Esfahbod23768672019-05-15 21:57:26 -07001869 | hb_map (hb_add (this))
1870 | hb_map ([&] (const RuleSet &_) { return _.intersects (glyphs, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07001871 | hb_any
1872 ;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001873 }
1874
Qunxin Liub4fc5932020-12-09 10:44:18 -08001875 bool may_have_non_1to1 () const
1876 { return true; }
1877
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301878 void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001879 {
Garret Rieger4e2f4092022-01-31 12:20:32 -08001880 hb_set_t* cur_active_glyphs = &c->push_cur_active_glyphs ();
1881 get_coverage ().intersected_coverage_glyphs (&c->previous_parent_active_glyphs (),
1882 cur_active_glyphs);
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08001883
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001884 struct ContextClosureLookupContext lookup_context = {
Qunxin Liub8a58a02021-01-10 15:50:04 -08001885 {intersects_glyph, intersected_glyph},
1886 ContextFormat::SimpleContext,
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001887 nullptr
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001888 };
Behdad Esfahbod05f21302019-03-29 22:40:13 -07001889
Qunxin Liub8a58a02021-01-10 15:50:04 -08001890 + hb_zip (this+coverage, hb_range ((unsigned) ruleSet.len))
Garret Rieger4e2f4092022-01-31 12:20:32 -08001891 | hb_filter ([&] (hb_codepoint_t _) {
1892 return c->previous_parent_active_glyphs ().has (_);
1893 }, hb_first)
Qunxin Liub8a58a02021-01-10 15:50:04 -08001894 | hb_map ([&](const hb_pair_t<hb_codepoint_t, unsigned> _) { return hb_pair_t<unsigned, const RuleSet&> (_.first, this+ruleSet[_.second]); })
1895 | hb_apply ([&] (const hb_pair_t<unsigned, const RuleSet&>& _) { _.second.closure (c, _.first, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07001896 ;
Garret Riegerbc899652022-01-28 13:54:10 -08001897
1898 c->pop_cur_done_glyphs ();
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001899 }
1900
Qunxin Liu0b39c482019-10-22 16:00:43 -07001901 void closure_lookups (hb_closure_lookups_context_t *c) const
1902 {
Garret Rieger9fad5402020-09-28 13:24:25 -07001903 struct ContextClosureLookupContext lookup_context = {
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08001904 {intersects_glyph, intersected_glyph},
1905 ContextFormat::SimpleContext,
Garret Rieger9fad5402020-09-28 13:24:25 -07001906 nullptr
1907 };
1908
1909 + hb_zip (this+coverage, ruleSet)
1910 | hb_filter (*c->glyphs, hb_first)
1911 | hb_map (hb_second)
Qunxin Liu0b39c482019-10-22 16:00:43 -07001912 | hb_map (hb_add (this))
Garret Riegere31c2692020-09-28 16:51:25 -07001913 | hb_apply ([&] (const RuleSet &_) { _.closure_lookups (c, lookup_context); })
Qunxin Liu0b39c482019-10-22 16:00:43 -07001914 ;
1915 }
1916
Qunxin Liu8200e482020-02-26 13:11:42 -08001917 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
1918
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301919 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001920 {
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07001921 (this+coverage).collect_coverage (c->input);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001922
1923 struct ContextCollectGlyphsLookupContext lookup_context = {
1924 {collect_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001925 nullptr
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001926 };
1927
Behdad Esfahbod05f21302019-03-29 22:40:13 -07001928 + hb_iter (ruleSet)
Behdad Esfahbod23768672019-05-15 21:57:26 -07001929 | hb_map (hb_add (this))
1930 | hb_apply ([&] (const RuleSet &_) { _.collect_glyphs (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07001931 ;
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001932 }
1933
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301934 bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001935 {
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05001936 const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001937 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001938 {match_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001939 nullptr
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001940 };
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07001941 return rule_set.would_apply (c, lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001942 }
1943
Ebrahim Byagowie4120082018-12-17 21:31:01 +03301944 const Coverage &get_coverage () const { return this+coverage; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001945
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301946 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001947 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001948 TRACE_APPLY (this);
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05001949 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -04001950 if (likely (index == NOT_COVERED))
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001951 return_trace (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04001952
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001953 const RuleSet &rule_set = this+ruleSet[index];
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001954 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001955 {match_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001956 nullptr
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001957 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001958 return_trace (rule_set.apply (c, lookup_context));
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001959 }
1960
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301961 bool subset (hb_subset_context_t *c) const
Behdad Esfahbod339d3602018-09-03 17:33:34 -07001962 {
1963 TRACE_SUBSET (this);
Garret Riegere5835052020-09-29 11:05:08 -07001964 const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001965 const hb_map_t &glyph_map = *c->plan->glyph_map;
1966
1967 auto *out = c->serializer->start_embed (*this);
1968 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
1969 out->format = format;
1970
1971 const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
1972 hb_sorted_vector_t<hb_codepoint_t> new_coverage;
1973 + hb_zip (this+coverage, ruleSet)
1974 | hb_filter (glyphset, hb_first)
1975 | hb_filter (subset_offset_array (c, out->ruleSet, this, lookup_map), hb_second)
1976 | hb_map (hb_first)
1977 | hb_map (glyph_map)
1978 | hb_sink (new_coverage)
1979 ;
1980
Garret Rieger085aa652021-06-14 16:47:45 -07001981 out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001982 return_trace (bool (new_coverage));
Behdad Esfahbod339d3602018-09-03 17:33:34 -07001983 }
1984
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301985 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001986 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001987 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001988 return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001989 }
1990
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001991 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001992 HBUINT16 format; /* Format identifier--format = 1 */
Behdad Esfahbodad28f972021-03-31 12:49:14 -06001993 Offset16To<Coverage>
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001994 coverage; /* Offset to Coverage table--from
1995 * beginning of table */
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06001996 Array16OfOffset16To<RuleSet>
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001997 ruleSet; /* Array of RuleSet tables
1998 * ordered by Coverage Index */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04001999 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04002000 DEFINE_SIZE_ARRAY (6, ruleSet);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002001};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002002
2003
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002004struct ContextFormat2
2005{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302006 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002007 {
2008 if (!(this+coverage).intersects (glyphs))
2009 return false;
2010
2011 const ClassDef &class_def = this+classDef;
2012
2013 struct ContextClosureLookupContext lookup_context = {
Qunxin Liub8a58a02021-01-10 15:50:04 -08002014 {intersects_class, intersected_class_glyphs},
2015 ContextFormat::ClassBasedContext,
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002016 &class_def
2017 };
2018
Qunxin Liu540f19b2021-10-29 17:11:53 -07002019 hb_set_t retained_coverage_glyphs;
2020 (this+coverage).intersected_coverage_glyphs (glyphs, &retained_coverage_glyphs);
2021
2022 hb_set_t coverage_glyph_classes;
2023 class_def.intersected_classes (&retained_coverage_glyphs, &coverage_glyph_classes);
2024
2025
Behdad Esfahbod668d2d52019-03-29 22:48:38 -07002026 return
Behdad Esfahbod26111a12020-06-28 02:59:47 -07002027 + hb_iter (ruleSet)
2028 | hb_map (hb_add (this))
2029 | hb_enumerate
2030 | hb_map ([&] (const hb_pair_t<unsigned, const RuleSet &> p)
Behdad Esfahbode5306922019-03-29 23:31:07 -07002031 { return class_def.intersects_class (glyphs, p.first) &&
Qunxin Liu540f19b2021-10-29 17:11:53 -07002032 coverage_glyph_classes.has (p.first) &&
Behdad Esfahbod26111a12020-06-28 02:59:47 -07002033 p.second.intersects (glyphs, lookup_context); })
Behdad Esfahbod668d2d52019-03-29 22:48:38 -07002034 | hb_any
2035 ;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002036 }
2037
Qunxin Liub4fc5932020-12-09 10:44:18 -08002038 bool may_have_non_1to1 () const
2039 { return true; }
2040
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302041 void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002042 {
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002043 if (!(this+coverage).intersects (c->glyphs))
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002044 return;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002045
Garret Rieger4e2f4092022-01-31 12:20:32 -08002046 hb_set_t* cur_active_glyphs = &c->push_cur_active_glyphs ();
2047 get_coverage ().intersected_coverage_glyphs (&c->previous_parent_active_glyphs (),
2048 cur_active_glyphs);
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08002049
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002050 const ClassDef &class_def = this+classDef;
2051
2052 struct ContextClosureLookupContext lookup_context = {
Qunxin Liub8a58a02021-01-10 15:50:04 -08002053 {intersects_class, intersected_class_glyphs},
2054 ContextFormat::ClassBasedContext,
Behdad Esfahbod11fba792013-01-02 23:36:37 -06002055 &class_def
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002056 };
2057
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07002058 + hb_enumerate (ruleSet)
Behdad Esfahbod78d35f02019-05-15 18:15:05 -07002059 | hb_filter ([&] (unsigned _)
Garret Riegerbc899652022-01-28 13:54:10 -08002060 { return class_def.intersects_class (&c->parent_active_glyphs (), _); },
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07002061 hb_first)
Behdad Esfahbodad28f972021-03-31 12:49:14 -06002062 | hb_apply ([&] (const hb_pair_t<unsigned, const Offset16To<RuleSet>&> _)
Qunxin Liub8a58a02021-01-10 15:50:04 -08002063 {
2064 const RuleSet& rule_set = this+_.second;
2065 rule_set.closure (c, _.first, lookup_context);
2066 })
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07002067 ;
Garret Riegerbc899652022-01-28 13:54:10 -08002068
2069 c->pop_cur_done_glyphs ();
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002070 }
2071
Qunxin Liu0b39c482019-10-22 16:00:43 -07002072 void closure_lookups (hb_closure_lookups_context_t *c) const
2073 {
Garret Rieger9fad5402020-09-28 13:24:25 -07002074 if (!(this+coverage).intersects (c->glyphs))
2075 return;
2076
2077 const ClassDef &class_def = this+classDef;
2078
2079 struct ContextClosureLookupContext lookup_context = {
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08002080 {intersects_class, intersected_class_glyphs},
2081 ContextFormat::ClassBasedContext,
Garret Rieger9fad5402020-09-28 13:24:25 -07002082 &class_def
2083 };
2084
Qunxin Liu0b39c482019-10-22 16:00:43 -07002085 + hb_iter (ruleSet)
2086 | hb_map (hb_add (this))
Garret Rieger9fad5402020-09-28 13:24:25 -07002087 | hb_enumerate
2088 | hb_filter ([&] (const hb_pair_t<unsigned, const RuleSet &> p)
2089 { return class_def.intersects_class (c->glyphs, p.first); })
2090 | hb_map (hb_second)
2091 | hb_apply ([&] (const RuleSet & _)
2092 { _.closure_lookups (c, lookup_context); });
Qunxin Liu0b39c482019-10-22 16:00:43 -07002093 }
2094
Qunxin Liu8200e482020-02-26 13:11:42 -08002095 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
2096
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302097 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002098 {
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07002099 (this+coverage).collect_coverage (c->input);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05002100
Behdad Esfahbod11fba792013-01-02 23:36:37 -06002101 const ClassDef &class_def = this+classDef;
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05002102 struct ContextCollectGlyphsLookupContext lookup_context = {
2103 {collect_class},
Behdad Esfahbod11fba792013-01-02 23:36:37 -06002104 &class_def
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05002105 };
2106
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002107 + hb_iter (ruleSet)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002108 | hb_map (hb_add (this))
2109 | hb_apply ([&] (const RuleSet &_) { _.collect_glyphs (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002110 ;
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002111 }
2112
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302113 bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002114 {
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002115 const ClassDef &class_def = this+classDef;
Behdad Esfahbod2dc11412012-11-24 19:16:34 -05002116 unsigned int index = class_def.get_class (c->glyphs[0]);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002117 const RuleSet &rule_set = this+ruleSet[index];
2118 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002119 {match_class},
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002120 &class_def
2121 };
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07002122 return rule_set.would_apply (c, lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002123 }
2124
Ebrahim Byagowie4120082018-12-17 21:31:01 +03302125 const Coverage &get_coverage () const { return this+coverage; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002126
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302127 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002128 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002129 TRACE_APPLY (this);
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05002130 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002131 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002132
2133 const ClassDef &class_def = this+classDef;
Behdad Esfahbod2dc11412012-11-24 19:16:34 -05002134 index = class_def.get_class (c->buffer->cur().codepoint);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002135 const RuleSet &rule_set = this+ruleSet[index];
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002136 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002137 {match_class},
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04002138 &class_def
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002139 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002140 return_trace (rule_set.apply (c, lookup_context));
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002141 }
2142
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302143 bool subset (hb_subset_context_t *c) const
Behdad Esfahbod339d3602018-09-03 17:33:34 -07002144 {
2145 TRACE_SUBSET (this);
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002146 auto *out = c->serializer->start_embed (*this);
2147 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
2148 out->format = format;
2149 if (unlikely (!out->coverage.serialize_subset (c, coverage, this)))
2150 return_trace (false);
2151
2152 hb_map_t klass_map;
2153 out->classDef.serialize_subset (c, classDef, this, &klass_map);
2154
Qunxin Liu540f19b2021-10-29 17:11:53 -07002155 const hb_set_t* glyphset = c->plan->glyphset_gsub ();
2156 hb_set_t retained_coverage_glyphs;
2157 (this+coverage).intersected_coverage_glyphs (glyphset, &retained_coverage_glyphs);
Garret Riegerf51b48c2021-11-02 16:16:52 -07002158
Qunxin Liu540f19b2021-10-29 17:11:53 -07002159 hb_set_t coverage_glyph_classes;
2160 (this+classDef).intersected_classes (&retained_coverage_glyphs, &coverage_glyph_classes);
2161
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002162 const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
2163 bool ret = true;
Qunxin Liu540f19b2021-10-29 17:11:53 -07002164 int non_zero_index = -1, index = 0;
Behdad Esfahbod6d941942021-02-19 17:08:10 -07002165 for (const auto& _ : + hb_enumerate (ruleSet)
2166 | hb_filter (klass_map, hb_first))
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002167 {
2168 auto *o = out->ruleSet.serialize_append (c->serializer);
2169 if (unlikely (!o))
2170 {
Ebrahim Byagowi5a7cc7f2020-07-29 08:33:32 +04302171 ret = false;
2172 break;
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002173 }
2174
Qunxin Liu540f19b2021-10-29 17:11:53 -07002175 if (coverage_glyph_classes.has (_.first) &&
2176 o->serialize_subset (c, _.second, this, lookup_map, &klass_map))
Ebrahim Byagowi5a7cc7f2020-07-29 08:33:32 +04302177 non_zero_index = index;
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002178
2179 index++;
2180 }
2181
Qunxin Liu540f19b2021-10-29 17:11:53 -07002182 if (!ret || non_zero_index == -1) return_trace (false);
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002183
2184 //prune empty trailing ruleSets
2185 --index;
2186 while (index > non_zero_index)
2187 {
2188 out->ruleSet.pop ();
2189 index--;
2190 }
2191
2192 return_trace (bool (out->ruleSet));
Behdad Esfahbod339d3602018-09-03 17:33:34 -07002193 }
2194
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302195 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002196 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002197 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002198 return_trace (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002199 }
2200
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002201 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002202 HBUINT16 format; /* Format identifier--format = 2 */
Behdad Esfahbodad28f972021-03-31 12:49:14 -06002203 Offset16To<Coverage>
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002204 coverage; /* Offset to Coverage table--from
2205 * beginning of table */
Behdad Esfahbodad28f972021-03-31 12:49:14 -06002206 Offset16To<ClassDef>
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002207 classDef; /* Offset to glyph ClassDef table--from
2208 * beginning of table */
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06002209 Array16OfOffset16To<RuleSet>
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002210 ruleSet; /* Array of RuleSet tables
2211 * ordered by class */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04002212 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04002213 DEFINE_SIZE_ARRAY (8, ruleSet);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002214};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002215
2216
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002217struct ContextFormat3
2218{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302219 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002220 {
Behdad Esfahbodfb059082018-11-30 20:45:40 -05002221 if (!(this+coverageZ[0]).intersects (glyphs))
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002222 return false;
2223
2224 struct ContextClosureLookupContext lookup_context = {
Qunxin Liub8a58a02021-01-10 15:50:04 -08002225 {intersects_coverage, intersected_coverage_glyphs},
2226 ContextFormat::CoverageBasedContext,
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002227 this
2228 };
2229 return context_intersects (glyphs,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02002230 glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002231 lookup_context);
2232 }
2233
Qunxin Liub4fc5932020-12-09 10:44:18 -08002234 bool may_have_non_1to1 () const
2235 { return true; }
2236
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302237 void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002238 {
Behdad Esfahbodfb059082018-11-30 20:45:40 -05002239 if (!(this+coverageZ[0]).intersects (c->glyphs))
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002240 return;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002241
Garret Rieger4e2f4092022-01-31 12:20:32 -08002242 hb_set_t* cur_active_glyphs = &c->push_cur_active_glyphs ();
2243 get_coverage ().intersected_coverage_glyphs (&c->previous_parent_active_glyphs (),
2244 cur_active_glyphs);
2245
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08002246
Behdad Esfahbod0382b712018-11-02 12:23:26 -04002247 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002248 struct ContextClosureLookupContext lookup_context = {
Qunxin Liub8a58a02021-01-10 15:50:04 -08002249 {intersects_coverage, intersected_coverage_glyphs},
2250 ContextFormat::CoverageBasedContext,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002251 this
2252 };
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002253 context_closure_lookup (c,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02002254 glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002255 lookupCount, lookupRecord,
Qunxin Liub8a58a02021-01-10 15:50:04 -08002256 0, lookup_context);
Garret Riegerbc899652022-01-28 13:54:10 -08002257
2258 c->pop_cur_done_glyphs ();
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002259 }
2260
Qunxin Liu0b39c482019-10-22 16:00:43 -07002261 void closure_lookups (hb_closure_lookups_context_t *c) const
2262 {
Garret Riegera5c0ec72020-09-25 14:57:20 -07002263 if (!intersects (c->glyphs))
2264 return;
Qunxin Liu0b39c482019-10-22 16:00:43 -07002265 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
2266 recurse_lookups (c, lookupCount, lookupRecord);
2267 }
2268
Qunxin Liu8200e482020-02-26 13:11:42 -08002269 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
2270
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302271 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002272 {
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07002273 (this+coverageZ[0]).collect_coverage (c->input);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05002274
Behdad Esfahbod0382b712018-11-02 12:23:26 -04002275 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05002276 struct ContextCollectGlyphsLookupContext lookup_context = {
2277 {collect_coverage},
Behdad Esfahbode75943d2012-11-30 08:38:24 +02002278 this
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05002279 };
2280
2281 context_collect_glyphs_lookup (c,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02002282 glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05002283 lookupCount, lookupRecord,
2284 lookup_context);
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002285 }
2286
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302287 bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002288 {
Behdad Esfahbod0382b712018-11-02 12:23:26 -04002289 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002290 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002291 {match_coverage},
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002292 this
2293 };
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07002294 return context_would_apply_lookup (c,
2295 glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
2296 lookupCount, lookupRecord,
2297 lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002298 }
2299
Ebrahim Byagowie4120082018-12-17 21:31:01 +03302300 const Coverage &get_coverage () const { return this+coverageZ[0]; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002301
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302302 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002303 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002304 TRACE_APPLY (this);
Behdad Esfahbodfb059082018-11-30 20:45:40 -05002305 unsigned int index = (this+coverageZ[0]).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002306 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04002307
Behdad Esfahbod0382b712018-11-02 12:23:26 -04002308 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002309 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002310 {match_coverage},
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04002311 this
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002312 };
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02002313 return_trace (context_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, lookup_context));
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002314 }
2315
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302316 bool subset (hb_subset_context_t *c) const
Behdad Esfahbod339d3602018-09-03 17:33:34 -07002317 {
2318 TRACE_SUBSET (this);
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002319 auto *out = c->serializer->start_embed (this);
2320 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
2321
2322 out->format = format;
2323 out->glyphCount = glyphCount;
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002324
Behdad Esfahbod26111a12020-06-28 02:59:47 -07002325 auto coverages = coverageZ.as_array (glyphCount);
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002326
Behdad Esfahbodad28f972021-03-31 12:49:14 -06002327 for (const Offset16To<Coverage>& offset : coverages)
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002328 {
Behdad Esfahbod6d941942021-02-19 17:08:10 -07002329 /* TODO(subset) This looks like should not be necessary to write this way. */
Behdad Esfahbod9b4b5842021-03-31 13:27:21 -06002330 auto *o = c->serializer->allocate_size<Offset16To<Coverage>> (Offset16To<Coverage>::static_size);
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002331 if (unlikely (!o)) return_trace (false);
2332 if (!o->serialize_subset (c, offset, this)) return_trace (false);
2333 }
2334
Qunxin Liu36ed56b2021-09-23 10:51:21 -07002335 const UnsizedArrayOf<LookupRecord>& lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>> (coverageZ.as_array (glyphCount));
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002336 const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
Garret Riegerf51b48c2021-11-02 16:16:52 -07002337
Ebrahim Byagowia79d0e42020-05-21 07:32:58 +04302338
Qunxin Liu36ed56b2021-09-23 10:51:21 -07002339 unsigned count = serialize_lookuprecord_array (c->serializer, lookupRecord.as_array (lookupCount), lookup_map);
2340 return_trace (c->serializer->check_assign (out->lookupCount, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
Behdad Esfahbod339d3602018-09-03 17:33:34 -07002341 }
2342
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302343 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002344 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002345 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002346 if (!c->check_struct (this)) return_trace (false);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002347 unsigned int count = glyphCount;
Behdad Esfahbodfb059082018-11-30 20:45:40 -05002348 if (!count) return_trace (false); /* We want to access coverageZ[0] freely. */
Behdad Esfahbod9507b052018-09-10 23:18:07 +02002349 if (!c->check_array (coverageZ.arrayZ, count)) return_trace (false);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002350 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002351 if (!coverageZ[i].sanitize (c, this)) return_trace (false);
Behdad Esfahbod0382b712018-11-02 12:23:26 -04002352 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
Behdad Esfahbod9507b052018-09-10 23:18:07 +02002353 return_trace (c->check_array (lookupRecord, lookupCount));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002354 }
2355
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002356 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002357 HBUINT16 format; /* Format identifier--format = 3 */
2358 HBUINT16 glyphCount; /* Number of glyphs in the input glyph
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002359 * sequence */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002360 HBUINT16 lookupCount; /* Number of LookupRecords */
Behdad Esfahbodad28f972021-03-31 12:49:14 -06002361 UnsizedArrayOf<Offset16To<Coverage>>
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02002362 coverageZ; /* Array of offsets to Coverage
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002363 * table in glyph sequence order */
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02002364/*UnsizedArrayOf<LookupRecord>
2365 lookupRecordX;*/ /* Array of LookupRecords--in
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002366 * design order */
Behdad Esfahbod569da922010-05-10 16:38:32 -04002367 public:
Behdad Esfahbod6d7c6e12018-02-07 14:09:56 -06002368 DEFINE_SIZE_ARRAY (6, coverageZ);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002369};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002370
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002371struct Context
2372{
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -07002373 template <typename context_t, typename ...Ts>
Behdad Esfahbod83e3eab2019-05-07 20:58:43 -07002374 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002375 {
Behdad Esfahbod00f6a8e2014-12-12 20:36:49 -08002376 TRACE_DISPATCH (this, u.format);
Behdad Esfahbodf396fbb2015-10-09 12:25:55 -04002377 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002378 switch (u.format) {
Behdad Esfahbod6d555ce2021-11-02 00:18:22 -06002379 case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
2380 case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
2381 case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002382 default:return_trace (c->default_return_value ());
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002383 }
2384 }
2385
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002386 protected:
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002387 union {
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002388 HBUINT16 format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -04002389 ContextFormat1 format1;
2390 ContextFormat2 format2;
2391 ContextFormat3 format3;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002392 } u;
2393};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002394
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002395
2396/* Chaining Contextual lookups */
2397
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002398struct ChainContextClosureLookupContext
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002399{
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002400 ContextClosureFuncs funcs;
Qunxin Liub8a58a02021-01-10 15:50:04 -08002401 ContextFormat context_format;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002402 const void *intersects_data[3];
2403};
2404
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002405struct ChainContextCollectGlyphsLookupContext
2406{
2407 ContextCollectGlyphsFuncs funcs;
2408 const void *collect_data[3];
2409};
2410
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002411struct ChainContextApplyLookupContext
2412{
2413 ContextApplyFuncs funcs;
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04002414 const void *match_data[3];
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04002415};
2416
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002417static inline bool chain_context_intersects (const hb_set_t *glyphs,
2418 unsigned int backtrackCount,
2419 const HBUINT16 backtrack[],
2420 unsigned int inputCount, /* Including the first glyph (not matched) */
2421 const HBUINT16 input[], /* Array of input values--start with second glyph */
2422 unsigned int lookaheadCount,
2423 const HBUINT16 lookahead[],
2424 ChainContextClosureLookupContext &lookup_context)
2425{
Qunxin Liu44d88cf2020-05-08 15:33:34 -07002426 return array_is_subset_of (glyphs,
2427 backtrackCount, backtrack,
2428 lookup_context.funcs.intersects, lookup_context.intersects_data[0])
2429 && array_is_subset_of (glyphs,
2430 inputCount ? inputCount - 1 : 0, input,
2431 lookup_context.funcs.intersects, lookup_context.intersects_data[1])
2432 && array_is_subset_of (glyphs,
2433 lookaheadCount, lookahead,
2434 lookup_context.funcs.intersects, lookup_context.intersects_data[2]);
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002435}
2436
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002437static inline void chain_context_closure_lookup (hb_closure_context_t *c,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002438 unsigned int backtrackCount,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002439 const HBUINT16 backtrack[],
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002440 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002441 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002442 unsigned int lookaheadCount,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002443 const HBUINT16 lookahead[],
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002444 unsigned int lookupCount,
2445 const LookupRecord lookupRecord[],
Qunxin Liub8a58a02021-01-10 15:50:04 -08002446 unsigned value,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002447 ChainContextClosureLookupContext &lookup_context)
2448{
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002449 if (chain_context_intersects (c->glyphs,
2450 backtrackCount, backtrack,
2451 inputCount, input,
2452 lookaheadCount, lookahead,
2453 lookup_context))
Qunxin Liub8a58a02021-01-10 15:50:04 -08002454 context_closure_recurse_lookups (c,
2455 inputCount, input,
2456 lookupCount, lookupRecord,
2457 value,
2458 lookup_context.context_format,
2459 lookup_context.intersects_data[1],
2460 lookup_context.funcs.intersected_glyphs);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002461}
2462
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002463static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03302464 unsigned int backtrackCount,
2465 const HBUINT16 backtrack[],
2466 unsigned int inputCount, /* Including the first glyph (not matched) */
2467 const HBUINT16 input[], /* Array of input values--start with second glyph */
2468 unsigned int lookaheadCount,
2469 const HBUINT16 lookahead[],
2470 unsigned int lookupCount,
2471 const LookupRecord lookupRecord[],
2472 ChainContextCollectGlyphsLookupContext &lookup_context)
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002473{
Behdad Esfahbod83035932012-12-04 17:08:41 -05002474 collect_array (c, c->before,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002475 backtrackCount, backtrack,
2476 lookup_context.funcs.collect, lookup_context.collect_data[0]);
Behdad Esfahbod83035932012-12-04 17:08:41 -05002477 collect_array (c, c->input,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002478 inputCount ? inputCount - 1 : 0, input,
2479 lookup_context.funcs.collect, lookup_context.collect_data[1]);
Behdad Esfahbod83035932012-12-04 17:08:41 -05002480 collect_array (c, c->after,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002481 lookaheadCount, lookahead,
2482 lookup_context.funcs.collect, lookup_context.collect_data[2]);
2483 recurse_lookups (c,
2484 lookupCount, lookupRecord);
2485}
2486
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002487static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c,
2488 unsigned int backtrackCount,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002489 const HBUINT16 backtrack[] HB_UNUSED,
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002490 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002491 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002492 unsigned int lookaheadCount,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002493 const HBUINT16 lookahead[] HB_UNUSED,
Behdad Esfahbod0beb66e2012-12-05 18:46:04 -05002494 unsigned int lookupCount HB_UNUSED,
2495 const LookupRecord lookupRecord[] HB_UNUSED,
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002496 ChainContextApplyLookupContext &lookup_context)
2497{
Behdad Esfahbodd9b204d2012-08-23 16:22:28 -04002498 return (c->zero_context ? !backtrackCount && !lookaheadCount : true)
Behdad Esfahbod1f2bb172012-08-23 16:10:37 -04002499 && would_match_input (c,
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002500 inputCount, input,
2501 lookup_context.funcs.match, lookup_context.match_data[1]);
2502}
2503
Behdad Esfahbodfd034492018-01-17 16:46:51 -08002504static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002505 unsigned int backtrackCount,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002506 const HBUINT16 backtrack[],
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002507 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002508 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002509 unsigned int lookaheadCount,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002510 const HBUINT16 lookahead[],
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002511 unsigned int lookupCount,
2512 const LookupRecord lookupRecord[],
2513 ChainContextApplyLookupContext &lookup_context)
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04002514{
Behdad Esfahbod60006d32022-01-20 15:29:28 -07002515 unsigned end_index = c->buffer->idx;
Behdad Esfahbod78481b32021-11-21 16:50:34 -07002516 unsigned match_end = 0;
2517 unsigned match_positions[HB_MAX_CONTEXT_LENGTH];
Behdad Esfahbod60006d32022-01-20 15:29:28 -07002518 if (!(match_input (c,
2519 inputCount, input,
2520 lookup_context.funcs.match, lookup_context.match_data[1],
2521 &match_end, match_positions) && (end_index = match_end)
2522 && match_lookahead (c,
2523 lookaheadCount, lookahead,
2524 lookup_context.funcs.match, lookup_context.match_data[2],
2525 match_end, &end_index)))
Behdad Esfahbod78481b32021-11-21 16:50:34 -07002526 {
Behdad Esfahbod60006d32022-01-20 15:29:28 -07002527 c->buffer->unsafe_to_concat (c->buffer->idx, end_index);
2528 return false;
Behdad Esfahbod78481b32021-11-21 16:50:34 -07002529 }
Behdad Esfahbod60006d32022-01-20 15:29:28 -07002530
2531 unsigned start_index = c->buffer->out_len;
2532 if (!match_backtrack (c,
2533 backtrackCount, backtrack,
2534 lookup_context.funcs.match, lookup_context.match_data[0],
2535 &start_index))
Behdad Esfahbod78481b32021-11-21 16:50:34 -07002536 {
2537 c->buffer->unsafe_to_concat_from_outbuffer (start_index, end_index);
2538 return false;
2539 }
Behdad Esfahbod60006d32022-01-20 15:29:28 -07002540
2541 c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index);
2542 apply_lookup (c,
2543 inputCount, match_positions,
2544 lookupCount, lookupRecord,
2545 match_end);
2546 return true;
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04002547}
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04002548
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002549struct ChainRule
2550{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302551 bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002552 {
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002553 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
Behdad Esfahbod5639e252021-03-31 16:04:43 -06002554 const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002555 return chain_context_intersects (glyphs,
2556 backtrack.len, backtrack.arrayZ,
Behdad Esfahbodeffc7ce2018-09-13 20:21:54 +02002557 input.lenP1, input.arrayZ,
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002558 lookahead.len, lookahead.arrayZ,
2559 lookup_context);
2560 }
2561
Qunxin Liub8a58a02021-01-10 15:50:04 -08002562 void closure (hb_closure_context_t *c, unsigned value,
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302563 ChainContextClosureLookupContext &lookup_context) const
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002564 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04302565 if (unlikely (c->lookup_limit_exceeded ())) return;
Garret Rieger4ad686b2020-03-25 23:32:28 -07002566
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002567 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
Behdad Esfahbod5639e252021-03-31 16:04:43 -06002568 const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
2569 const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002570 chain_context_closure_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002571 backtrack.len, backtrack.arrayZ,
Behdad Esfahbodeffc7ce2018-09-13 20:21:54 +02002572 input.lenP1, input.arrayZ,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002573 lookahead.len, lookahead.arrayZ,
2574 lookup.len, lookup.arrayZ,
Qunxin Liub8a58a02021-01-10 15:50:04 -08002575 value,
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002576 lookup_context);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002577 }
2578
Garret Riegerad241f92020-09-28 15:26:13 -07002579 void closure_lookups (hb_closure_lookups_context_t *c,
2580 ChainContextClosureLookupContext &lookup_context) const
Qunxin Liu0b39c482019-10-22 16:00:43 -07002581 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04302582 if (unlikely (c->lookup_limit_exceeded ())) return;
Garret Riegerad241f92020-09-28 15:26:13 -07002583 if (!intersects (c->glyphs, lookup_context)) return;
Garret Rieger4ad686b2020-03-25 23:32:28 -07002584
Qunxin Liu0b39c482019-10-22 16:00:43 -07002585 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
Behdad Esfahbod5639e252021-03-31 16:04:43 -06002586 const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
2587 const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
Qunxin Liu0b39c482019-10-22 16:00:43 -07002588 recurse_lookups (c, lookup.len, lookup.arrayZ);
2589 }
2590
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302591 void collect_glyphs (hb_collect_glyphs_context_t *c,
2592 ChainContextCollectGlyphsLookupContext &lookup_context) const
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002593 {
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002594 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
Behdad Esfahbod5639e252021-03-31 16:04:43 -06002595 const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
2596 const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002597 chain_context_collect_glyphs_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002598 backtrack.len, backtrack.arrayZ,
Behdad Esfahbodeffc7ce2018-09-13 20:21:54 +02002599 input.lenP1, input.arrayZ,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002600 lookahead.len, lookahead.arrayZ,
2601 lookup.len, lookup.arrayZ,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002602 lookup_context);
2603 }
2604
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302605 bool would_apply (hb_would_apply_context_t *c,
2606 ChainContextApplyLookupContext &lookup_context) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002607 {
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002608 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
Behdad Esfahbod5639e252021-03-31 16:04:43 -06002609 const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
2610 const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07002611 return chain_context_would_apply_lookup (c,
2612 backtrack.len, backtrack.arrayZ,
2613 input.lenP1, input.arrayZ,
2614 lookahead.len, lookahead.arrayZ, lookup.len,
2615 lookup.arrayZ, lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002616 }
2617
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302618 bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002619 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002620 TRACE_APPLY (this);
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002621 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
Behdad Esfahbod5639e252021-03-31 16:04:43 -06002622 const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
2623 const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002624 return_trace (chain_context_apply_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002625 backtrack.len, backtrack.arrayZ,
Behdad Esfahbodeffc7ce2018-09-13 20:21:54 +02002626 input.lenP1, input.arrayZ,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002627 lookahead.len, lookahead.arrayZ, lookup.len,
2628 lookup.arrayZ, lookup_context));
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002629 }
2630
Qunxin Liub66094a2019-09-30 16:19:18 -07002631 template<typename Iterator,
2632 hb_requires (hb_is_iterator (Iterator))>
2633 void serialize_array (hb_serialize_context_t *c,
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04302634 HBUINT16 len,
2635 Iterator it) const
Qunxin Liub66094a2019-09-30 16:19:18 -07002636 {
2637 c->copy (len);
2638 for (const auto g : it)
Behdad Esfahbod83b66bf2021-02-23 13:04:25 -07002639 c->copy ((HBUINT16) g);
Qunxin Liub66094a2019-09-30 16:19:18 -07002640 }
2641
Qunxin Liu36ed56b2021-09-23 10:51:21 -07002642 bool serialize (hb_serialize_context_t *c,
2643 const hb_map_t *lookup_map,
2644 const hb_map_t *backtrack_map,
2645 const hb_map_t *input_map = nullptr,
2646 const hb_map_t *lookahead_map = nullptr) const
Qunxin Liub66094a2019-09-30 16:19:18 -07002647 {
2648 TRACE_SERIALIZE (this);
2649 auto *out = c->start_embed (this);
Qunxin Liu36ed56b2021-09-23 10:51:21 -07002650 if (unlikely (!out)) return_trace (false);
Qunxin Liub66094a2019-09-30 16:19:18 -07002651
2652 const hb_map_t *mapping = backtrack_map;
2653 serialize_array (c, backtrack.len, + backtrack.iter ()
2654 | hb_map (mapping));
2655
2656 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
2657 if (input_map) mapping = input_map;
2658 serialize_array (c, input.lenP1, + input.iter ()
2659 | hb_map (mapping));
2660
Behdad Esfahbod5639e252021-03-31 16:04:43 -06002661 const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
Qunxin Liub66094a2019-09-30 16:19:18 -07002662 if (lookahead_map) mapping = lookahead_map;
2663 serialize_array (c, lookahead.len, + lookahead.iter ()
2664 | hb_map (mapping));
2665
Behdad Esfahbod5639e252021-03-31 16:04:43 -06002666 const Array16Of<LookupRecord> &lookupRecord = StructAfter<Array16Of<LookupRecord>> (lookahead);
Qunxin Liu593e58c2020-05-20 18:00:25 -07002667
Garret Rieger8f47dd52020-11-04 11:05:22 -08002668 HBUINT16* lookupCount = c->embed (&(lookupRecord.len));
Qunxin Liu36ed56b2021-09-23 10:51:21 -07002669 if (!lookupCount) return_trace (false);
Garret Rieger8f47dd52020-11-04 11:05:22 -08002670
Qunxin Liu36ed56b2021-09-23 10:51:21 -07002671 unsigned count = serialize_lookuprecord_array (c, lookupRecord.as_array (), lookup_map);
2672 return_trace (c->check_assign (*lookupCount, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
Qunxin Liub66094a2019-09-30 16:19:18 -07002673 }
2674
2675 bool subset (hb_subset_context_t *c,
Qunxin Liu593e58c2020-05-20 18:00:25 -07002676 const hb_map_t *lookup_map,
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04302677 const hb_map_t *backtrack_map = nullptr,
2678 const hb_map_t *input_map = nullptr,
2679 const hb_map_t *lookahead_map = nullptr) const
Qunxin Liub66094a2019-09-30 16:19:18 -07002680 {
2681 TRACE_SUBSET (this);
2682
Qunxin Liub2fcca62019-10-24 15:15:26 -07002683 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
Behdad Esfahbod5639e252021-03-31 16:04:43 -06002684 const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
Qunxin Liub2fcca62019-10-24 15:15:26 -07002685
Qunxin Liub66094a2019-09-30 16:19:18 -07002686 if (!backtrack_map)
2687 {
Garret Riegere5835052020-09-29 11:05:08 -07002688 const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
Qunxin Liub66094a2019-09-30 16:19:18 -07002689 if (!hb_all (backtrack, glyphset) ||
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04302690 !hb_all (input, glyphset) ||
2691 !hb_all (lookahead, glyphset))
2692 return_trace (false);
Qunxin Liub66094a2019-09-30 16:19:18 -07002693
Qunxin Liu36ed56b2021-09-23 10:51:21 -07002694 serialize (c->serializer, lookup_map, c->plan->glyph_map);
Qunxin Liub66094a2019-09-30 16:19:18 -07002695 }
2696 else
2697 {
2698 if (!hb_all (backtrack, backtrack_map) ||
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04302699 !hb_all (input, input_map) ||
2700 !hb_all (lookahead, lookahead_map))
2701 return_trace (false);
Ebrahim Byagowiaca63902019-10-22 00:06:46 +03302702
Qunxin Liu36ed56b2021-09-23 10:51:21 -07002703 serialize (c->serializer, lookup_map, backtrack_map, input_map, lookahead_map);
Qunxin Liub66094a2019-09-30 16:19:18 -07002704 }
2705
2706 return_trace (true);
2707 }
2708
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302709 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002710 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002711 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002712 if (!backtrack.sanitize (c)) return_trace (false);
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002713 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002714 if (!input.sanitize (c)) return_trace (false);
Behdad Esfahbod5639e252021-03-31 16:04:43 -06002715 const Array16Of<HBUINT16> &lookahead = StructAfter<Array16Of<HBUINT16>> (input);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002716 if (!lookahead.sanitize (c)) return_trace (false);
Behdad Esfahbod5639e252021-03-31 16:04:43 -06002717 const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002718 return_trace (lookup.sanitize (c));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002719 }
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002720
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002721 protected:
Behdad Esfahbod5639e252021-03-31 16:04:43 -06002722 Array16Of<HBUINT16>
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04002723 backtrack; /* Array of backtracking values
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002724 * (to be matched before the input
2725 * sequence) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002726 HeadlessArrayOf<HBUINT16>
Behdad Esfahbode8cbaaf2009-05-18 02:03:58 -04002727 inputX; /* Array of input values (start with
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002728 * second glyph) */
Behdad Esfahbod5639e252021-03-31 16:04:43 -06002729 Array16Of<HBUINT16>
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04002730 lookaheadX; /* Array of lookahead values's (to be
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04002731 * matched after the input sequence) */
Behdad Esfahbod5639e252021-03-31 16:04:43 -06002732 Array16Of<LookupRecord>
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04002733 lookupX; /* Array of LookupRecords--in
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002734 * design order) */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04002735 public:
Behdad Esfahbodbea34c72010-05-10 17:28:16 -04002736 DEFINE_SIZE_MIN (8);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002737};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002738
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002739struct ChainRuleSet
2740{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302741 bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002742 {
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002743 return
2744 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002745 | hb_map (hb_add (this))
2746 | hb_map ([&] (const ChainRule &_) { return _.intersects (glyphs, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002747 | hb_any
2748 ;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002749 }
Qunxin Liub8a58a02021-01-10 15:50:04 -08002750 void closure (hb_closure_context_t *c, unsigned value, ChainContextClosureLookupContext &lookup_context) const
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002751 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04302752 if (unlikely (c->lookup_limit_exceeded ())) return;
Garret Rieger4ad686b2020-03-25 23:32:28 -07002753
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002754 return
2755 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002756 | hb_map (hb_add (this))
Qunxin Liub8a58a02021-01-10 15:50:04 -08002757 | hb_apply ([&] (const ChainRule &_) { _.closure (c, value, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002758 ;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002759 }
2760
Garret Riegerad241f92020-09-28 15:26:13 -07002761 void closure_lookups (hb_closure_lookups_context_t *c,
2762 ChainContextClosureLookupContext &lookup_context) const
Qunxin Liu0b39c482019-10-22 16:00:43 -07002763 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04302764 if (unlikely (c->lookup_limit_exceeded ())) return;
Garret Rieger4ad686b2020-03-25 23:32:28 -07002765
Qunxin Liu0b39c482019-10-22 16:00:43 -07002766 + hb_iter (rule)
2767 | hb_map (hb_add (this))
Garret Riegere31c2692020-09-28 16:51:25 -07002768 | hb_apply ([&] (const ChainRule &_) { _.closure_lookups (c, lookup_context); })
Qunxin Liu0b39c482019-10-22 16:00:43 -07002769 ;
2770 }
2771
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302772 void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002773 {
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002774 return
2775 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002776 | hb_map (hb_add (this))
2777 | hb_apply ([&] (const ChainRule &_) { _.collect_glyphs (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002778 ;
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002779 }
2780
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302781 bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002782 {
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002783 return
2784 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002785 | hb_map (hb_add (this))
2786 | hb_map ([&] (const ChainRule &_) { return _.would_apply (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002787 | hb_any
2788 ;
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002789 }
2790
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302791 bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002792 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002793 TRACE_APPLY (this);
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002794 return_trace (
2795 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002796 | hb_map (hb_add (this))
2797 | hb_map ([&] (const ChainRule &_) { return _.apply (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002798 | hb_any
2799 )
2800 ;
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04002801 }
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002802
Qunxin Liub66094a2019-09-30 16:19:18 -07002803 bool subset (hb_subset_context_t *c,
Qunxin Liu593e58c2020-05-20 18:00:25 -07002804 const hb_map_t *lookup_map,
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04302805 const hb_map_t *backtrack_klass_map = nullptr,
2806 const hb_map_t *input_klass_map = nullptr,
2807 const hb_map_t *lookahead_klass_map = nullptr) const
Qunxin Liub66094a2019-09-30 16:19:18 -07002808 {
2809 TRACE_SUBSET (this);
2810
2811 auto snap = c->serializer->snapshot ();
2812 auto *out = c->serializer->start_embed (*this);
2813 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
2814
Behdad Esfahbodad28f972021-03-31 12:49:14 -06002815 for (const Offset16To<ChainRule>& _ : rule)
Qunxin Liub66094a2019-09-30 16:19:18 -07002816 {
2817 if (!_) continue;
Garret Riegerc2cc5662021-09-22 14:15:55 -07002818 auto o_snap = c->serializer->snapshot ();
Qunxin Liub66094a2019-09-30 16:19:18 -07002819 auto *o = out->rule.serialize_append (c->serializer);
2820 if (unlikely (!o)) continue;
Ebrahim Byagowiaca63902019-10-22 00:06:46 +03302821
ariza188a0a42020-03-07 11:02:36 -08002822 if (!o->serialize_subset (c, _, this,
Qunxin Liu593e58c2020-05-20 18:00:25 -07002823 lookup_map,
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04302824 backtrack_klass_map,
2825 input_klass_map,
2826 lookahead_klass_map))
Qunxin Liub66094a2019-09-30 16:19:18 -07002827 {
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04302828 out->rule.pop ();
2829 c->serializer->revert (o_snap);
Qunxin Liub66094a2019-09-30 16:19:18 -07002830 }
2831 }
2832
2833 bool ret = bool (out->rule);
2834 if (!ret) c->serializer->revert (snap);
Ebrahim Byagowiaca63902019-10-22 00:06:46 +03302835
Qunxin Liub66094a2019-09-30 16:19:18 -07002836 return_trace (ret);
2837 }
2838
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302839 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002840 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002841 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002842 return_trace (rule.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002843 }
2844
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002845 protected:
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06002846 Array16OfOffset16To<ChainRule>
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04002847 rule; /* Array of ChainRule tables
2848 * ordered by preference */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04002849 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04002850 DEFINE_SIZE_ARRAY (2, rule);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002851};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002852
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002853struct ChainContextFormat1
2854{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302855 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002856 {
2857 struct ChainContextClosureLookupContext lookup_context = {
Qunxin Liub8a58a02021-01-10 15:50:04 -08002858 {intersects_glyph, intersected_glyph},
2859 ContextFormat::SimpleContext,
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002860 {nullptr, nullptr, nullptr}
2861 };
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002862
2863 return
2864 + hb_zip (this+coverage, ruleSet)
2865 | hb_filter (*glyphs, hb_first)
2866 | hb_map (hb_second)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002867 | hb_map (hb_add (this))
2868 | hb_map ([&] (const ChainRuleSet &_) { return _.intersects (glyphs, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002869 | hb_any
2870 ;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002871 }
2872
Qunxin Liub4fc5932020-12-09 10:44:18 -08002873 bool may_have_non_1to1 () const
2874 { return true; }
2875
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302876 void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002877 {
Garret Rieger4e2f4092022-01-31 12:20:32 -08002878 hb_set_t* cur_active_glyphs = &c->push_cur_active_glyphs ();
2879 get_coverage ().intersected_coverage_glyphs (&c->previous_parent_active_glyphs (),
2880 cur_active_glyphs);
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08002881
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002882 struct ChainContextClosureLookupContext lookup_context = {
Qunxin Liub8a58a02021-01-10 15:50:04 -08002883 {intersects_glyph, intersected_glyph},
2884 ContextFormat::SimpleContext,
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02002885 {nullptr, nullptr, nullptr}
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002886 };
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002887
Qunxin Liub8a58a02021-01-10 15:50:04 -08002888 + hb_zip (this+coverage, hb_range ((unsigned) ruleSet.len))
Garret Rieger4e2f4092022-01-31 12:20:32 -08002889 | hb_filter ([&] (hb_codepoint_t _) {
2890 return c->previous_parent_active_glyphs ().has (_);
2891 }, hb_first)
Qunxin Liub8a58a02021-01-10 15:50:04 -08002892 | hb_map ([&](const hb_pair_t<hb_codepoint_t, unsigned> _) { return hb_pair_t<unsigned, const ChainRuleSet&> (_.first, this+ruleSet[_.second]); })
2893 | hb_apply ([&] (const hb_pair_t<unsigned, const ChainRuleSet&>& _) { _.second.closure (c, _.first, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002894 ;
Garret Riegerbc899652022-01-28 13:54:10 -08002895
2896 c->pop_cur_done_glyphs ();
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 {
Garret Riegerad241f92020-09-28 15:26:13 -07002901 struct ChainContextClosureLookupContext lookup_context = {
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08002902 {intersects_glyph, intersected_glyph},
2903 ContextFormat::SimpleContext,
Garret Riegerad241f92020-09-28 15:26:13 -07002904 {nullptr, nullptr, nullptr}
2905 };
2906
2907 + hb_zip (this+coverage, ruleSet)
2908 | hb_filter (*c->glyphs, hb_first)
2909 | hb_map (hb_second)
Qunxin Liu0b39c482019-10-22 16:00:43 -07002910 | hb_map (hb_add (this))
Garret Riegere31c2692020-09-28 16:51:25 -07002911 | hb_apply ([&] (const ChainRuleSet &_) { _.closure_lookups (c, lookup_context); })
Qunxin Liu0b39c482019-10-22 16:00:43 -07002912 ;
2913 }
2914
Qunxin Liu8200e482020-02-26 13:11:42 -08002915 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
2916
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302917 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002918 {
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07002919 (this+coverage).collect_coverage (c->input);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002920
2921 struct ChainContextCollectGlyphsLookupContext lookup_context = {
2922 {collect_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02002923 {nullptr, nullptr, nullptr}
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002924 };
2925
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002926 + hb_iter (ruleSet)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002927 | hb_map (hb_add (this))
2928 | hb_apply ([&] (const ChainRuleSet &_) { _.collect_glyphs (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002929 ;
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002930 }
2931
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302932 bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002933 {
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05002934 const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002935 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002936 {match_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02002937 {nullptr, nullptr, nullptr}
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002938 };
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07002939 return rule_set.would_apply (c, lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002940 }
2941
Ebrahim Byagowie4120082018-12-17 21:31:01 +03302942 const Coverage &get_coverage () const { return this+coverage; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002943
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302944 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002945 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002946 TRACE_APPLY (this);
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05002947 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002948 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002949
2950 const ChainRuleSet &rule_set = this+ruleSet[index];
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002951 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002952 {match_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02002953 {nullptr, nullptr, nullptr}
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002954 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002955 return_trace (rule_set.apply (c, lookup_context));
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002956 }
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002957
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302958 bool subset (hb_subset_context_t *c) const
Behdad Esfahbod339d3602018-09-03 17:33:34 -07002959 {
2960 TRACE_SUBSET (this);
Garret Riegere5835052020-09-29 11:05:08 -07002961 const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
Qunxin Liub66094a2019-09-30 16:19:18 -07002962 const hb_map_t &glyph_map = *c->plan->glyph_map;
2963
2964 auto *out = c->serializer->start_embed (*this);
2965 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
2966 out->format = format;
2967
Qunxin Liu593e58c2020-05-20 18:00:25 -07002968 const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
Qunxin Liub66094a2019-09-30 16:19:18 -07002969 hb_sorted_vector_t<hb_codepoint_t> new_coverage;
2970 + hb_zip (this+coverage, ruleSet)
2971 | hb_filter (glyphset, hb_first)
Qunxin Liu593e58c2020-05-20 18:00:25 -07002972 | hb_filter (subset_offset_array (c, out->ruleSet, this, lookup_map), hb_second)
Qunxin Liub66094a2019-09-30 16:19:18 -07002973 | hb_map (hb_first)
2974 | hb_map (glyph_map)
2975 | hb_sink (new_coverage)
2976 ;
2977
Garret Rieger085aa652021-06-14 16:47:45 -07002978 out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
Qunxin Liub66094a2019-09-30 16:19:18 -07002979 return_trace (bool (new_coverage));
Behdad Esfahbod339d3602018-09-03 17:33:34 -07002980 }
2981
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302982 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002983 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002984 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002985 return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002986 }
2987
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002988 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002989 HBUINT16 format; /* Format identifier--format = 1 */
Behdad Esfahbodad28f972021-03-31 12:49:14 -06002990 Offset16To<Coverage>
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04002991 coverage; /* Offset to Coverage table--from
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002992 * beginning of table */
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06002993 Array16OfOffset16To<ChainRuleSet>
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002994 ruleSet; /* Array of ChainRuleSet tables
2995 * ordered by Coverage Index */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04002996 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04002997 DEFINE_SIZE_ARRAY (6, ruleSet);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002998};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002999
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04003000struct ChainContextFormat2
3001{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303002 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07003003 {
3004 if (!(this+coverage).intersects (glyphs))
3005 return false;
3006
3007 const ClassDef &backtrack_class_def = this+backtrackClassDef;
3008 const ClassDef &input_class_def = this+inputClassDef;
3009 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
3010
3011 struct ChainContextClosureLookupContext lookup_context = {
Qunxin Liub8a58a02021-01-10 15:50:04 -08003012 {intersects_class, intersected_class_glyphs},
3013 ContextFormat::ClassBasedContext,
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07003014 {&backtrack_class_def,
3015 &input_class_def,
3016 &lookahead_class_def}
3017 };
3018
Qunxin Liu540f19b2021-10-29 17:11:53 -07003019 hb_set_t retained_coverage_glyphs;
3020 (this+coverage).intersected_coverage_glyphs (glyphs, &retained_coverage_glyphs);
3021
3022 hb_set_t coverage_glyph_classes;
3023 input_class_def.intersected_classes (&retained_coverage_glyphs, &coverage_glyph_classes);
3024
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07003025 return
Behdad Esfahbod26111a12020-06-28 02:59:47 -07003026 + hb_iter (ruleSet)
3027 | hb_map (hb_add (this))
3028 | hb_enumerate
3029 | hb_map ([&] (const hb_pair_t<unsigned, const ChainRuleSet &> p)
Behdad Esfahbod78d35f02019-05-15 18:15:05 -07003030 { return input_class_def.intersects_class (glyphs, p.first) &&
Qunxin Liu540f19b2021-10-29 17:11:53 -07003031 coverage_glyph_classes.has (p.first) &&
Behdad Esfahbod26111a12020-06-28 02:59:47 -07003032 p.second.intersects (glyphs, lookup_context); })
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07003033 | hb_any
3034 ;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07003035 }
Qunxin Liub4fc5932020-12-09 10:44:18 -08003036
3037 bool may_have_non_1to1 () const
3038 { return true; }
3039
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303040 void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04003041 {
Behdad Esfahbod31081f72012-04-23 16:54:58 -04003042 if (!(this+coverage).intersects (c->glyphs))
Behdad Esfahbod5caece62012-04-23 23:03:12 -04003043 return;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04003044
Garret Rieger4e2f4092022-01-31 12:20:32 -08003045 hb_set_t* cur_active_glyphs = &c->push_cur_active_glyphs ();
3046 get_coverage ().intersected_coverage_glyphs (&c->previous_parent_active_glyphs (),
3047 cur_active_glyphs);
3048
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08003049
Behdad Esfahbod31081f72012-04-23 16:54:58 -04003050 const ClassDef &backtrack_class_def = this+backtrackClassDef;
3051 const ClassDef &input_class_def = this+inputClassDef;
3052 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
3053
3054 struct ChainContextClosureLookupContext lookup_context = {
Qunxin Liub8a58a02021-01-10 15:50:04 -08003055 {intersects_class, intersected_class_glyphs},
3056 ContextFormat::ClassBasedContext,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04003057 {&backtrack_class_def,
3058 &input_class_def,
3059 &lookahead_class_def}
3060 };
3061
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07003062 + hb_enumerate (ruleSet)
Behdad Esfahbod78d35f02019-05-15 18:15:05 -07003063 | hb_filter ([&] (unsigned _)
Garret Riegerbc899652022-01-28 13:54:10 -08003064 { return input_class_def.intersects_class (&c->parent_active_glyphs (), _); },
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07003065 hb_first)
Behdad Esfahbodad28f972021-03-31 12:49:14 -06003066 | hb_apply ([&] (const hb_pair_t<unsigned, const Offset16To<ChainRuleSet>&> _)
Qunxin Liub8a58a02021-01-10 15:50:04 -08003067 {
3068 const ChainRuleSet& chainrule_set = this+_.second;
3069 chainrule_set.closure (c, _.first, lookup_context);
3070 })
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07003071 ;
Garret Riegerbc899652022-01-28 13:54:10 -08003072
3073 c->pop_cur_done_glyphs ();
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04003074 }
3075
Qunxin Liu0b39c482019-10-22 16:00:43 -07003076 void closure_lookups (hb_closure_lookups_context_t *c) const
3077 {
Garret Riegerad241f92020-09-28 15:26:13 -07003078 if (!(this+coverage).intersects (c->glyphs))
3079 return;
3080
3081 const ClassDef &backtrack_class_def = this+backtrackClassDef;
3082 const ClassDef &input_class_def = this+inputClassDef;
3083 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
3084
3085 struct ChainContextClosureLookupContext lookup_context = {
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08003086 {intersects_class, intersected_class_glyphs},
3087 ContextFormat::ClassBasedContext,
Garret Riegerad241f92020-09-28 15:26:13 -07003088 {&backtrack_class_def,
3089 &input_class_def,
3090 &lookahead_class_def}
3091 };
3092
Qunxin Liu0b39c482019-10-22 16:00:43 -07003093 + hb_iter (ruleSet)
3094 | hb_map (hb_add (this))
Garret Riegerad241f92020-09-28 15:26:13 -07003095 | hb_enumerate
Behdad Esfahbod6e1afac2021-02-09 18:48:46 -07003096 | hb_filter([&] (unsigned klass)
3097 { return input_class_def.intersects_class (c->glyphs, klass); }, hb_first)
Garret Riegerad241f92020-09-28 15:26:13 -07003098 | hb_map (hb_second)
3099 | hb_apply ([&] (const ChainRuleSet &_)
3100 { _.closure_lookups (c, lookup_context); })
Qunxin Liu0b39c482019-10-22 16:00:43 -07003101 ;
3102 }
3103
Qunxin Liu8200e482020-02-26 13:11:42 -08003104 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
3105
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303106 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbod26514d52012-11-23 18:13:48 -05003107 {
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07003108 (this+coverage).collect_coverage (c->input);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05003109
Behdad Esfahbod11fba792013-01-02 23:36:37 -06003110 const ClassDef &backtrack_class_def = this+backtrackClassDef;
3111 const ClassDef &input_class_def = this+inputClassDef;
3112 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
3113
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05003114 struct ChainContextCollectGlyphsLookupContext lookup_context = {
3115 {collect_class},
Behdad Esfahbod11fba792013-01-02 23:36:37 -06003116 {&backtrack_class_def,
3117 &input_class_def,
3118 &lookahead_class_def}
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05003119 };
3120
Behdad Esfahbod05f21302019-03-29 22:40:13 -07003121 + hb_iter (ruleSet)
Behdad Esfahbod23768672019-05-15 21:57:26 -07003122 | hb_map (hb_add (this))
3123 | hb_apply ([&] (const ChainRuleSet &_) { _.collect_glyphs (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07003124 ;
Behdad Esfahbod26514d52012-11-23 18:13:48 -05003125 }
3126
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303127 bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003128 {
Behdad Esfahbod11fba792013-01-02 23:36:37 -06003129 const ClassDef &backtrack_class_def = this+backtrackClassDef;
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003130 const ClassDef &input_class_def = this+inputClassDef;
Behdad Esfahbod11fba792013-01-02 23:36:37 -06003131 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003132
Behdad Esfahbod2dc11412012-11-24 19:16:34 -05003133 unsigned int index = input_class_def.get_class (c->glyphs[0]);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003134 const ChainRuleSet &rule_set = this+ruleSet[index];
3135 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05003136 {match_class},
Behdad Esfahbod11fba792013-01-02 23:36:37 -06003137 {&backtrack_class_def,
3138 &input_class_def,
3139 &lookahead_class_def}
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003140 };
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07003141 return rule_set.would_apply (c, lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003142 }
3143
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303144 const Coverage &get_coverage () const { return this+coverage; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05003145
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303146 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04003147 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05003148 TRACE_APPLY (this);
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05003149 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003150 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04003151
3152 const ClassDef &backtrack_class_def = this+backtrackClassDef;
3153 const ClassDef &input_class_def = this+inputClassDef;
3154 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
3155
Behdad Esfahbod2dc11412012-11-24 19:16:34 -05003156 index = input_class_def.get_class (c->buffer->cur().codepoint);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04003157 const ChainRuleSet &rule_set = this+ruleSet[index];
Behdad Esfahbod31081f72012-04-23 16:54:58 -04003158 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05003159 {match_class},
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04003160 {&backtrack_class_def,
3161 &input_class_def,
3162 &lookahead_class_def}
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04003163 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003164 return_trace (rule_set.apply (c, lookup_context));
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003165 }
3166
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303167 bool subset (hb_subset_context_t *c) const
Behdad Esfahbod339d3602018-09-03 17:33:34 -07003168 {
3169 TRACE_SUBSET (this);
Qunxin Liub66094a2019-09-30 16:19:18 -07003170 auto *out = c->serializer->start_embed (*this);
3171 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
3172 out->format = format;
ariza188a0a42020-03-07 11:02:36 -08003173 out->coverage.serialize_subset (c, coverage, this);
Qunxin Liub66094a2019-09-30 16:19:18 -07003174
3175 hb_map_t backtrack_klass_map;
Qunxin Liub66094a2019-09-30 16:19:18 -07003176 hb_map_t input_klass_map;
Qunxin Liub66094a2019-09-30 16:19:18 -07003177 hb_map_t lookahead_klass_map;
Behdad Esfahboddfa9d7a2021-02-11 11:08:52 -07003178
3179 out->backtrackClassDef.serialize_subset (c, backtrackClassDef, this, &backtrack_klass_map);
3180 // TODO: subset inputClassDef based on glyphs survived in Coverage subsetting
3181 out->inputClassDef.serialize_subset (c, inputClassDef, this, &input_klass_map);
ariza188a0a42020-03-07 11:02:36 -08003182 out->lookaheadClassDef.serialize_subset (c, lookaheadClassDef, this, &lookahead_klass_map);
Behdad Esfahboddfa9d7a2021-02-11 11:08:52 -07003183
3184 if (unlikely (!c->serializer->propagate_error (backtrack_klass_map,
3185 input_klass_map,
3186 lookahead_klass_map)))
Garret Rieger06dbb6a2020-07-31 15:56:14 -07003187 return_trace (false);
Qunxin Liub66094a2019-09-30 16:19:18 -07003188
Qunxin Liu540f19b2021-10-29 17:11:53 -07003189 const hb_set_t* glyphset = c->plan->glyphset_gsub ();
3190 hb_set_t retained_coverage_glyphs;
3191 (this+coverage).intersected_coverage_glyphs (glyphset, &retained_coverage_glyphs);
3192
3193 hb_set_t coverage_glyph_classes;
3194 (this+inputClassDef).intersected_classes (&retained_coverage_glyphs, &coverage_glyph_classes);
3195
Garret Riegerdc375552020-09-25 13:08:46 -07003196 int non_zero_index = -1, index = 0;
Qunxin Liub66094a2019-09-30 16:19:18 -07003197 bool ret = true;
Qunxin Liu593e58c2020-05-20 18:00:25 -07003198 const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
Garret Riegerdc375552020-09-25 13:08:46 -07003199 auto last_non_zero = c->serializer->snapshot ();
Qunxin Liu540f19b2021-10-29 17:11:53 -07003200 for (const auto& _ : + hb_enumerate (ruleSet)
3201 | hb_filter (input_klass_map, hb_first))
Qunxin Liub66094a2019-09-30 16:19:18 -07003202 {
3203 auto *o = out->ruleSet.serialize_append (c->serializer);
3204 if (unlikely (!o))
3205 {
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04303206 ret = false;
3207 break;
Qunxin Liub66094a2019-09-30 16:19:18 -07003208 }
Qunxin Liu540f19b2021-10-29 17:11:53 -07003209 if (coverage_glyph_classes.has (_.first) &&
3210 o->serialize_subset (c, _.second, this,
Qunxin Liu593e58c2020-05-20 18:00:25 -07003211 lookup_map,
3212 &backtrack_klass_map,
3213 &input_klass_map,
3214 &lookahead_klass_map))
Garret Riegerdc375552020-09-25 13:08:46 -07003215 {
3216 last_non_zero = c->serializer->snapshot ();
Ebrahim Byagowi5a7cc7f2020-07-29 08:33:32 +04303217 non_zero_index = index;
Garret Riegerdc375552020-09-25 13:08:46 -07003218 }
Qunxin Liu593e58c2020-05-20 18:00:25 -07003219
3220 index++;
Qunxin Liub66094a2019-09-30 16:19:18 -07003221 }
3222
Qunxin Liu540f19b2021-10-29 17:11:53 -07003223 if (!ret || non_zero_index == -1) return_trace (false);
Qunxin Liub66094a2019-09-30 16:19:18 -07003224
Garret Riegerdc375552020-09-25 13:08:46 -07003225 // prune empty trailing ruleSets
3226 if (index > non_zero_index) {
3227 c->serializer->revert (last_non_zero);
3228 out->ruleSet.len = non_zero_index + 1;
Qunxin Liub66094a2019-09-30 16:19:18 -07003229 }
3230
3231 return_trace (bool (out->ruleSet));
Behdad Esfahbod339d3602018-09-03 17:33:34 -07003232 }
3233
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303234 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03003235 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05003236 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003237 return_trace (coverage.sanitize (c, this) &&
3238 backtrackClassDef.sanitize (c, this) &&
3239 inputClassDef.sanitize (c, this) &&
3240 lookaheadClassDef.sanitize (c, this) &&
3241 ruleSet.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04003242 }
3243
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04003244 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01003245 HBUINT16 format; /* Format identifier--format = 2 */
Behdad Esfahbodad28f972021-03-31 12:49:14 -06003246 Offset16To<Coverage>
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04003247 coverage; /* Offset to Coverage table--from
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003248 * beginning of table */
Behdad Esfahbodad28f972021-03-31 12:49:14 -06003249 Offset16To<ClassDef>
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04003250 backtrackClassDef; /* Offset to glyph ClassDef table
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003251 * containing backtrack sequence
3252 * data--from beginning of table */
Behdad Esfahbodad28f972021-03-31 12:49:14 -06003253 Offset16To<ClassDef>
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04003254 inputClassDef; /* Offset to glyph ClassDef
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003255 * table containing input sequence
3256 * data--from beginning of table */
Behdad Esfahbodad28f972021-03-31 12:49:14 -06003257 Offset16To<ClassDef>
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04003258 lookaheadClassDef; /* Offset to glyph ClassDef table
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003259 * containing lookahead sequence
3260 * data--from beginning of table */
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06003261 Array16OfOffset16To<ChainRuleSet>
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04003262 ruleSet; /* Array of ChainRuleSet tables
3263 * ordered by class */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04003264 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04003265 DEFINE_SIZE_ARRAY (12, ruleSet);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003266};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003267
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04003268struct ChainContextFormat3
3269{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303270 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07003271 {
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06003272 const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07003273
3274 if (!(this+input[0]).intersects (glyphs))
3275 return false;
3276
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06003277 const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07003278 struct ChainContextClosureLookupContext lookup_context = {
Qunxin Liub8a58a02021-01-10 15:50:04 -08003279 {intersects_coverage, intersected_coverage_glyphs},
3280 ContextFormat::CoverageBasedContext,
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07003281 {this, this, this}
3282 };
3283 return chain_context_intersects (glyphs,
3284 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
3285 input.len, (const HBUINT16 *) input.arrayZ + 1,
3286 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
3287 lookup_context);
3288 }
3289
Qunxin Liub4fc5932020-12-09 10:44:18 -08003290 bool may_have_non_1to1 () const
3291 { return true; }
3292
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303293 void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04003294 {
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06003295 const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
Behdad Esfahbod5caece62012-04-23 23:03:12 -04003296
3297 if (!(this+input[0]).intersects (c->glyphs))
3298 return;
3299
Garret Rieger4e2f4092022-01-31 12:20:32 -08003300 hb_set_t* cur_active_glyphs = &c->push_cur_active_glyphs ();
3301 get_coverage ().intersected_coverage_glyphs (&c->previous_parent_active_glyphs (),
3302 cur_active_glyphs);
3303
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08003304
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06003305 const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
Behdad Esfahbod5639e252021-03-31 16:04:43 -06003306 const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
Behdad Esfahbod5caece62012-04-23 23:03:12 -04003307 struct ChainContextClosureLookupContext lookup_context = {
Qunxin Liub8a58a02021-01-10 15:50:04 -08003308 {intersects_coverage, intersected_coverage_glyphs},
3309 ContextFormat::CoverageBasedContext,
Behdad Esfahbod5caece62012-04-23 23:03:12 -04003310 {this, this, this}
3311 };
3312 chain_context_closure_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07003313 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
3314 input.len, (const HBUINT16 *) input.arrayZ + 1,
3315 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
3316 lookup.len, lookup.arrayZ,
Qunxin Liub8a58a02021-01-10 15:50:04 -08003317 0, lookup_context);
Garret Riegerbc899652022-01-28 13:54:10 -08003318
3319 c->pop_cur_done_glyphs ();
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04003320 }
3321
Qunxin Liu0b39c482019-10-22 16:00:43 -07003322 void closure_lookups (hb_closure_lookups_context_t *c) const
3323 {
Garret Riegera5c0ec72020-09-25 14:57:20 -07003324 if (!intersects (c->glyphs))
3325 return;
3326
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06003327 const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
3328 const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
Behdad Esfahbod5639e252021-03-31 16:04:43 -06003329 const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
Qunxin Liu0b39c482019-10-22 16:00:43 -07003330 recurse_lookups (c, lookup.len, lookup.arrayZ);
3331 }
3332
Qunxin Liu8200e482020-02-26 13:11:42 -08003333 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
3334
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303335 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbod26514d52012-11-23 18:13:48 -05003336 {
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06003337 const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05003338
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07003339 (this+input[0]).collect_coverage (c->input);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05003340
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06003341 const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
Behdad Esfahbod5639e252021-03-31 16:04:43 -06003342 const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05003343 struct ChainContextCollectGlyphsLookupContext lookup_context = {
3344 {collect_coverage},
3345 {this, this, this}
3346 };
3347 chain_context_collect_glyphs_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07003348 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
3349 input.len, (const HBUINT16 *) input.arrayZ + 1,
3350 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
3351 lookup.len, lookup.arrayZ,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05003352 lookup_context);
Behdad Esfahbod26514d52012-11-23 18:13:48 -05003353 }
3354
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303355 bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003356 {
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06003357 const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
3358 const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
Behdad Esfahbod5639e252021-03-31 16:04:43 -06003359 const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003360 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05003361 {match_coverage},
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003362 {this, this, this}
3363 };
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07003364 return chain_context_would_apply_lookup (c,
3365 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
3366 input.len, (const HBUINT16 *) input.arrayZ + 1,
3367 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
3368 lookup.len, lookup.arrayZ, lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003369 }
3370
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303371 const Coverage &get_coverage () const
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05003372 {
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06003373 const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05003374 return this+input[0];
3375 }
3376
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303377 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04003378 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05003379 TRACE_APPLY (this);
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06003380 const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04003381
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05003382 unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003383 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003384
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06003385 const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
Behdad Esfahbod5639e252021-03-31 16:04:43 -06003386 const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04003387 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05003388 {match_coverage},
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04003389 {this, this, this}
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04003390 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003391 return_trace (chain_context_apply_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07003392 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
3393 input.len, (const HBUINT16 *) input.arrayZ + 1,
3394 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
3395 lookup.len, lookup.arrayZ, lookup_context));
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003396 }
3397
Qunxin Liub66094a2019-09-30 16:19:18 -07003398 template<typename Iterator,
3399 hb_requires (hb_is_iterator (Iterator))>
Ebrahim Byagowi07acd1a2020-03-08 23:39:24 +03303400 bool serialize_coverage_offsets (hb_subset_context_t *c, Iterator it, const void* base) const
Qunxin Liub66094a2019-09-30 16:19:18 -07003401 {
3402 TRACE_SERIALIZE (this);
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06003403 auto *out = c->serializer->start_embed<Array16OfOffset16To<Coverage>> ();
Qunxin Liub66094a2019-09-30 16:19:18 -07003404
Garret Rieger90eb1a42020-09-25 12:36:32 -07003405 if (unlikely (!c->serializer->allocate_size<HBUINT16> (HBUINT16::static_size)))
Garret Rieger940e1c62020-09-28 17:22:01 -07003406 return_trace (false);
Qunxin Liub66094a2019-09-30 16:19:18 -07003407
Garret Rieger940e1c62020-09-28 17:22:01 -07003408 for (auto& offset : it) {
3409 auto *o = out->serialize_append (c->serializer);
3410 if (unlikely (!o) || !o->serialize_subset (c, offset, base))
3411 return_trace (false);
3412 }
Qunxin Liub66094a2019-09-30 16:19:18 -07003413
Garret Rieger940e1c62020-09-28 17:22:01 -07003414 return_trace (true);
Qunxin Liub66094a2019-09-30 16:19:18 -07003415 }
3416
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303417 bool subset (hb_subset_context_t *c) const
Behdad Esfahbod339d3602018-09-03 17:33:34 -07003418 {
3419 TRACE_SUBSET (this);
Qunxin Liub66094a2019-09-30 16:19:18 -07003420
3421 auto *out = c->serializer->start_embed (this);
3422 if (unlikely (!out)) return_trace (false);
3423 if (unlikely (!c->serializer->embed (this->format))) return_trace (false);
3424
ariza188a0a42020-03-07 11:02:36 -08003425 if (!serialize_coverage_offsets (c, backtrack.iter (), this))
Qunxin Liub66094a2019-09-30 16:19:18 -07003426 return_trace (false);
Ebrahim Byagowiaca63902019-10-22 00:06:46 +03303427
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06003428 const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
ariza188a0a42020-03-07 11:02:36 -08003429 if (!serialize_coverage_offsets (c, input.iter (), this))
Qunxin Liub66094a2019-09-30 16:19:18 -07003430 return_trace (false);
3431
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06003432 const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
ariza188a0a42020-03-07 11:02:36 -08003433 if (!serialize_coverage_offsets (c, lookahead.iter (), this))
Qunxin Liub66094a2019-09-30 16:19:18 -07003434 return_trace (false);
Ebrahim Byagowiaca63902019-10-22 00:06:46 +03303435
Behdad Esfahbod5639e252021-03-31 16:04:43 -06003436 const Array16Of<LookupRecord> &lookupRecord = StructAfter<Array16Of<LookupRecord>> (lookahead);
Qunxin Liu37379f82021-09-02 11:54:37 -07003437 const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
Garret Riegerf51b48c2021-11-02 16:16:52 -07003438
Qunxin Liu36ed56b2021-09-23 10:51:21 -07003439 HBUINT16 *lookupCount = c->serializer->copy<HBUINT16> (lookupRecord.len);
3440 if (!lookupCount) return_trace (false);
Qunxin Liu37379f82021-09-02 11:54:37 -07003441
Qunxin Liu36ed56b2021-09-23 10:51:21 -07003442 unsigned count = serialize_lookuprecord_array (c->serializer, lookupRecord.as_array (), lookup_map);
3443 return_trace (c->serializer->check_assign (*lookupCount, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
Behdad Esfahbod339d3602018-09-03 17:33:34 -07003444 }
3445
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303446 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03003447 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05003448 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003449 if (!backtrack.sanitize (c, this)) return_trace (false);
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06003450 const Array16OfOffset16To<Coverage> &input = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003451 if (!input.sanitize (c, this)) return_trace (false);
3452 if (!input.len) return_trace (false); /* To be consistent with Context. */
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06003453 const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003454 if (!lookahead.sanitize (c, this)) return_trace (false);
Behdad Esfahbod5639e252021-03-31 16:04:43 -06003455 const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003456 return_trace (lookup.sanitize (c));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04003457 }
3458
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04003459 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01003460 HBUINT16 format; /* Format identifier--format = 3 */
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06003461 Array16OfOffset16To<Coverage>
Behdad Esfahbod13ed4402009-05-18 02:14:37 -04003462 backtrack; /* Array of coverage tables
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003463 * in backtracking sequence, in glyph
3464 * sequence order */
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06003465 Array16OfOffset16To<Coverage>
Behdad Esfahbod13ed4402009-05-18 02:14:37 -04003466 inputX ; /* Array of coverage
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003467 * tables in input sequence, in glyph
3468 * sequence order */
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06003469 Array16OfOffset16To<Coverage>
Behdad Esfahbod13ed4402009-05-18 02:14:37 -04003470 lookaheadX; /* Array of coverage tables
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003471 * in lookahead sequence, in glyph
3472 * sequence order */
Behdad Esfahbod5639e252021-03-31 16:04:43 -06003473 Array16Of<LookupRecord>
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04003474 lookupX; /* Array of LookupRecords--in
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04003475 * design order) */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04003476 public:
Behdad Esfahbodbea34c72010-05-10 17:28:16 -04003477 DEFINE_SIZE_MIN (10);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003478};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003479
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04003480struct ChainContext
3481{
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -07003482 template <typename context_t, typename ...Ts>
Behdad Esfahbod83e3eab2019-05-07 20:58:43 -07003483 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04003484 {
Behdad Esfahbod00f6a8e2014-12-12 20:36:49 -08003485 TRACE_DISPATCH (this, u.format);
Behdad Esfahbodf396fbb2015-10-09 12:25:55 -04003486 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04003487 switch (u.format) {
Behdad Esfahbod6d555ce2021-11-02 00:18:22 -06003488 case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
3489 case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
3490 case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003491 default:return_trace (c->default_return_value ());
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003492 }
3493 }
3494
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04003495 protected:
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003496 union {
Behdad Esfahbod6b191782018-01-10 03:07:30 +01003497 HBUINT16 format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -04003498 ChainContextFormat1 format1;
3499 ChainContextFormat2 format2;
3500 ChainContextFormat3 format3;
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003501 } u;
3502};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003503
3504
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003505template <typename T>
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003506struct ExtensionFormat1
3507{
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303508 unsigned int get_type () const { return extensionLookupType; }
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003509
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003510 template <typename X>
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303511 const X& get_subtable () const
Behdad Esfahbodad28f972021-03-31 12:49:14 -06003512 { return this + reinterpret_cast<const Offset32To<typename T::SubTable> &> (extensionOffset); }
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003513
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -07003514 template <typename context_t, typename ...Ts>
Behdad Esfahbod83e3eab2019-05-07 20:58:43 -07003515 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003516 {
3517 TRACE_DISPATCH (this, format);
Behdad Esfahbodf396fbb2015-10-09 12:25:55 -04003518 if (unlikely (!c->may_dispatch (this, this))) return_trace (c->no_dispatch_return_value ());
Behdad Esfahbod6d555ce2021-11-02 00:18:22 -06003519 return_trace (get_subtable<typename T::SubTable> ().dispatch (c, get_type (), std::forward<Ts> (ds)...));
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003520 }
3521
Qunxin Liu8200e482020-02-26 13:11:42 -08003522 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
3523 { dispatch (c); }
3524
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003525 /* This is called from may_dispatch() above with hb_sanitize_context_t. */
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303526 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03003527 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05003528 TRACE_SANITIZE (this);
Behdad Esfahbod949f6af2018-01-15 20:44:10 -05003529 return_trace (c->check_struct (this) &&
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07003530 extensionLookupType != T::SubTable::Extension);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04003531 }
3532
Garret Rieger08a49972020-10-06 13:02:12 -07003533 bool subset (hb_subset_context_t *c) const
3534 {
3535 TRACE_SUBSET (this);
3536
3537 auto *out = c->serializer->start_embed (this);
3538 if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
3539
3540 out->format = format;
3541 out->extensionLookupType = extensionLookupType;
3542
3543 const auto& src_offset =
Behdad Esfahbodad28f972021-03-31 12:49:14 -06003544 reinterpret_cast<const Offset32To<typename T::SubTable> &> (extensionOffset);
Garret Rieger08a49972020-10-06 13:02:12 -07003545 auto& dest_offset =
Behdad Esfahbodad28f972021-03-31 12:49:14 -06003546 reinterpret_cast<Offset32To<typename T::SubTable> &> (out->extensionOffset);
Garret Rieger08a49972020-10-06 13:02:12 -07003547
3548 return_trace (dest_offset.serialize_subset (c, src_offset, this, get_type ()));
3549 }
3550
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04003551 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01003552 HBUINT16 format; /* Format identifier. Set to 1. */
3553 HBUINT16 extensionLookupType; /* Lookup type of subtable referenced
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003554 * by ExtensionOffset (i.e. the
3555 * extension subtable). */
Behdad Esfahbodcd9bc732019-05-10 13:17:41 -07003556 Offset32 extensionOffset; /* Offset to the extension subtable,
Behdad Esfahbod81f2af42010-04-22 00:58:49 -04003557 * of lookup type subtable. */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04003558 public:
3559 DEFINE_SIZE_STATIC (8);
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003560};
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003561
Behdad Esfahbod653eeb22012-11-23 16:57:36 -05003562template <typename T>
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003563struct Extension
3564{
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303565 unsigned int get_type () const
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003566 {
3567 switch (u.format) {
Behdad Esfahboddacebca2010-05-10 19:45:41 -04003568 case 1: return u.format1.get_type ();
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003569 default:return 0;
3570 }
3571 }
Behdad Esfahbod7dddd4e2012-11-23 17:04:55 -05003572 template <typename X>
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303573 const X& get_subtable () const
Behdad Esfahbod7dddd4e2012-11-23 17:04:55 -05003574 {
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003575 switch (u.format) {
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07003576 case 1: return u.format1.template get_subtable<typename T::SubTable> ();
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04303577 default:return Null (typename T::SubTable);
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003578 }
Behdad Esfahbod7dddd4e2012-11-23 17:04:55 -05003579 }
3580
Garret Rieger08a49972020-10-06 13:02:12 -07003581 // Specialization of dispatch for subset. dispatch() normally just
3582 // dispatches to the sub table this points too, but for subset
3583 // we need to run subset on this subtable too.
3584 template <typename ...Ts>
3585 typename hb_subset_context_t::return_t dispatch (hb_subset_context_t *c, Ts&&... ds) const
3586 {
3587 switch (u.format) {
3588 case 1: return u.format1.subset (c);
3589 default: return c->default_return_value ();
3590 }
3591 }
3592
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -07003593 template <typename context_t, typename ...Ts>
Behdad Esfahbod83e3eab2019-05-07 20:58:43 -07003594 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
Behdad Esfahbod653eeb22012-11-23 16:57:36 -05003595 {
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003596 TRACE_DISPATCH (this, u.format);
Behdad Esfahbodf396fbb2015-10-09 12:25:55 -04003597 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04003598 switch (u.format) {
Behdad Esfahbod6d555ce2021-11-02 00:18:22 -06003599 case 1: return_trace (u.format1.dispatch (c, std::forward<Ts> (ds)...));
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003600 default:return_trace (c->default_return_value ());
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04003601 }
3602 }
3603
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04003604 protected:
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003605 union {
Behdad Esfahbod6b191782018-01-10 03:07:30 +01003606 HBUINT16 format; /* Format identifier */
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003607 ExtensionFormat1<T> format1;
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003608 } u;
3609};
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003610
3611
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04003612/*
3613 * GSUB/GPOS Common
3614 */
3615
Behdad Esfahbod97e59132018-10-10 11:41:05 -04003616struct hb_ot_layout_lookup_accelerator_t
3617{
3618 template <typename TLookup>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303619 void init (const TLookup &lookup)
Behdad Esfahbod97e59132018-10-10 11:41:05 -04003620 {
3621 digest.init ();
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07003622 lookup.collect_coverage (&digest);
Behdad Esfahbod78c09bf2018-10-10 11:50:46 -04003623
3624 subtables.init ();
3625 OT::hb_get_subtables_context_t c_get_subtables (subtables);
3626 lookup.dispatch (&c_get_subtables);
Behdad Esfahbod97e59132018-10-10 11:41:05 -04003627 }
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303628 void fini () { subtables.fini (); }
Behdad Esfahbod97e59132018-10-10 11:41:05 -04003629
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303630 bool may_have (hb_codepoint_t g) const
Behdad Esfahbod97e59132018-10-10 11:41:05 -04003631 { return digest.may_have (g); }
3632
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303633 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbode78549e2018-10-10 11:54:48 -04003634 {
Behdad Esfahbod474a1202018-12-21 18:46:51 -05003635 for (unsigned int i = 0; i < subtables.length; i++)
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03303636 if (subtables[i].apply (c))
3637 return true;
3638 return false;
Behdad Esfahbode78549e2018-10-10 11:54:48 -04003639 }
3640
3641 private:
Behdad Esfahbod97e59132018-10-10 11:41:05 -04003642 hb_set_digest_t digest;
Behdad Esfahbod78c09bf2018-10-10 11:50:46 -04003643 hb_get_subtables_context_t::array_t subtables;
Behdad Esfahbod97e59132018-10-10 11:41:05 -04003644};
3645
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04003646struct GSUBGPOS
3647{
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303648 bool has_data () const { return version.to_int (); }
3649 unsigned int get_script_count () const
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04003650 { return (this+scriptList).len; }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303651 const Tag& get_script_tag (unsigned int i) const
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04003652 { return (this+scriptList).get_tag (i); }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303653 unsigned int get_script_tags (unsigned int start_offset,
3654 unsigned int *script_count /* IN/OUT */,
3655 hb_tag_t *script_tags /* OUT */) const
Behdad Esfahbode21899b2009-11-04 16:36:14 -05003656 { return (this+scriptList).get_tags (start_offset, script_count, script_tags); }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303657 const Script& get_script (unsigned int i) const
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04003658 { return (this+scriptList)[i]; }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303659 bool find_script_index (hb_tag_t tag, unsigned int *index) const
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04003660 { return (this+scriptList).find_index (tag, index); }
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04003661
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303662 unsigned int get_feature_count () const
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04003663 { return (this+featureList).len; }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303664 hb_tag_t get_feature_tag (unsigned int i) const
Jonathan Kewda132932014-04-27 14:05:24 +01003665 { return i == Index::NOT_FOUND_INDEX ? HB_TAG_NONE : (this+featureList).get_tag (i); }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303666 unsigned int get_feature_tags (unsigned int start_offset,
3667 unsigned int *feature_count /* IN/OUT */,
3668 hb_tag_t *feature_tags /* OUT */) const
Behdad Esfahbode21899b2009-11-04 16:36:14 -05003669 { return (this+featureList).get_tags (start_offset, feature_count, feature_tags); }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303670 const Feature& get_feature (unsigned int i) const
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04003671 { return (this+featureList)[i]; }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303672 bool find_feature_index (hb_tag_t tag, unsigned int *index) const
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04003673 { return (this+featureList).find_index (tag, index); }
3674
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303675 unsigned int get_lookup_count () const
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04003676 { return (this+lookupList).len; }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303677 const Lookup& get_lookup (unsigned int i) const
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04003678 { return (this+lookupList)[i]; }
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04003679
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303680 bool find_variations_index (const int *coords, unsigned int num_coords,
3681 unsigned int *index) const
Behdad Esfahboda8498732019-06-19 19:26:22 -07003682 {
Qunxin Liu0b39c482019-10-22 16:00:43 -07003683#ifdef HB_NO_VAR
Ebrahim Byagowi2e1bf612020-03-26 22:59:26 +04303684 *index = FeatureVariations::NOT_FOUND_INDEX;
Behdad Esfahboda8498732019-06-19 19:26:22 -07003685 return false;
3686#endif
Ebrahim Byagowi071e2e32020-03-26 12:01:53 +04303687 return (version.to_int () >= 0x00010001u ? this+featureVars : Null (FeatureVariations))
Behdad Esfahboda8498732019-06-19 19:26:22 -07003688 .find_index (coords, num_coords, index);
3689 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303690 const Feature& get_feature_variation (unsigned int feature_index,
Behdad Esfahbod3d9a6e62019-01-22 12:02:06 +01003691 unsigned int variations_index) const
Behdad Esfahbodec87ba92016-09-10 03:53:11 -07003692 {
Behdad Esfahboda8498732019-06-19 19:26:22 -07003693#ifndef HB_NO_VAR
Behdad Esfahbodec87ba92016-09-10 03:53:11 -07003694 if (FeatureVariations::NOT_FOUND_INDEX != variations_index &&
3695 version.to_int () >= 0x00010001u)
3696 {
Behdad Esfahbod4ebbeb72016-09-10 04:52:34 -07003697 const Feature *feature = (this+featureVars).find_substitute (variations_index,
3698 feature_index);
Behdad Esfahbodec87ba92016-09-10 03:53:11 -07003699 if (feature)
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03303700 return *feature;
Behdad Esfahbodec87ba92016-09-10 03:53:11 -07003701 }
Behdad Esfahboda8498732019-06-19 19:26:22 -07003702#endif
Behdad Esfahbodec87ba92016-09-10 03:53:11 -07003703 return get_feature (feature_index);
3704 }
Behdad Esfahbod59055b52016-09-10 01:24:28 -07003705
Qunxin Liu0b39c482019-10-22 16:00:43 -07003706 void feature_variation_collect_lookups (const hb_set_t *feature_indexes,
3707 hb_set_t *lookup_indexes /* OUT */) const
3708 {
3709#ifndef HB_NO_VAR
3710 if (version.to_int () >= 0x00010001u)
3711 (this+featureVars).collect_lookups (feature_indexes, lookup_indexes);
3712#endif
3713 }
3714
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07003715 template <typename TLookup>
Qunxin Liu973c47f2020-06-11 11:27:57 -07003716 void closure_lookups (hb_face_t *face,
3717 const hb_set_t *glyphs,
Ebrahim Byagowi5a7cc7f2020-07-29 08:33:32 +04303718 hb_set_t *lookup_indexes /* IN/OUT */) const
Qunxin Liu973c47f2020-06-11 11:27:57 -07003719 {
3720 hb_set_t visited_lookups, inactive_lookups;
3721 OT::hb_closure_lookups_context_t c (face, glyphs, &visited_lookups, &inactive_lookups);
3722
3723 for (unsigned lookup_index : + hb_iter (lookup_indexes))
3724 reinterpret_cast<const TLookup &> (get_lookup (lookup_index)).closure_lookups (&c, lookup_index);
3725
3726 hb_set_union (lookup_indexes, &visited_lookups);
3727 hb_set_subtract (lookup_indexes, &inactive_lookups);
3728 }
3729
Qunxin Liu56ca4352021-01-28 15:21:26 -08003730 void prune_langsys (const hb_map_t *duplicate_feature_map,
Behdad Esfahbod394f7722021-11-19 11:49:23 -07003731 hb_hashmap_t<unsigned, hb_set_t *> *script_langsys_map,
Qunxin Liu56ca4352021-01-28 15:21:26 -08003732 hb_set_t *new_feature_indexes /* OUT */) const
3733 {
3734 hb_prune_langsys_context_t c (this, script_langsys_map, duplicate_feature_map, new_feature_indexes);
Garret Riegerc6adb902021-03-29 16:08:44 -07003735
Qunxin Liu56ca4352021-01-28 15:21:26 -08003736 unsigned count = get_script_count ();
3737 for (unsigned script_index = 0; script_index < count; script_index++)
3738 {
3739 const Script& s = get_script (script_index);
3740 s.prune_langsys (&c, script_index);
3741 }
3742 }
3743
Qunxin Liu973c47f2020-06-11 11:27:57 -07003744 template <typename TLookup>
Qunxin Liue565d1f2019-11-01 10:21:36 -07003745 bool subset (hb_subset_layout_context_t *c) const
Behdad Esfahbodbfa72a92018-09-01 18:34:50 -07003746 {
3747 TRACE_SUBSET (this);
Qunxin Liue565d1f2019-11-01 10:21:36 -07003748 auto *out = c->subset_context->serializer->embed (*this);
Behdad Esfahbodbfa72a92018-09-01 18:34:50 -07003749 if (unlikely (!out)) return_trace (false);
Behdad Esfahbod1b6d0c42018-12-13 18:10:48 -05003750
Qunxin Liue565d1f2019-11-01 10:21:36 -07003751 typedef LookupOffsetList<TLookup> TLookupList;
Behdad Esfahbodad28f972021-03-31 12:49:14 -06003752 reinterpret_cast<Offset16To<TLookupList> &> (out->lookupList)
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04303753 .serialize_subset (c->subset_context,
Behdad Esfahbodad28f972021-03-31 12:49:14 -06003754 reinterpret_cast<const Offset16To<TLookupList> &> (lookupList),
Qunxin Liue565d1f2019-11-01 10:21:36 -07003755 this,
Qunxin Liue565d1f2019-11-01 10:21:36 -07003756 c);
3757
Behdad Esfahbodad28f972021-03-31 12:49:14 -06003758 reinterpret_cast<Offset16To<RecordListOfFeature> &> (out->featureList)
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04303759 .serialize_subset (c->subset_context,
Behdad Esfahbodad28f972021-03-31 12:49:14 -06003760 reinterpret_cast<const Offset16To<RecordListOfFeature> &> (featureList),
Qunxin Liue565d1f2019-11-01 10:21:36 -07003761 this,
Qunxin Liue565d1f2019-11-01 10:21:36 -07003762 c);
3763
3764 out->scriptList.serialize_subset (c->subset_context,
3765 scriptList,
3766 this,
Qunxin Liue565d1f2019-11-01 10:21:36 -07003767 c);
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07003768
Behdad Esfahboda8498732019-06-19 19:26:22 -07003769#ifndef HB_NO_VAR
Behdad Esfahbodbfa72a92018-09-01 18:34:50 -07003770 if (version.to_int () >= 0x00010001u)
Qunxin Liue565d1f2019-11-01 10:21:36 -07003771 {
ariza188a0a42020-03-07 11:02:36 -08003772 bool ret = out->featureVars.serialize_subset (c->subset_context, featureVars, this, c);
Qunxin Liue565d1f2019-11-01 10:21:36 -07003773 if (!ret)
3774 {
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04303775 out->version.major = 1;
3776 out->version.minor = 0;
Qunxin Liue565d1f2019-11-01 10:21:36 -07003777 }
3778 }
Behdad Esfahboda8498732019-06-19 19:26:22 -07003779#endif
Behdad Esfahbod1b6d0c42018-12-13 18:10:48 -05003780
Behdad Esfahbodbfa72a92018-09-01 18:34:50 -07003781 return_trace (true);
3782 }
3783
Qunxin Liu56ca4352021-01-28 15:21:26 -08003784 void find_duplicate_features (const hb_map_t *lookup_indices,
3785 const hb_set_t *feature_indices,
3786 hb_map_t *duplicate_feature_map /* OUT */) const
3787 {
Qunxin Liu364b6b32021-10-31 14:38:20 -07003788 if (feature_indices->is_empty ()) return;
Behdad Esfahbod394f7722021-11-19 11:49:23 -07003789 hb_hashmap_t<hb_tag_t, hb_set_t *> unique_features;
Qunxin Liu56ca4352021-01-28 15:21:26 -08003790 //find out duplicate features after subset
Qunxin Liu56ca4352021-01-28 15:21:26 -08003791 for (unsigned i : feature_indices->iter ())
3792 {
Qunxin Liu56ca4352021-01-28 15:21:26 -08003793 hb_tag_t t = get_feature_tag (i);
Behdad Esfahbod5a91db12022-01-13 12:44:48 -07003794 if (t == HB_MAP_VALUE_INVALID) continue;
Qunxin Liu364b6b32021-10-31 14:38:20 -07003795 if (!unique_features.has (t))
Qunxin Liu56ca4352021-01-28 15:21:26 -08003796 {
Qunxin Liu364b6b32021-10-31 14:38:20 -07003797 hb_set_t* indices = hb_set_create ();
3798 if (unlikely (indices == hb_set_get_empty () ||
3799 !unique_features.set (t, indices)))
3800 {
3801 hb_set_destroy (indices);
3802 for (auto _ : unique_features.iter ())
3803 hb_set_destroy (_.second);
3804 return;
3805 }
3806 if (unique_features.get (t))
3807 unique_features.get (t)->add (i);
Qunxin Liu56ca4352021-01-28 15:21:26 -08003808 duplicate_feature_map->set (i, i);
Qunxin Liu56ca4352021-01-28 15:21:26 -08003809 continue;
3810 }
3811
Qunxin Liu8c5c8172021-09-12 20:16:30 -07003812 bool found = false;
Qunxin Liu56ca4352021-01-28 15:21:26 -08003813
Qunxin Liu364b6b32021-10-31 14:38:20 -07003814 hb_set_t* same_tag_features = unique_features.get (t);
3815 for (unsigned other_f_index : same_tag_features->iter ())
Qunxin Liu56ca4352021-01-28 15:21:26 -08003816 {
Qunxin Liu8c5c8172021-09-12 20:16:30 -07003817 const Feature& f = get_feature (i);
3818 const Feature& other_f = get_feature (other_f_index);
3819
3820 auto f_iter =
3821 + hb_iter (f.lookupIndex)
3822 | hb_filter (lookup_indices)
3823 ;
Garret Riegerf51b48c2021-11-02 16:16:52 -07003824
Qunxin Liu8c5c8172021-09-12 20:16:30 -07003825 auto other_f_iter =
3826 + hb_iter (other_f.lookupIndex)
3827 | hb_filter (lookup_indices)
3828 ;
Garret Riegerf51b48c2021-11-02 16:16:52 -07003829
Qunxin Liu8c5c8172021-09-12 20:16:30 -07003830 bool is_equal = true;
3831 for (; f_iter && other_f_iter; f_iter++, other_f_iter++)
3832 {
3833 unsigned a = *f_iter;
3834 unsigned b = *other_f_iter;
3835 if (a != b) { is_equal = false; break; }
3836 }
3837
3838 if (is_equal == false || f_iter || other_f_iter) continue;
Garret Riegerf51b48c2021-11-02 16:16:52 -07003839
Qunxin Liu8c5c8172021-09-12 20:16:30 -07003840 found = true;
3841 duplicate_feature_map->set (i, other_f_index);
3842 break;
Qunxin Liu56ca4352021-01-28 15:21:26 -08003843 }
Garret Riegerf51b48c2021-11-02 16:16:52 -07003844
Qunxin Liu8c5c8172021-09-12 20:16:30 -07003845 if (found == false)
Qunxin Liu56ca4352021-01-28 15:21:26 -08003846 {
Qunxin Liu364b6b32021-10-31 14:38:20 -07003847 same_tag_features->add (i);
Qunxin Liu56ca4352021-01-28 15:21:26 -08003848 duplicate_feature_map->set (i, i);
Qunxin Liu56ca4352021-01-28 15:21:26 -08003849 }
3850 }
Qunxin Liu364b6b32021-10-31 14:38:20 -07003851
3852 for (auto _ : unique_features.iter ())
3853 hb_set_destroy (_.second);
Qunxin Liu56ca4352021-01-28 15:21:26 -08003854 }
3855
Garret Rieger718bf5a2020-09-29 13:16:01 -07003856 void prune_features (const hb_map_t *lookup_indices, /* IN */
Qunxin Liu56ca4352021-01-28 15:21:26 -08003857 hb_set_t *feature_indices /* IN/OUT */) const
Qunxin Liu8ffc9ad2019-10-31 15:59:02 -07003858 {
Garret Rieger718bf5a2020-09-29 13:16:01 -07003859#ifndef HB_NO_VAR
3860 // This is the set of feature indices which have alternate versions defined
3861 // if the FeatureVariation's table and the alternate version(s) intersect the
3862 // set of lookup indices.
3863 hb_set_t alternate_feature_indices;
3864 if (version.to_int () >= 0x00010001u)
3865 (this+featureVars).closure_features (lookup_indices, &alternate_feature_indices);
Behdad Esfahbodfad452b2021-08-16 20:48:24 -06003866 if (unlikely (alternate_feature_indices.in_error()))
3867 {
3868 feature_indices->err ();
Garret Rieger718bf5a2020-09-29 13:16:01 -07003869 return;
3870 }
3871#endif
3872
3873 for (unsigned i : feature_indices->iter())
Qunxin Liu8ffc9ad2019-10-31 15:59:02 -07003874 {
Qunxin Liud7c012a2020-02-26 13:11:42 -08003875 const Feature& f = get_feature (i);
Garret Riegerc35d7862021-04-01 14:32:38 -07003876 hb_tag_t tag = get_feature_tag (i);
3877 if (tag == HB_TAG ('p', 'r', 'e', 'f'))
3878 // Note: Never ever drop feature 'pref', even if it's empty.
3879 // HarfBuzz chooses shaper for Khmer based on presence of this
3880 // feature. See thread at:
3881 // http://lists.freedesktop.org/archives/harfbuzz/2012-November/002660.html
3882 continue;
Garret Rieger718bf5a2020-09-29 13:16:01 -07003883
Qunxin Liuca418ca2021-11-17 16:42:08 -08003884
3885 if (!f.featureParams.is_null () &&
3886 tag == HB_TAG ('s', 'i', 'z', 'e'))
3887 continue;
3888
3889 if (!f.intersects_lookup_indexes (lookup_indices)
Behdad Esfahbod29025292021-03-02 15:05:22 -07003890#ifndef HB_NO_VAR
3891 && !alternate_feature_indices.has (i)
3892#endif
3893 )
3894 feature_indices->del (i);
Qunxin Liu8ffc9ad2019-10-31 15:59:02 -07003895 }
Qunxin Liu8ffc9ad2019-10-31 15:59:02 -07003896 }
3897
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303898 unsigned int get_size () const
Behdad Esfahbodbfa72a92018-09-01 18:34:50 -07003899 {
3900 return min_size +
3901 (version.to_int () >= 0x00010001u ? featureVars.static_size : 0);
3902 }
3903
Behdad Esfahbod6d618522018-09-03 16:41:28 -07003904 template <typename TLookup>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303905 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03003906 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05003907 TRACE_SANITIZE (this);
Behdad Esfahbod5efe3602021-03-31 15:33:22 -06003908 typedef List16OfOffset16To<TLookup> TLookupList;
Behdad Esfahbod8e3cde62019-06-19 19:58:24 -07003909 if (unlikely (!(version.sanitize (c) &&
3910 likely (version.major == 1) &&
3911 scriptList.sanitize (c, this) &&
3912 featureList.sanitize (c, this) &&
Behdad Esfahbodad28f972021-03-31 12:49:14 -06003913 reinterpret_cast<const Offset16To<TLookupList> &> (lookupList).sanitize (c, this))))
Behdad Esfahbod8e3cde62019-06-19 19:58:24 -07003914 return_trace (false);
3915
Behdad Esfahboda8498732019-06-19 19:26:22 -07003916#ifndef HB_NO_VAR
Behdad Esfahbod8e3cde62019-06-19 19:58:24 -07003917 if (unlikely (!(version.to_int () < 0x00010001u || featureVars.sanitize (c, this))))
3918 return_trace (false);
Behdad Esfahboda8498732019-06-19 19:26:22 -07003919#endif
Behdad Esfahbod8e3cde62019-06-19 19:58:24 -07003920
3921 return_trace (true);
Behdad Esfahbodcd3827e2009-08-04 02:09:34 -04003922 }
3923
Behdad Esfahbod963413f2018-08-26 00:47:55 -07003924 template <typename T>
3925 struct accelerator_t
3926 {
Behdad Esfahbodac1bb3e2022-01-20 11:47:17 -07003927 accelerator_t (hb_face_t *face)
Behdad Esfahbod963413f2018-08-26 00:47:55 -07003928 {
Ebrahim Byagowiba22df32020-03-10 10:42:20 +03303929 this->table = hb_sanitize_context_t ().reference_table<T> (face);
Behdad Esfahbod56719472020-06-05 12:57:23 -07003930 if (unlikely (this->table->is_blocklisted (this->table.get_blob (), face)))
Behdad Esfahbod574d8882018-11-25 16:51:22 -05003931 {
3932 hb_blob_destroy (this->table.get_blob ());
3933 this->table = hb_blob_get_empty ();
3934 }
Behdad Esfahbod963413f2018-08-26 00:47:55 -07003935
Behdad Esfahbodb9291002018-08-26 01:15:47 -07003936 this->lookup_count = table->get_lookup_count ();
Behdad Esfahbod963413f2018-08-26 00:47:55 -07003937
Behdad Esfahbod2337f0d2021-07-08 10:58:50 -06003938 this->accels = (hb_ot_layout_lookup_accelerator_t *) hb_calloc (this->lookup_count, sizeof (hb_ot_layout_lookup_accelerator_t));
Behdad Esfahbod963413f2018-08-26 00:47:55 -07003939 if (unlikely (!this->accels))
Dominik Röttschesa5f6f862020-10-23 14:25:05 +03003940 {
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03303941 this->lookup_count = 0;
Behdad Esfahbod53806e52020-11-25 11:51:37 -07003942 this->table.destroy ();
Dominik Röttschesa5f6f862020-10-23 14:25:05 +03003943 this->table = hb_blob_get_empty ();
3944 }
Behdad Esfahbod963413f2018-08-26 00:47:55 -07003945
3946 for (unsigned int i = 0; i < this->lookup_count; i++)
Behdad Esfahbodb9291002018-08-26 01:15:47 -07003947 this->accels[i].init (table->get_lookup (i));
Behdad Esfahbod963413f2018-08-26 00:47:55 -07003948 }
Behdad Esfahbodac1bb3e2022-01-20 11:47:17 -07003949 ~accelerator_t ()
Behdad Esfahbod963413f2018-08-26 00:47:55 -07003950 {
Behdad Esfahbodb9291002018-08-26 01:15:47 -07003951 for (unsigned int i = 0; i < this->lookup_count; i++)
3952 this->accels[i].fini ();
Behdad Esfahbod2337f0d2021-07-08 10:58:50 -06003953 hb_free (this->accels);
Behdad Esfahbodda6aa3b2018-11-11 11:40:57 -05003954 this->table.destroy ();
Behdad Esfahbod963413f2018-08-26 00:47:55 -07003955 }
3956
Behdad Esfahbod5d0078a2018-11-10 23:52:15 -05003957 hb_blob_ptr_t<T> table;
Behdad Esfahbodb9291002018-08-26 01:15:47 -07003958 unsigned int lookup_count;
3959 hb_ot_layout_lookup_accelerator_t *accels;
Behdad Esfahbod963413f2018-08-26 00:47:55 -07003960 };
3961
Behdad Esfahbod212aba62009-05-24 00:50:27 -04003962 protected:
Behdad Esfahbod9a13ed42016-02-22 11:44:45 +09003963 FixedVersion<>version; /* Version of the GSUB/GPOS table--initially set
Behdad Esfahbod76271002014-07-11 14:54:42 -04003964 * to 0x00010000u */
Behdad Esfahbodad28f972021-03-31 12:49:14 -06003965 Offset16To<ScriptList>
Ebrahim Byagowice114d62019-12-31 15:53:02 +03303966 scriptList; /* ScriptList table */
Behdad Esfahbodad28f972021-03-31 12:49:14 -06003967 Offset16To<FeatureList>
Ebrahim Byagowice114d62019-12-31 15:53:02 +03303968 featureList; /* FeatureList table */
Behdad Esfahbodad28f972021-03-31 12:49:14 -06003969 Offset16To<LookupList>
Ebrahim Byagowice114d62019-12-31 15:53:02 +03303970 lookupList; /* LookupList table */
Behdad Esfahbodad28f972021-03-31 12:49:14 -06003971 Offset32To<FeatureVariations>
Behdad Esfahbod59055b52016-09-10 01:24:28 -07003972 featureVars; /* Offset to Feature Variations
3973 table--from beginning of table
3974 * (may be NULL). Introduced
3975 * in version 0x00010001. */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04003976 public:
Behdad Esfahbod59055b52016-09-10 01:24:28 -07003977 DEFINE_SIZE_MIN (10);
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04003978};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04003979
Behdad Esfahbod6f20f722009-05-17 20:28:01 -04003980
Behdad Esfahbod7d52e662012-11-16 18:49:54 -08003981} /* namespace OT */
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -04003982
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04003983
Behdad Esfahbodc77ae402018-08-25 22:36:36 -07003984#endif /* HB_OT_LAYOUT_GSUBGPOS_HH */