blob: c77ec12fbe82d7bfb32d67f7d7b1db1d9b73a640 [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
Behdad Esfahbodbca710e2022-06-02 12:06:25 -0600112 if (!done_lookups_glyph_set->has (lookup_index))
Garret Riegerc6adb902021-03-29 16:08:44 -0700113 {
Behdad Esfahbod997d9cc2022-06-02 18:04:12 -0600114 if (unlikely (!done_lookups_glyph_set->set (lookup_index, hb::unique_ptr<hb_set_t> {hb_set_create ()})))
Behdad Esfahbod9ed5f042021-03-29 18:14:30 -0600115 return true;
Garret Riegerc6adb902021-03-29 16:08:44 -0700116 }
Garret Rieger52df6b92021-03-29 16:17:27 -0700117
Garret Rieger9f77a0c2021-03-30 14:10:45 -0700118 hb_set_clear (done_lookups_glyph_set->get (lookup_index));
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -0800119 }
120
121 hb_set_t *covered_glyph_set = done_lookups_glyph_set->get (lookup_index);
Garret Rieger8b686af2021-04-06 11:33:38 -0700122 if (unlikely (covered_glyph_set->in_error ()))
Garret Rieger64122b52021-04-05 12:53:08 -0700123 return true;
Garret Riegerf3c1f4f2022-01-28 11:50:22 -0800124 if (parent_active_glyphs ().is_subset (*covered_glyph_set))
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -0800125 return true;
Garret Riegerc6adb902021-03-29 16:08:44 -0700126
Garret Riegerf3c1f4f2022-01-28 11:50:22 -0800127 covered_glyph_set->union_ (parent_active_glyphs ());
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -0800128 return false;
Garret Rieger45186b92018-06-05 17:14:42 -0700129 }
130
Garret Rieger4e2f4092022-01-31 12:20:32 -0800131 const hb_set_t& previous_parent_active_glyphs () {
132 if (active_glyphs_stack.length <= 1)
133 return *glyphs;
134
135 return active_glyphs_stack[active_glyphs_stack.length - 2];
136 }
137
Garret Riegerf3c1f4f2022-01-28 11:50:22 -0800138 const hb_set_t& parent_active_glyphs ()
Qunxin Liub4fc5932020-12-09 10:44:18 -0800139 {
Garret Riegerf3c1f4f2022-01-28 11:50:22 -0800140 if (!active_glyphs_stack)
141 return *glyphs;
Garret Riegerc6adb902021-03-29 16:08:44 -0700142
Qunxin Liub4fc5932020-12-09 10:44:18 -0800143 return active_glyphs_stack.tail ();
144 }
145
Garret Riegerf3c1f4f2022-01-28 11:50:22 -0800146 hb_set_t& push_cur_active_glyphs ()
Qunxin Liub4fc5932020-12-09 10:44:18 -0800147 {
Garret Riegerf3c1f4f2022-01-28 11:50:22 -0800148 return *active_glyphs_stack.push ();
Qunxin Liub4fc5932020-12-09 10:44:18 -0800149 }
150
151 bool pop_cur_done_glyphs ()
152 {
Behdad Esfahbod6826b2c2022-07-20 13:25:34 -0600153 if (!active_glyphs_stack)
Qunxin Liub4fc5932020-12-09 10:44:18 -0800154 return false;
155
156 active_glyphs_stack.pop ();
157 return true;
158 }
159
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400160 hb_face_t *face;
Behdad Esfahbod6a9be5b2012-04-23 22:23:17 -0400161 hb_set_t *glyphs;
Behdad Esfahbodede1a712019-01-09 10:45:53 -0800162 hb_set_t output[1];
Garret Riegerf3c1f4f2022-01-28 11:50:22 -0800163 hb_vector_t<hb_set_t> active_glyphs_stack;
Behdad Esfahbodf4a8b702022-05-30 05:30:37 -0600164 recurse_func_t recurse_func = nullptr;
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400165 unsigned int nesting_level_left;
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400166
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400167 hb_closure_context_t (hb_face_t *face_,
Behdad Esfahbod6a9be5b2012-04-23 22:23:17 -0400168 hb_set_t *glyphs_,
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -0800169 hb_map_t *done_lookups_glyph_count_,
Behdad Esfahbod997d9cc2022-06-02 18:04:12 -0600170 hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *done_lookups_glyph_set_,
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330171 unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400172 face (face_),
173 glyphs (glyphs_),
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400174 nesting_level_left (nesting_level_left_),
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -0800175 done_lookups_glyph_count (done_lookups_glyph_count_),
Behdad Esfahbodf4a8b702022-05-30 05:30:37 -0600176 done_lookups_glyph_set (done_lookups_glyph_set_)
Garret Riegerf3c1f4f2022-01-28 11:50:22 -0800177 {}
Behdad Esfahbod9b346772012-11-23 17:55:40 -0500178
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330179 ~hb_closure_context_t () { flush (); }
Behdad Esfahbodc38bd402018-07-24 09:43:27 -0700180
Behdad Esfahbod9b346772012-11-23 17:55:40 -0500181 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
Garret Rieger45186b92018-06-05 17:14:42 -0700182
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330183 void flush ()
Behdad Esfahbodc38bd402018-07-24 09:43:27 -0700184 {
Garret Riegerf3c1f4f2022-01-28 11:50:22 -0800185 output->del_range (face->get_num_glyphs (), HB_SET_VALUE_INVALID); /* Remove invalid glyphs. */
186 glyphs->union_ (*output);
187 output->clear ();
Qunxin Liub4fc5932020-12-09 10:44:18 -0800188 active_glyphs_stack.pop ();
Garret Riegerf3c1f4f2022-01-28 11:50:22 -0800189 active_glyphs_stack.reset ();
Behdad Esfahbodc38bd402018-07-24 09:43:27 -0700190 }
191
Garret Rieger45186b92018-06-05 17:14:42 -0700192 private:
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -0800193 hb_map_t *done_lookups_glyph_count;
Behdad Esfahbod997d9cc2022-06-02 18:04:12 -0600194 hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *done_lookups_glyph_set;
Behdad Esfahbodf4a8b702022-05-30 05:30:37 -0600195 unsigned int lookup_count = 0;
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400196};
197
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -0800198
199
Qunxin Liu0b39c482019-10-22 16:00:43 -0700200struct hb_closure_lookups_context_t :
Behdad Esfahbod25aec022020-06-18 16:58:01 -0700201 hb_dispatch_context_t<hb_closure_lookups_context_t>
Qunxin Liu0b39c482019-10-22 16:00:43 -0700202{
Qunxin Liu0b39c482019-10-22 16:00:43 -0700203 typedef return_t (*recurse_func_t) (hb_closure_lookups_context_t *c, unsigned lookup_index);
204 template <typename T>
205 return_t dispatch (const T &obj) { obj.closure_lookups (this); return hb_empty_t (); }
206 static return_t default_return_value () { return hb_empty_t (); }
207 void recurse (unsigned lookup_index)
208 {
209 if (unlikely (nesting_level_left == 0 || !recurse_func))
210 return;
211
212 /* Return if new lookup was recursed to before. */
Garret Rieger77507a12021-12-10 14:10:04 -0800213 if (lookup_limit_exceeded ()
214 || visited_lookups->in_error ()
215 || visited_lookups->has (lookup_index))
216 // Don't increment lookup count here, that will be done in the call to closure_lookups()
217 // made by recurse_func.
Qunxin Liu0b39c482019-10-22 16:00:43 -0700218 return;
219
Qunxin Liu0b39c482019-10-22 16:00:43 -0700220 nesting_level_left--;
221 recurse_func (this, lookup_index);
222 nesting_level_left++;
223 }
224
225 void set_lookup_visited (unsigned lookup_index)
226 { visited_lookups->add (lookup_index); }
227
228 void set_lookup_inactive (unsigned lookup_index)
229 { inactive_lookups->add (lookup_index); }
230
Garret Rieger4ad686b2020-03-25 23:32:28 -0700231 bool lookup_limit_exceeded ()
Qunxin Liu706014f2021-12-01 20:20:12 -0800232 {
233 bool ret = lookup_count > HB_MAX_LOOKUP_VISIT_COUNT;
234 if (ret)
235 DEBUG_MSG (SUBSET, nullptr, "lookup visit count limit exceeded in lookup closure!");
236 return ret; }
Garret Rieger4ad686b2020-03-25 23:32:28 -0700237
Qunxin Liu0b39c482019-10-22 16:00:43 -0700238 bool is_lookup_visited (unsigned lookup_index)
Garret Rieger834a2242020-03-12 03:02:36 -0700239 {
Qunxin Liu706014f2021-12-01 20:20:12 -0800240 if (unlikely (lookup_count++ > HB_MAX_LOOKUP_VISIT_COUNT))
241 {
242 DEBUG_MSG (SUBSET, nullptr, "total visited lookup count %u exceeds max limit, lookup %u is dropped.",
243 lookup_count, lookup_index);
Garret Rieger834a2242020-03-12 03:02:36 -0700244 return true;
Qunxin Liu706014f2021-12-01 20:20:12 -0800245 }
Garret Rieger834a2242020-03-12 03:02:36 -0700246
Behdad Esfahbodd7e2a512021-02-11 10:55:03 -0700247 if (unlikely (visited_lookups->in_error ()))
Garret Rieger95622392020-08-12 13:01:22 -0700248 return true;
249
Garret Rieger834a2242020-03-12 03:02:36 -0700250 return visited_lookups->has (lookup_index);
251 }
Qunxin Liu0b39c482019-10-22 16:00:43 -0700252
253 hb_face_t *face;
254 const hb_set_t *glyphs;
255 recurse_func_t recurse_func;
256 unsigned int nesting_level_left;
Qunxin Liu0b39c482019-10-22 16:00:43 -0700257
258 hb_closure_lookups_context_t (hb_face_t *face_,
259 const hb_set_t *glyphs_,
260 hb_set_t *visited_lookups_,
261 hb_set_t *inactive_lookups_,
262 unsigned nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
263 face (face_),
264 glyphs (glyphs_),
265 recurse_func (nullptr),
266 nesting_level_left (nesting_level_left_),
Qunxin Liu0b39c482019-10-22 16:00:43 -0700267 visited_lookups (visited_lookups_),
Garret Rieger834a2242020-03-12 03:02:36 -0700268 inactive_lookups (inactive_lookups_),
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +0430269 lookup_count (0) {}
Qunxin Liu0b39c482019-10-22 16:00:43 -0700270
271 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
272
273 private:
274 hb_set_t *visited_lookups;
275 hb_set_t *inactive_lookups;
Garret Rieger834a2242020-03-12 03:02:36 -0700276 unsigned int lookup_count;
Qunxin Liu0b39c482019-10-22 16:00:43 -0700277};
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400278
Behdad Esfahbod77a1a2b2015-10-09 12:20:58 -0400279struct hb_would_apply_context_t :
Behdad Esfahbod8d0a90a2020-06-18 16:53:54 -0700280 hb_dispatch_context_t<hb_would_apply_context_t, bool>
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400281{
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500282 template <typename T>
Behdad Esfahbodc14efb82019-05-05 09:54:58 -0700283 return_t dispatch (const T &obj) { return obj.would_apply (this); }
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330284 static return_t default_return_value () { return false; }
Behdad Esfahbod7b912c12013-01-04 01:25:27 -0600285 bool stop_sublookup_iteration (return_t r) const { return r; }
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500286
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400287 hb_face_t *face;
Behdad Esfahbod472f2292012-08-07 22:25:24 -0400288 const hb_codepoint_t *glyphs;
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400289 unsigned int len;
Behdad Esfahbodd9b204d2012-08-23 16:22:28 -0400290 bool zero_context;
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400291
292 hb_would_apply_context_t (hb_face_t *face_,
Behdad Esfahbod472f2292012-08-07 22:25:24 -0400293 const hb_codepoint_t *glyphs_,
294 unsigned int len_,
Behdad Esfahbod2bd9fe32012-09-04 15:15:19 -0400295 bool zero_context_) :
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400296 face (face_),
Behdad Esfahbod472f2292012-08-07 22:25:24 -0400297 glyphs (glyphs_),
298 len (len_),
Behdad Esfahbod70d66962020-06-18 17:09:39 -0700299 zero_context (zero_context_) {}
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400300};
301
Behdad Esfahbod77a1a2b2015-10-09 12:20:58 -0400302struct hb_collect_glyphs_context_t :
Behdad Esfahbod25aec022020-06-18 16:58:01 -0700303 hb_dispatch_context_t<hb_collect_glyphs_context_t>
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800304{
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500305 typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index);
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500306 template <typename T>
Behdad Esfahbod7df3ecf2019-05-10 20:43:26 -0700307 return_t dispatch (const T &obj) { obj.collect_glyphs (this); return hb_empty_t (); }
308 static return_t default_return_value () { return hb_empty_t (); }
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700309 void recurse (unsigned int lookup_index)
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500310 {
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500311 if (unlikely (nesting_level_left == 0 || !recurse_func))
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700312 return;
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500313
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200314 /* Note that GPOS sets recurse_func to nullptr already, so it doesn't get
Behdad Esfahbod1bcfa062012-12-04 16:58:09 -0500315 * past the previous check. For GSUB, we only want to collect the output
Behdad Esfahbod76ea5632013-05-04 16:01:20 -0400316 * glyphs in the recursion. If output is not requested, we can go home now.
317 *
318 * Note further, that the above is not exactly correct. A recursed lookup
319 * is allowed to match input that is not matched in the context, but that's
320 * not how most fonts are built. It's possible to relax that and recurse
321 * with all sets here if it proves to be an issue.
322 */
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500323
324 if (output == hb_set_get_empty ())
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700325 return;
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500326
Behdad Esfahbodfde3e4a2014-10-29 11:23:08 -0700327 /* Return if new lookup was recursed to before. */
Behdad Esfahbod8b9d9b72017-10-22 17:48:06 -0400328 if (recursed_lookups->has (lookup_index))
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700329 return;
Behdad Esfahbodfde3e4a2014-10-29 11:23:08 -0700330
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500331 hb_set_t *old_before = before;
332 hb_set_t *old_input = input;
333 hb_set_t *old_after = after;
334 before = input = after = hb_set_get_empty ();
Behdad Esfahbod1bcfa062012-12-04 16:58:09 -0500335
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500336 nesting_level_left--;
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500337 recurse_func (this, lookup_index);
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500338 nesting_level_left++;
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500339
340 before = old_before;
341 input = old_input;
342 after = old_after;
343
Behdad Esfahbod8b9d9b72017-10-22 17:48:06 -0400344 recursed_lookups->add (lookup_index);
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500345 }
346
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800347 hb_face_t *face;
Behdad Esfahbod83035932012-12-04 17:08:41 -0500348 hb_set_t *before;
349 hb_set_t *input;
350 hb_set_t *after;
351 hb_set_t *output;
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500352 recurse_func_t recurse_func;
Behdad Esfahbod8b9d9b72017-10-22 17:48:06 -0400353 hb_set_t *recursed_lookups;
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500354 unsigned int nesting_level_left;
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800355
356 hb_collect_glyphs_context_t (hb_face_t *face_,
Ebrahim Byagowi63109432018-10-13 14:00:05 +0330357 hb_set_t *glyphs_before, /* OUT. May be NULL */
358 hb_set_t *glyphs_input, /* OUT. May be NULL */
359 hb_set_t *glyphs_after, /* OUT. May be NULL */
360 hb_set_t *glyphs_output, /* OUT. May be NULL */
Behdad Esfahbod5ba45042015-11-02 15:43:08 -0800361 unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800362 face (face_),
Behdad Esfahbod83035932012-12-04 17:08:41 -0500363 before (glyphs_before ? glyphs_before : hb_set_get_empty ()),
364 input (glyphs_input ? glyphs_input : hb_set_get_empty ()),
365 after (glyphs_after ? glyphs_after : hb_set_get_empty ()),
366 output (glyphs_output ? glyphs_output : hb_set_get_empty ()),
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200367 recurse_func (nullptr),
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700368 recursed_lookups (hb_set_create ()),
Behdad Esfahbod70d66962020-06-18 17:09:39 -0700369 nesting_level_left (nesting_level_left_) {}
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330370 ~hb_collect_glyphs_context_t () { hb_set_destroy (recursed_lookups); }
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500371
372 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800373};
374
375
376
Behdad Esfahbod8e36ccf2015-02-17 19:15:34 +0300377template <typename set_t>
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -0700378struct hb_collect_coverage_context_t :
Behdad Esfahbod8d0a90a2020-06-18 16:53:54 -0700379 hb_dispatch_context_t<hb_collect_coverage_context_t<set_t>, const Coverage &>
Behdad Esfahbod2005fa52012-11-22 14:38:10 -0500380{
Behdad Esfahboddc492d72020-06-18 17:03:05 -0700381 typedef const Coverage &return_t; // Stoopid that we have to dupe this here.
Behdad Esfahbod2005fa52012-11-22 14:38:10 -0500382 template <typename T>
Behdad Esfahbodc14efb82019-05-05 09:54:58 -0700383 return_t dispatch (const T &obj) { return obj.get_coverage (); }
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +0430384 static return_t default_return_value () { return Null (Coverage); }
Behdad Esfahbod8e36ccf2015-02-17 19:15:34 +0300385 bool stop_sublookup_iteration (return_t r) const
386 {
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -0700387 r.collect_coverage (set);
Behdad Esfahbod8e36ccf2015-02-17 19:15:34 +0300388 return false;
389 }
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500390
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -0700391 hb_collect_coverage_context_t (set_t *set_) :
Behdad Esfahbod70d66962020-06-18 17:09:39 -0700392 set (set_) {}
Behdad Esfahboda1733db2012-11-23 16:40:04 -0500393
Behdad Esfahbod8e36ccf2015-02-17 19:15:34 +0300394 set_t *set;
Behdad Esfahbod2005fa52012-11-22 14:38:10 -0500395};
396
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800397struct hb_ot_apply_context_t :
398 hb_dispatch_context_t<hb_ot_apply_context_t, bool, HB_DEBUG_APPLY>
Behdad Esfahbod1376fb72010-04-29 02:19:21 -0400399{
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500400 struct matcher_t
401 {
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330402 matcher_t () :
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500403 lookup_props (0),
Behdad Esfahbod044d7a02022-03-28 12:38:56 -0600404 mask (-1),
Behdad Esfahbodcfc507c2013-02-14 10:40:12 -0500405 ignore_zwnj (false),
406 ignore_zwj (false),
Behdad Esfahbod044d7a02022-03-28 12:38:56 -0600407 per_syllable (false),
Behdad Esfahbode8f33972022-03-28 12:07:05 -0600408 syllable {0},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200409 match_func (nullptr),
Ebrahim Byagowif7a08cd2018-10-30 11:29:09 +0330410 match_data (nullptr) {}
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500411
Behdad Esfahbod8b349e12022-07-06 17:22:34 -0600412 typedef bool (*match_func_t) (hb_glyph_info_t &info, unsigned value, const void *data);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500413
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330414 void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; }
415 void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
416 void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
417 void set_mask (hb_mask_t mask_) { mask = mask_; }
Behdad Esfahbod044d7a02022-03-28 12:38:56 -0600418 void set_per_syllable (bool per_syllable_) { per_syllable = per_syllable_; }
419 void set_syllable (uint8_t syllable_) { syllable = per_syllable ? syllable_ : 0; }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330420 void set_match_func (match_func_t match_func_,
Ebrahim Byagowid0e2add2020-07-18 22:14:52 +0430421 const void *match_data_)
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500422 { match_func = match_func_; match_data = match_data_; }
423
Behdad Esfahbod2b2a6e82013-02-21 15:07:03 -0500424 enum may_match_t {
425 MATCH_NO,
426 MATCH_YES,
427 MATCH_MAYBE
428 };
429
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600430 may_match_t may_match (hb_glyph_info_t &info,
Behdad Esfahbod1ef67a62022-07-06 17:28:02 -0600431 hb_codepoint_t glyph_data) const
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500432 {
Behdad Esfahbod2b2a6e82013-02-21 15:07:03 -0500433 if (!(info.mask & mask) ||
434 (syllable && syllable != info.syllable ()))
435 return MATCH_NO;
436
437 if (match_func)
Behdad Esfahbod1ef67a62022-07-06 17:28:02 -0600438 return match_func (info, glyph_data, match_data) ? MATCH_YES : MATCH_NO;
Behdad Esfahbod2b2a6e82013-02-21 15:07:03 -0500439
440 return MATCH_MAYBE;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500441 }
442
443 enum may_skip_t {
444 SKIP_NO,
445 SKIP_YES,
446 SKIP_MAYBE
447 };
448
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330449 may_skip_t may_skip (const hb_ot_apply_context_t *c,
450 const hb_glyph_info_t &info) const
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500451 {
Behdad Esfahbodb98c5db2014-07-16 13:44:01 -0400452 if (!c->check_glyph_property (&info, lookup_props))
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500453 return SKIP_YES;
454
Khaled Hosny06cfe3f2017-05-17 21:32:47 +0300455 if (unlikely (_hb_glyph_info_is_default_ignorable_and_not_hidden (&info) &&
Behdad Esfahbod0b454792013-02-14 10:46:52 -0500456 (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) &&
Behdad Esfahbod4ba796b2015-07-22 17:41:31 +0100457 (ignore_zwj || !_hb_glyph_info_is_zwj (&info))))
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500458 return SKIP_MAYBE;
459
460 return SKIP_NO;
461 }
462
463 protected:
464 unsigned int lookup_props;
Behdad Esfahbod044d7a02022-03-28 12:38:56 -0600465 hb_mask_t mask;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500466 bool ignore_zwnj;
Behdad Esfahbod0b454792013-02-14 10:46:52 -0500467 bool ignore_zwj;
Behdad Esfahbod044d7a02022-03-28 12:38:56 -0600468 bool per_syllable;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500469 uint8_t syllable;
470 match_func_t match_func;
471 const void *match_data;
472 };
473
Behdad Esfahbod69626692015-01-29 13:08:41 +0100474 struct skipping_iterator_t
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500475 {
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330476 void init (hb_ot_apply_context_t *c_, bool context_match = false)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500477 {
Behdad Esfahbod514564f2015-01-29 13:48:48 +0100478 c = c_;
Behdad Esfahbod429b3872022-07-06 17:37:11 -0600479 match_glyph_data16 = nullptr;
Behdad Esfahbod5a9c7932022-07-22 21:33:15 -0600480#ifndef HB_NO_BEYOND_64K
Behdad Esfahbod429b3872022-07-06 17:37:11 -0600481 match_glyph_data24 = nullptr;
482#endif
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200483 matcher.set_match_func (nullptr, nullptr);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500484 matcher.set_lookup_props (c->lookup_props);
Behdad Esfahbod3583fb02018-09-23 22:33:38 -0400485 /* Ignore ZWNJ if we are matching GPOS, or matching GSUB context and asked to. */
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100486 matcher.set_ignore_zwnj (c->table_index == 1 || (context_match && c->auto_zwnj));
Behdad Esfahbod3583fb02018-09-23 22:33:38 -0400487 /* Ignore ZWJ if we are matching context, or asked to. */
488 matcher.set_ignore_zwj (context_match || c->auto_zwj);
Behdad Esfahbod514564f2015-01-29 13:48:48 +0100489 matcher.set_mask (context_match ? -1 : c->lookup_mask);
Behdad Esfahbod044d7a02022-03-28 12:38:56 -0600490 matcher.set_per_syllable (c->per_syllable);
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_,
Behdad Esfahbodf114b182022-07-06 17:31:46 -0600497 const void *match_data_)
Behdad Esfahbodc074ebc2013-02-13 11:22:42 -0500498 {
Behdad Esfahbod4a6b1ee2015-10-21 11:20:55 -0200499 matcher.set_match_func (match_func_, match_data_);
Behdad Esfahbodf114b182022-07-06 17:31:46 -0600500 }
501 void set_glyph_data (const HBUINT16 glyph_data[])
502 {
Behdad Esfahbod429b3872022-07-06 17:37:11 -0600503 match_glyph_data16 = glyph_data;
Behdad Esfahbod5a9c7932022-07-22 21:33:15 -0600504#ifndef HB_NO_BEYOND_64K
Behdad Esfahbod429b3872022-07-06 17:37:11 -0600505 match_glyph_data24 = nullptr;
506#endif
Behdad Esfahbodc074ebc2013-02-13 11:22:42 -0500507 }
Behdad Esfahbod5a9c7932022-07-22 21:33:15 -0600508#ifndef HB_NO_BEYOND_64K
Behdad Esfahbod429b3872022-07-06 17:37:11 -0600509 void set_glyph_data (const HBUINT24 glyph_data[])
510 {
511 match_glyph_data16 = nullptr;
512 match_glyph_data24 = glyph_data;
513 }
514#endif
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500515
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330516 void reset (unsigned int start_index_,
Ebrahim Byagowi08428a12020-04-24 23:45:17 +0430517 unsigned int num_items_)
Behdad Esfahbodb051be52015-01-29 13:40:39 +0100518 {
519 idx = start_index_;
520 num_items = num_items_;
521 end = c->buffer->len;
522 matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
523 }
524
Ebrahim Byagowi64a45be2019-11-09 12:25:33 +0330525 void reject ()
526 {
527 num_items++;
Behdad Esfahbod429b3872022-07-06 17:37:11 -0600528 backup_glyph_data ();
Ebrahim Byagowi64a45be2019-11-09 12:25:33 +0330529 }
Behdad Esfahbod69626692015-01-29 13:08:41 +0100530
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330531 matcher_t::may_skip_t
532 may_skip (const hb_glyph_info_t &info) const
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330533 { return matcher.may_skip (c, info); }
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200534
Behdad Esfahbod3122c2c2021-12-04 19:50:33 -0800535 bool next (unsigned *unsafe_to = nullptr)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500536 {
Behdad Esfahbod506ffeb2012-01-18 16:07:53 -0500537 assert (num_items > 0);
Behdad Esfahbod37d13ac2015-01-29 11:38:01 +0100538 while (idx + num_items < end)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500539 {
Behdad Esfahboda4a48fe2012-01-17 18:08:41 -0500540 idx++;
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600541 hb_glyph_info_t &info = c->buffer->info[idx];
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500542
Behdad Esfahbodff93ac82013-02-21 14:51:40 -0500543 matcher_t::may_skip_t skip = matcher.may_skip (c, info);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500544 if (unlikely (skip == matcher_t::SKIP_YES))
545 continue;
546
Behdad Esfahbod429b3872022-07-06 17:37:11 -0600547 matcher_t::may_match_t match = matcher.may_match (info, get_glyph_data ());
Behdad Esfahbod722e8b82013-02-21 15:37:51 -0500548 if (match == matcher_t::MATCH_YES ||
549 (match == matcher_t::MATCH_MAYBE &&
550 skip == matcher_t::SKIP_NO))
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500551 {
552 num_items--;
Behdad Esfahbod429b3872022-07-06 17:37:11 -0600553 advance_glyph_data ();
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500554 return true;
555 }
556
557 if (skip == matcher_t::SKIP_NO)
Behdad Esfahbod3122c2c2021-12-04 19:50:33 -0800558 {
559 if (unsafe_to)
560 *unsafe_to = idx + 1;
Behdad Esfahbod722e8b82013-02-21 15:37:51 -0500561 return false;
Behdad Esfahbod3122c2c2021-12-04 19:50:33 -0800562 }
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500563 }
Behdad Esfahbod3122c2c2021-12-04 19:50:33 -0800564 if (unsafe_to)
565 *unsafe_to = end;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500566 return false;
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500567 }
Behdad Esfahbod3122c2c2021-12-04 19:50:33 -0800568 bool prev (unsigned *unsafe_from = nullptr)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500569 {
Behdad Esfahbod506ffeb2012-01-18 16:07:53 -0500570 assert (num_items > 0);
Behdad Esfahbod18a06f82018-07-05 14:03:48 +0430571 while (idx > num_items - 1)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500572 {
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500573 idx--;
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600574 hb_glyph_info_t &info = c->buffer->out_info[idx];
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500575
Behdad Esfahbodff93ac82013-02-21 14:51:40 -0500576 matcher_t::may_skip_t skip = matcher.may_skip (c, info);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500577 if (unlikely (skip == matcher_t::SKIP_YES))
578 continue;
579
Behdad Esfahbod429b3872022-07-06 17:37:11 -0600580 matcher_t::may_match_t match = matcher.may_match (info, get_glyph_data ());
Behdad Esfahbod722e8b82013-02-21 15:37:51 -0500581 if (match == matcher_t::MATCH_YES ||
582 (match == matcher_t::MATCH_MAYBE &&
583 skip == matcher_t::SKIP_NO))
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500584 {
585 num_items--;
Behdad Esfahbod429b3872022-07-06 17:37:11 -0600586 advance_glyph_data ();
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500587 return true;
588 }
589
590 if (skip == matcher_t::SKIP_NO)
Behdad Esfahbod3122c2c2021-12-04 19:50:33 -0800591 {
592 if (unsafe_from)
593 *unsafe_from = hb_max (1u, idx) - 1u;
Behdad Esfahbod722e8b82013-02-21 15:37:51 -0500594 return false;
Behdad Esfahbod3122c2c2021-12-04 19:50:33 -0800595 }
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500596 }
Behdad Esfahbod3122c2c2021-12-04 19:50:33 -0800597 if (unsafe_from)
598 *unsafe_from = 0;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500599 return false;
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500600 }
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500601
Behdad Esfahbod429b3872022-07-06 17:37:11 -0600602 hb_codepoint_t
603 get_glyph_data ()
604 {
605 if (match_glyph_data16) return *match_glyph_data16;
Behdad Esfahbod5a9c7932022-07-22 21:33:15 -0600606#ifndef HB_NO_BEYOND_64K
Behdad Esfahbod429b3872022-07-06 17:37:11 -0600607 else
608 if (match_glyph_data24) return *match_glyph_data24;
609#endif
610 return 0;
611 }
612 void
613 advance_glyph_data ()
614 {
615 if (match_glyph_data16) match_glyph_data16++;
Behdad Esfahbod5a9c7932022-07-22 21:33:15 -0600616#ifndef HB_NO_BEYOND_64K
Behdad Esfahbod429b3872022-07-06 17:37:11 -0600617 else
618 if (match_glyph_data24) match_glyph_data24++;
619#endif
620 }
621 void
622 backup_glyph_data ()
623 {
624 if (match_glyph_data16) match_glyph_data16--;
Behdad Esfahbod5a9c7932022-07-22 21:33:15 -0600625#ifndef HB_NO_BEYOND_64K
Behdad Esfahbod429b3872022-07-06 17:37:11 -0600626 else
627 if (match_glyph_data24) match_glyph_data24--;
628#endif
629 }
630
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500631 unsigned int idx;
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400632 protected:
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800633 hb_ot_apply_context_t *c;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500634 matcher_t matcher;
Behdad Esfahbod429b3872022-07-06 17:37:11 -0600635 const HBUINT16 *match_glyph_data16;
Behdad Esfahbod5a9c7932022-07-22 21:33:15 -0600636#ifndef HB_NO_BEYOND_64K
Behdad Esfahbod429b3872022-07-06 17:37:11 -0600637 const HBUINT24 *match_glyph_data24;
638#endif
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500639
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500640 unsigned int num_items;
Behdad Esfahbod69626692015-01-29 13:08:41 +0100641 unsigned int end;
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500642 };
643
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100644
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330645 const char *get_name () { return "APPLY"; }
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800646 typedef return_t (*recurse_func_t) (hb_ot_apply_context_t *c, unsigned int lookup_index);
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100647 template <typename T>
Behdad Esfahbodc14efb82019-05-05 09:54:58 -0700648 return_t dispatch (const T &obj) { return obj.apply (this); }
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330649 static return_t default_return_value () { return false; }
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100650 bool stop_sublookup_iteration (return_t r) const { return r; }
Behdad Esfahbod12757b62018-01-26 18:14:05 -0800651 return_t recurse (unsigned int sub_lookup_index)
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100652 {
Behdad Esfahbodbaf77792017-11-14 21:53:48 -0800653 if (unlikely (nesting_level_left == 0 || !recurse_func || buffer->max_ops-- <= 0))
Behdad Esfahbod9a2a8572022-05-31 04:25:20 -0600654 {
655 buffer->shaping_failed = true;
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100656 return default_return_value ();
Behdad Esfahbod9a2a8572022-05-31 04:25:20 -0600657 }
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100658
659 nesting_level_left--;
Behdad Esfahbod12757b62018-01-26 18:14:05 -0800660 bool ret = recurse_func (this, sub_lookup_index);
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100661 nesting_level_left++;
662 return ret;
663 }
664
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100665 skipping_iterator_t iter_input, iter_context;
666
Behdad Esfahbod880f50f2022-05-20 16:50:00 -0600667 unsigned int table_index; /* GSUB/GPOS */
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100668 hb_font_t *font;
669 hb_face_t *face;
670 hb_buffer_t *buffer;
Behdad Esfahbodf4a8b702022-05-30 05:30:37 -0600671 recurse_func_t recurse_func = nullptr;
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100672 const GDEF &gdef;
673 const VariationStore &var_store;
Behdad Esfahbod880f50f2022-05-20 16:50:00 -0600674 VariationStore::cache_t *var_store_cache;
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100675
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100676 hb_direction_t direction;
Behdad Esfahbod97aa1ce2022-05-29 10:32:59 -0600677 hb_mask_t lookup_mask = 1;
678 unsigned int lookup_index = (unsigned) -1;
679 unsigned int lookup_props = 0;
680 unsigned int nesting_level_left = HB_MAX_NESTING_LEVEL;
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100681
Behdad Esfahbod80de4bc2018-09-10 16:24:52 +0200682 bool has_glyph_classes;
Behdad Esfahbod97aa1ce2022-05-29 10:32:59 -0600683 bool auto_zwnj = true;
684 bool auto_zwj = true;
685 bool per_syllable = false;
686 bool random = false;
687 uint32_t random_state = 1;
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600688 unsigned new_syllables = (unsigned) -1;
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100689
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800690 hb_ot_apply_context_t (unsigned int table_index_,
Ebrahim Byagowid0e2add2020-07-18 22:14:52 +0430691 hb_font_t *font_,
692 hb_buffer_t *buffer_) :
Behdad Esfahbod880f50f2022-05-20 16:50:00 -0600693 table_index (table_index_),
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100694 font (font_), face (font->face), buffer (buffer_),
Behdad Esfahbod7dcf8e12019-06-26 13:44:10 -0700695 gdef (
696#ifndef HB_NO_OT_LAYOUT
697 *face->table.GDEF->table
698#else
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +0430699 Null (GDEF)
Behdad Esfahbod7dcf8e12019-06-26 13:44:10 -0700700#endif
701 ),
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100702 var_store (gdef.get_var_store ()),
Behdad Esfahbod3eb7eff2022-05-21 15:25:53 -0600703 var_store_cache (
704#ifndef HB_NO_VAR
705 table_index == 1 && font->num_coords ? var_store.create_cache () : nullptr
706#else
707 nullptr
708#endif
709 ),
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100710 direction (buffer_->props.direction),
Behdad Esfahbod97aa1ce2022-05-29 10:32:59 -0600711 has_glyph_classes (gdef.has_glyph_classes ())
Behdad Esfahbod880f50f2022-05-20 16:50:00 -0600712 { init_iters (); }
713
Behdad Esfahbod3eb7eff2022-05-21 15:25:53 -0600714 ~hb_ot_apply_context_t ()
715 {
716#ifndef HB_NO_VAR
717 VariationStore::destroy_cache (var_store_cache);
718#endif
719 }
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100720
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330721 void init_iters ()
Behdad Esfahbod365576d2015-01-29 13:59:42 +0100722 {
Behdad Esfahbod365576d2015-01-29 13:59:42 +0100723 iter_input.init (this, false);
724 iter_context.init (this, true);
725 }
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100726
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330727 void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; init_iters (); }
728 void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; init_iters (); }
729 void set_auto_zwnj (bool auto_zwnj_) { auto_zwnj = auto_zwnj_; init_iters (); }
Behdad Esfahbod044d7a02022-03-28 12:38:56 -0600730 void set_per_syllable (bool per_syllable_) { per_syllable = per_syllable_; init_iters (); }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330731 void set_random (bool random_) { random = random_; }
732 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
733 void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; }
734 void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; init_iters (); }
Behdad Esfahbod9516cbd2018-09-23 22:00:34 -0400735
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330736 uint32_t random_number ()
Behdad Esfahbod08260c72018-09-11 10:51:19 +0200737 {
Behdad Esfahbodcfdea882018-09-11 10:57:48 +0200738 /* http://www.cplusplus.com/reference/random/minstd_rand/ */
739 random_state = random_state * 48271 % 2147483647;
740 return random_state;
Behdad Esfahbod08260c72018-09-11 10:51:19 +0200741 }
742
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330743 bool match_properties_mark (hb_codepoint_t glyph,
744 unsigned int glyph_props,
745 unsigned int match_props) const
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400746 {
747 /* If using mark filtering sets, the high short of
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700748 * match_props has the set index.
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400749 */
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700750 if (match_props & LookupFlag::UseMarkFilteringSet)
751 return gdef.mark_set_covers (match_props >> 16, glyph);
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400752
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700753 /* The second byte of match_props has the meaning
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400754 * "ignore marks of attachment type different than
755 * the attachment type specified."
756 */
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700757 if (match_props & LookupFlag::MarkAttachmentType)
758 return (match_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400759
760 return true;
761 }
762
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330763 bool check_glyph_property (const hb_glyph_info_t *info,
764 unsigned int match_props) const
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400765 {
Behdad Esfahbodb98c5db2014-07-16 13:44:01 -0400766 hb_codepoint_t glyph = info->codepoint;
767 unsigned int glyph_props = _hb_glyph_info_get_glyph_props (info);
768
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400769 /* Not covered, if, for example, glyph class is ligature and
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700770 * match_props includes LookupFlags::IgnoreLigatures
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400771 */
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700772 if (glyph_props & match_props & LookupFlag::IgnoreFlags)
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400773 return false;
774
Behdad Esfahbod5a08ecf2012-11-16 13:34:29 -0800775 if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK))
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700776 return match_properties_mark (glyph, glyph_props, match_props);
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400777
778 return true;
779 }
780
Behdad Esfahbodfa12f1a2022-01-12 15:08:34 -0700781 void _set_glyph_class (hb_codepoint_t glyph_index,
Ebrahim Byagowi9748ae72020-08-11 17:52:48 +0430782 unsigned int class_guess = 0,
783 bool ligature = false,
784 bool component = false) const
Behdad Esfahbod60da7632012-07-16 16:13:32 -0400785 {
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600786 if (new_syllables != (unsigned) -1)
787 buffer->cur().syllable() = new_syllables;
788
Behdad Esfahbod9408e0d2022-01-12 15:07:34 -0700789 unsigned int props = _hb_glyph_info_get_glyph_props (&buffer->cur());
790 props |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED;
Behdad Esfahbod09675a82013-10-18 01:05:58 +0200791 if (ligature)
Behdad Esfahbod832a6f92014-06-04 16:57:42 -0400792 {
Behdad Esfahbod9408e0d2022-01-12 15:07:34 -0700793 props |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED;
Behdad Esfahbod832a6f92014-06-04 16:57:42 -0400794 /* In the only place that the MULTIPLIED bit is used, Uniscribe
795 * seems to only care about the "last" transformation between
Bruce Mitchener257d0e52018-10-19 22:49:21 +0700796 * Ligature and Multiple substitutions. Ie. if you ligate, expand,
Behdad Esfahbod832a6f92014-06-04 16:57:42 -0400797 * and ligate again, it forgives the multiplication and acts as
798 * if only ligation happened. As such, clear MULTIPLIED bit.
799 */
Behdad Esfahbod9408e0d2022-01-12 15:07:34 -0700800 props &= ~HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
Behdad Esfahbod832a6f92014-06-04 16:57:42 -0400801 }
802 if (component)
Behdad Esfahbod9408e0d2022-01-12 15:07:34 -0700803 props |= HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
Behdad Esfahbod2fca1422012-07-30 18:46:41 -0400804 if (likely (has_glyph_classes))
Behdad Esfahbod96c969c2022-01-12 15:06:40 -0700805 {
Behdad Esfahbod9408e0d2022-01-12 15:07:34 -0700806 props &= HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE;
807 _hb_glyph_info_set_glyph_props (&buffer->cur(), props | gdef.get_glyph_props (glyph_index));
Behdad Esfahbod96c969c2022-01-12 15:06:40 -0700808 }
Behdad Esfahbod05bd1b62012-07-30 19:30:01 -0400809 else if (class_guess)
Behdad Esfahbod96c969c2022-01-12 15:06:40 -0700810 {
Behdad Esfahbod9408e0d2022-01-12 15:07:34 -0700811 props &= HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE;
812 _hb_glyph_info_set_glyph_props (&buffer->cur(), props | class_guess);
Behdad Esfahbod96c969c2022-01-12 15:06:40 -0700813 }
814 else
Behdad Esfahbod9408e0d2022-01-12 15:07:34 -0700815 _hb_glyph_info_set_glyph_props (&buffer->cur(), props);
Behdad Esfahbod60da7632012-07-16 16:13:32 -0400816 }
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500817
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330818 void replace_glyph (hb_codepoint_t glyph_index) const
Behdad Esfahbod3ec77d62012-06-08 21:44:06 -0400819 {
Behdad Esfahbodfa12f1a2022-01-12 15:08:34 -0700820 _set_glyph_class (glyph_index);
Behdad Esfahbod3f1998a2021-03-15 13:33:44 -0600821 (void) buffer->replace_glyph (glyph_index);
Behdad Esfahbod98370e82010-10-27 17:39:01 -0400822 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330823 void replace_glyph_inplace (hb_codepoint_t glyph_index) const
Behdad Esfahbod7fbbf862012-07-30 18:36:42 -0400824 {
Behdad Esfahbodfa12f1a2022-01-12 15:08:34 -0700825 _set_glyph_class (glyph_index);
Behdad Esfahbod7fbbf862012-07-30 18:36:42 -0400826 buffer->cur().codepoint = glyph_index;
827 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330828 void replace_glyph_with_ligature (hb_codepoint_t glyph_index,
Behdad Esfahbodf4cd99f2020-04-22 14:45:57 -0700829 unsigned int class_guess) const
Behdad Esfahboda0161742013-10-18 00:06:30 +0200830 {
Behdad Esfahbodfa12f1a2022-01-12 15:08:34 -0700831 _set_glyph_class (glyph_index, class_guess, true);
Behdad Esfahbod3f1998a2021-03-15 13:33:44 -0600832 (void) buffer->replace_glyph (glyph_index);
Behdad Esfahboda0161742013-10-18 00:06:30 +0200833 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330834 void output_glyph_for_component (hb_codepoint_t glyph_index,
Behdad Esfahbodf4cd99f2020-04-22 14:45:57 -0700835 unsigned int class_guess) const
Behdad Esfahboda0161742013-10-18 00:06:30 +0200836 {
Behdad Esfahbodfa12f1a2022-01-12 15:08:34 -0700837 _set_glyph_class (glyph_index, class_guess, false, true);
Behdad Esfahbod34a12042021-03-15 14:39:06 -0600838 (void) buffer->output_glyph (glyph_index);
Behdad Esfahboda0161742013-10-18 00:06:30 +0200839 }
Behdad Esfahbod1376fb72010-04-29 02:19:21 -0400840};
841
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -0400842
Behdad Esfahbodf9b643f2022-06-04 07:29:40 -0600843struct hb_accelerate_subtables_context_t :
844 hb_dispatch_context_t<hb_accelerate_subtables_context_t>
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400845{
846 template <typename Type>
Behdad Esfahboda061e472019-12-10 13:31:50 -0600847 static inline bool apply_to (const void *obj, OT::hb_ot_apply_context_t *c)
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400848 {
849 const Type *typed_obj = (const Type *) obj;
850 return typed_obj->apply (c);
851 }
852
Behdad Esfahbod39820af2022-06-07 10:18:38 -0600853#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600854 template <typename T>
Behdad Esfahbodd4c09e92022-06-07 09:03:30 -0600855 static inline auto apply_cached_ (const T *obj, OT::hb_ot_apply_context_t *c, hb_priority<1>) HB_RETURN (bool, obj->apply (c, true) )
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600856 template <typename T>
857 static inline auto apply_cached_ (const T *obj, OT::hb_ot_apply_context_t *c, hb_priority<0>) HB_RETURN (bool, obj->apply (c) )
858 template <typename Type>
859 static inline bool apply_cached_to (const void *obj, OT::hb_ot_apply_context_t *c)
860 {
861 const Type *typed_obj = (const Type *) obj;
862 return apply_cached_ (typed_obj, c, hb_prioritize);
863 }
864
865 template <typename T>
Behdad Esfahbod5963cf42022-06-07 09:12:45 -0600866 static inline auto cache_func_ (const T *obj, OT::hb_ot_apply_context_t *c, bool enter, hb_priority<1>) HB_RETURN (bool, obj->cache_func (c, enter) )
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600867 template <typename T>
Behdad Esfahbod5963cf42022-06-07 09:12:45 -0600868 static inline bool cache_func_ (const T *obj, OT::hb_ot_apply_context_t *c, bool enter, hb_priority<0>) { return false; }
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600869 template <typename Type>
Behdad Esfahbod5963cf42022-06-07 09:12:45 -0600870 static inline bool cache_func_to (const void *obj, OT::hb_ot_apply_context_t *c, bool enter)
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600871 {
872 const Type *typed_obj = (const Type *) obj;
Behdad Esfahbod5963cf42022-06-07 09:12:45 -0600873 return cache_func_ (typed_obj, c, enter, hb_prioritize);
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600874 }
Behdad Esfahbod39820af2022-06-07 10:18:38 -0600875#endif
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600876
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400877 typedef bool (*hb_apply_func_t) (const void *obj, OT::hb_ot_apply_context_t *c);
Behdad Esfahbod5963cf42022-06-07 09:12:45 -0600878 typedef bool (*hb_cache_func_t) (const void *obj, OT::hb_ot_apply_context_t *c, bool enter);
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400879
880 struct hb_applicable_t
881 {
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600882 friend struct hb_accelerate_subtables_context_t;
883 friend struct hb_ot_layout_lookup_accelerator_t;
884
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400885 template <typename T>
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600886 void init (const T &obj_,
Behdad Esfahbod39820af2022-06-07 10:18:38 -0600887 hb_apply_func_t apply_func_
888#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
889 , hb_apply_func_t apply_cached_func_
890 , hb_cache_func_t cache_func_
891#endif
892 )
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400893 {
894 obj = &obj_;
895 apply_func = apply_func_;
Behdad Esfahbod39820af2022-06-07 10:18:38 -0600896#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600897 apply_cached_func = apply_cached_func_;
Behdad Esfahbod5963cf42022-06-07 09:12:45 -0600898 cache_func = cache_func_;
Behdad Esfahbod39820af2022-06-07 10:18:38 -0600899#endif
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400900 digest.init ();
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -0700901 obj_.get_coverage ().collect_coverage (&digest);
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400902 }
903
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330904 bool apply (OT::hb_ot_apply_context_t *c) const
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400905 {
906 return digest.may_have (c->buffer->cur().codepoint) && apply_func (obj, c);
907 }
Behdad Esfahbod39820af2022-06-07 10:18:38 -0600908#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600909 bool apply_cached (OT::hb_ot_apply_context_t *c) const
910 {
911 return digest.may_have (c->buffer->cur().codepoint) && apply_cached_func (obj, c);
912 }
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600913 bool cache_enter (OT::hb_ot_apply_context_t *c) const
914 {
Behdad Esfahbod5963cf42022-06-07 09:12:45 -0600915 return cache_func (obj, c, true);
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600916 }
917 void cache_leave (OT::hb_ot_apply_context_t *c) const
918 {
Behdad Esfahbod5963cf42022-06-07 09:12:45 -0600919 cache_func (obj, c, false);
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600920 }
Behdad Esfahbod39820af2022-06-07 10:18:38 -0600921#endif
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400922
923 private:
924 const void *obj;
925 hb_apply_func_t apply_func;
Behdad Esfahbod39820af2022-06-07 10:18:38 -0600926#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600927 hb_apply_func_t apply_cached_func;
Behdad Esfahbod5963cf42022-06-07 09:12:45 -0600928 hb_cache_func_t cache_func;
Behdad Esfahbod39820af2022-06-07 10:18:38 -0600929#endif
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400930 hb_set_digest_t digest;
931 };
932
Behdad Esfahbodfa333e32018-12-27 17:56:22 -0500933 typedef hb_vector_t<hb_applicable_t> array_t;
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400934
Behdad Esfahbod39820af2022-06-07 10:18:38 -0600935#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600936 template <typename T>
937 auto cache_cost (const T &obj, hb_priority<1>) HB_AUTO_RETURN ( obj.cache_cost () )
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600938 template <typename T>
939 auto cache_cost (const T &obj, hb_priority<0>) HB_AUTO_RETURN ( 0u )
Behdad Esfahbod39820af2022-06-07 10:18:38 -0600940#endif
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600941
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400942 /* Dispatch interface. */
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400943 template <typename T>
Behdad Esfahbodc14efb82019-05-05 09:54:58 -0700944 return_t dispatch (const T &obj)
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400945 {
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600946 hb_applicable_t entry;
947
948 entry.init (obj,
Behdad Esfahbod39820af2022-06-07 10:18:38 -0600949 apply_to<T>
950#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
951 , apply_cached_to<T>
952 , cache_func_to<T>
953#endif
954 );
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600955
956 array.push (entry);
957
Behdad Esfahbod39820af2022-06-07 10:18:38 -0600958#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
Behdad Esfahbodc8fb0482022-06-07 09:20:27 -0600959 /* Cache handling
960 *
961 * We allow one subtable from each lookup to use a cache. The assumption
962 * being that multiple subtables of the same lookup cannot use a cache
963 * because the resources they would use will collide. As such, we ask
964 * each subtable to tell us how much it costs (which a cache would avoid),
965 * and we allocate the cache opportunity to the costliest subtable.
966 */
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600967 unsigned cost = cache_cost (obj, hb_prioritize);
968 if (cost > cache_user_cost && !array.in_error ())
969 {
970 cache_user_idx = array.length - 1;
971 cache_user_cost = cost;
972 }
Behdad Esfahbod39820af2022-06-07 10:18:38 -0600973#endif
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600974
Behdad Esfahbod7df3ecf2019-05-10 20:43:26 -0700975 return hb_empty_t ();
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400976 }
Behdad Esfahbod7df3ecf2019-05-10 20:43:26 -0700977 static return_t default_return_value () { return hb_empty_t (); }
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400978
Behdad Esfahbodf9b643f2022-06-04 07:29:40 -0600979 hb_accelerate_subtables_context_t (array_t &array_) :
980 array (array_) {}
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400981
982 array_t &array;
Behdad Esfahbod39820af2022-06-07 10:18:38 -0600983
984#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600985 unsigned cache_user_idx = (unsigned) -1;
986 unsigned cache_user_cost = 0;
Behdad Esfahbod39820af2022-06-07 10:18:38 -0600987#endif
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400988};
989
990
Behdad Esfahbod8b349e12022-07-06 17:22:34 -0600991typedef bool (*intersects_func_t) (const hb_set_t *glyphs, unsigned value, const void *data);
Qunxin Liub8a58a02021-01-10 15:50:04 -0800992typedef void (*intersected_glyphs_func_t) (const hb_set_t *glyphs, const void *data, unsigned value, hb_set_t *intersected_glyphs);
Behdad Esfahbod8b349e12022-07-06 17:22:34 -0600993typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, unsigned value, const void *data);
994typedef bool (*match_func_t) (hb_glyph_info_t &info, unsigned value, const void *data);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -0400995
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400996struct ContextClosureFuncs
997{
998 intersects_func_t intersects;
Qunxin Liub8a58a02021-01-10 15:50:04 -0800999 intersected_glyphs_func_t intersected_glyphs;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001000};
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001001struct ContextCollectGlyphsFuncs
1002{
1003 collect_glyphs_func_t collect;
1004};
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001005struct ContextApplyFuncs
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001006{
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001007 match_func_t match;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001008};
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06001009struct ChainContextApplyFuncs
1010{
1011 match_func_t match[3];
1012};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001013
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001014
Behdad Esfahbod8b349e12022-07-06 17:22:34 -06001015static inline bool intersects_glyph (const hb_set_t *glyphs, unsigned value, const void *data HB_UNUSED)
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001016{
1017 return glyphs->has (value);
1018}
Behdad Esfahbod8b349e12022-07-06 17:22:34 -06001019static inline bool intersects_class (const hb_set_t *glyphs, unsigned value, const void *data)
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001020{
1021 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
1022 return class_def.intersects_class (glyphs, value);
1023}
Behdad Esfahbod8b349e12022-07-06 17:22:34 -06001024static inline bool intersects_coverage (const hb_set_t *glyphs, unsigned value, const void *data)
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001025{
Behdad Esfahbod8b349e12022-07-06 17:22:34 -06001026 Offset16To<Coverage> coverage;
1027 coverage = value;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001028 return (data+coverage).intersects (glyphs);
1029}
1030
Qunxin Liub8a58a02021-01-10 15:50:04 -08001031
1032static inline void intersected_glyph (const hb_set_t *glyphs HB_UNUSED, const void *data, unsigned value, hb_set_t *intersected_glyphs)
1033{
1034 unsigned g = reinterpret_cast<const HBUINT16 *>(data)[value];
1035 intersected_glyphs->add (g);
1036}
1037static inline void intersected_class_glyphs (const hb_set_t *glyphs, const void *data, unsigned value, hb_set_t *intersected_glyphs)
1038{
1039 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
1040 class_def.intersected_class_glyphs (glyphs, value, intersected_glyphs);
1041}
1042static inline void intersected_coverage_glyphs (const hb_set_t *glyphs, const void *data, unsigned value, hb_set_t *intersected_glyphs)
1043{
Behdad Esfahbodad28f972021-03-31 12:49:14 -06001044 Offset16To<Coverage> coverage;
Qunxin Liub8a58a02021-01-10 15:50:04 -08001045 coverage = value;
Behdad Esfahbod00dfbbc2022-07-21 11:39:32 -06001046 (data+coverage).intersect_set (*glyphs, *intersected_glyphs);
Qunxin Liub8a58a02021-01-10 15:50:04 -08001047}
1048
1049
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06001050template <typename HBUINT>
Qunxin Liu44d88cf2020-05-08 15:33:34 -07001051static inline bool array_is_subset_of (const hb_set_t *glyphs,
1052 unsigned int count,
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06001053 const HBUINT values[],
Qunxin Liu44d88cf2020-05-08 15:33:34 -07001054 intersects_func_t intersects_func,
1055 const void *intersects_data)
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001056{
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06001057 for (const auto &_ : + hb_iter (values, count))
Qunxin Liu44d88cf2020-05-08 15:33:34 -07001058 if (!intersects_func (glyphs, _, intersects_data)) return false;
1059 return true;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001060}
1061
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001062
Behdad Esfahbod8b349e12022-07-06 17:22:34 -06001063static inline void collect_glyph (hb_set_t *glyphs, unsigned value, const void *data HB_UNUSED)
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001064{
1065 glyphs->add (value);
1066}
Behdad Esfahbod8b349e12022-07-06 17:22:34 -06001067static inline void collect_class (hb_set_t *glyphs, unsigned value, const void *data)
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001068{
1069 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
Behdad Esfahbod89ad3c62020-04-23 10:57:30 -07001070 class_def.collect_class (glyphs, value);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001071}
Behdad Esfahbod8b349e12022-07-06 17:22:34 -06001072static inline void collect_coverage (hb_set_t *glyphs, unsigned value, const void *data)
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001073{
Behdad Esfahbod8b349e12022-07-06 17:22:34 -06001074 Offset16To<Coverage> coverage;
1075 coverage = value;
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07001076 (data+coverage).collect_coverage (glyphs);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001077}
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06001078template <typename HBUINT>
Behdad Esfahbod0beb66e2012-12-05 18:46:04 -05001079static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001080 hb_set_t *glyphs,
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001081 unsigned int count,
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06001082 const HBUINT values[],
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001083 collect_glyphs_func_t collect_func,
1084 const void *collect_data)
1085{
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001086 return
1087 + hb_iter (values, count)
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06001088 | hb_apply ([&] (const HBUINT &_) { collect_func (glyphs, _, collect_data); })
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001089 ;
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001090}
1091
1092
Behdad Esfahbod8b349e12022-07-06 17:22:34 -06001093static inline bool match_glyph (hb_glyph_info_t &info, unsigned value, const void *data HB_UNUSED)
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001094{
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06001095 return info.codepoint == value;
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001096}
Behdad Esfahbod8b349e12022-07-06 17:22:34 -06001097static inline bool match_class (hb_glyph_info_t &info, unsigned value, const void *data)
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001098{
Behdad Esfahbod2b5a59c2009-08-04 11:38:50 -04001099 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06001100 return class_def.get_class (info.codepoint) == value;
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001101}
Behdad Esfahbod8b349e12022-07-06 17:22:34 -06001102static inline bool match_class_cached (hb_glyph_info_t &info, unsigned value, const void *data)
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06001103{
1104 unsigned klass = info.syllable();
1105 if (klass < 255)
1106 return klass == value;
1107 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
1108 klass = class_def.get_class (info.codepoint);
1109 if (likely (klass < 255))
1110 info.syllable() = klass;
1111 return klass == value;
1112}
Behdad Esfahbod8b349e12022-07-06 17:22:34 -06001113static inline bool match_coverage (hb_glyph_info_t &info, unsigned value, const void *data)
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001114{
Behdad Esfahbod8b349e12022-07-06 17:22:34 -06001115 Offset16To<Coverage> coverage;
1116 coverage = value;
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06001117 return (data+coverage).get_coverage (info.codepoint) != NOT_COVERED;
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001118}
1119
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06001120template <typename HBUINT>
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001121static inline bool would_match_input (hb_would_apply_context_t *c,
1122 unsigned int count, /* Including the first glyph (not matched) */
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06001123 const HBUINT input[], /* Array of input values--start with second glyph */
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001124 match_func_t match_func,
1125 const void *match_data)
1126{
1127 if (count != c->len)
1128 return false;
1129
1130 for (unsigned int i = 1; i < count; i++)
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06001131 {
1132 hb_glyph_info_t info;
1133 info.codepoint = c->glyphs[i];
1134 if (likely (!match_func (info, input[i - 1], match_data)))
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001135 return false;
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06001136 }
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001137
1138 return true;
1139}
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06001140template <typename HBUINT>
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001141static inline bool match_input (hb_ot_apply_context_t *c,
Behdad Esfahbode072c242009-05-18 03:47:31 -04001142 unsigned int count, /* Including the first glyph (not matched) */
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06001143 const HBUINT input[], /* Array of input values--start with second glyph */
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001144 match_func_t match_func,
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04001145 const void *match_data,
Behdad Esfahbod78481b32021-11-21 16:50:34 -07001146 unsigned int *end_position,
Behdad Esfahbod5ba45042015-11-02 15:43:08 -08001147 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001148 unsigned int *p_total_component_count = nullptr)
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001149{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001150 TRACE_APPLY (nullptr);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -04001151
Behdad Esfahbod5ba45042015-11-02 15:43:08 -08001152 if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return_trace (false);
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001153
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +02001154 hb_buffer_t *buffer = c->buffer;
1155
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001156 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
Behdad Esfahbodb051be52015-01-29 13:40:39 +01001157 skippy_iter.reset (buffer->idx, count - 1);
Behdad Esfahbodf114b182022-07-06 17:31:46 -06001158 skippy_iter.set_match_func (match_func, match_data);
1159 skippy_iter.set_glyph_data (input);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -04001160
Behdad Esfahbod191fa882012-08-28 22:58:55 -04001161 /*
1162 * This is perhaps the trickiest part of OpenType... Remarks:
1163 *
1164 * - If all components of the ligature were marks, we call this a mark ligature.
1165 *
1166 * - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize
1167 * it as a ligature glyph.
1168 *
1169 * - Ligatures cannot be formed across glyphs attached to different components
1170 * of previous ligatures. Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and
1171 * LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother.
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +02001172 * However, it would be wrong to ligate that SHADDA,FATHA sequence.
1173 * There are a couple of exceptions to this:
1174 *
1175 * o If a ligature tries ligating with marks that belong to it itself, go ahead,
1176 * assuming that the font designer knows what they are doing (otherwise it can
1177 * break Indic stuff when a matra wants to ligate with a conjunct,
1178 *
1179 * o If two marks want to ligate and they belong to different components of the
1180 * same ligature glyph, and said ligature glyph is to be ignored according to
1181 * mark-filtering rules, then allow.
ebraminio7c6937e2017-11-20 14:49:22 -05001182 * https://github.com/harfbuzz/harfbuzz/issues/545
Behdad Esfahbod191fa882012-08-28 22:58:55 -04001183 */
1184
Behdad Esfahbod93814ca2012-08-28 22:24:51 -04001185 unsigned int total_component_count = 0;
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +02001186 total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur());
Behdad Esfahbod93814ca2012-08-28 22:24:51 -04001187
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +02001188 unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
1189 unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001190
Behdad Esfahbod621c49c2017-10-04 15:06:48 +02001191 enum {
1192 LIGBASE_NOT_CHECKED,
1193 LIGBASE_MAY_NOT_SKIP,
1194 LIGBASE_MAY_SKIP
1195 } ligbase = LIGBASE_NOT_CHECKED;
1196
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +02001197 match_positions[0] = buffer->idx;
Behdad Esfahbod370f03e2012-01-16 17:03:55 -05001198 for (unsigned int i = 1; i < count; i++)
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001199 {
Behdad Esfahbod3122c2c2021-12-04 19:50:33 -08001200 unsigned unsafe_to;
1201 if (!skippy_iter.next (&unsafe_to))
1202 {
Behdad Esfahbod78481b32021-11-21 16:50:34 -07001203 *end_position = unsafe_to;
Behdad Esfahbod3122c2c2021-12-04 19:50:33 -08001204 return_trace (false);
1205 }
Behdad Esfahbod6cc136f2013-10-17 13:55:48 +02001206
1207 match_positions[i] = skippy_iter.idx;
Behdad Esfahbod93814ca2012-08-28 22:24:51 -04001208
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +02001209 unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]);
1210 unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -04001211
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +02001212 if (first_lig_id && first_lig_comp)
1213 {
Behdad Esfahbod93814ca2012-08-28 22:24:51 -04001214 /* If first component was attached to a previous ligature component,
1215 * all subsequent components should be attached to the same ligature
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +02001216 * component, otherwise we shouldn't ligate them... */
Behdad Esfahbod93814ca2012-08-28 22:24:51 -04001217 if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +02001218 {
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03301219 /* ...unless, we are attached to a base ligature and that base
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +02001220 * ligature is ignorable. */
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03301221 if (ligbase == LIGBASE_NOT_CHECKED)
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +02001222 {
Behdad Esfahbod621c49c2017-10-04 15:06:48 +02001223 bool found = false;
Behdad Esfahbod4d677432019-05-10 16:35:31 -07001224 const auto *out = buffer->out_info;
Behdad Esfahbod621c49c2017-10-04 15:06:48 +02001225 unsigned int j = buffer->out_len;
1226 while (j && _hb_glyph_info_get_lig_id (&out[j - 1]) == first_lig_id)
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +02001227 {
Behdad Esfahbod621c49c2017-10-04 15:06:48 +02001228 if (_hb_glyph_info_get_lig_comp (&out[j - 1]) == 0)
1229 {
1230 j--;
1231 found = true;
1232 break;
1233 }
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +02001234 j--;
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +02001235 }
Behdad Esfahbod621c49c2017-10-04 15:06:48 +02001236
Behdad Esfahbod12757b62018-01-26 18:14:05 -08001237 if (found && skippy_iter.may_skip (out[j]) == hb_ot_apply_context_t::matcher_t::SKIP_YES)
Behdad Esfahbod621c49c2017-10-04 15:06:48 +02001238 ligbase = LIGBASE_MAY_SKIP;
1239 else
1240 ligbase = LIGBASE_MAY_NOT_SKIP;
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +02001241 }
1242
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03301243 if (ligbase == LIGBASE_MAY_NOT_SKIP)
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +02001244 return_trace (false);
1245 }
1246 }
1247 else
Behdad Esfahbod621c49c2017-10-04 15:06:48 +02001248 {
Behdad Esfahbod93814ca2012-08-28 22:24:51 -04001249 /* If first component was NOT attached to a previous ligature component,
1250 * all subsequent components should also NOT be attached to any ligature
1251 * component, unless they are attached to the first component itself! */
1252 if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id))
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001253 return_trace (false);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -04001254 }
1255
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +02001256 total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001257 }
1258
Behdad Esfahbod78481b32021-11-21 16:50:34 -07001259 *end_position = skippy_iter.idx + 1;
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001260
Behdad Esfahbod191fa882012-08-28 22:58:55 -04001261 if (p_total_component_count)
1262 *p_total_component_count = total_component_count;
1263
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001264 return_trace (true);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001265}
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001266static inline bool ligate_input (hb_ot_apply_context_t *c,
Behdad Esfahbode714fe62013-10-17 13:49:51 +02001267 unsigned int count, /* Including the first glyph */
Bruce Mitchener5a24ea12018-10-20 08:09:52 +07001268 const unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
Behdad Esfahbod78481b32021-11-21 16:50:34 -07001269 unsigned int match_end,
Behdad Esfahboda177d022012-08-28 23:18:22 -04001270 hb_codepoint_t lig_glyph,
Behdad Esfahboda177d022012-08-28 23:18:22 -04001271 unsigned int total_component_count)
1272{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001273 TRACE_APPLY (nullptr);
Behdad Esfahbode714fe62013-10-17 13:49:51 +02001274
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +02001275 hb_buffer_t *buffer = c->buffer;
1276
Behdad Esfahbod78481b32021-11-21 16:50:34 -07001277 buffer->merge_clusters (buffer->idx, match_end);
Behdad Esfahbod607feb72013-02-14 07:43:13 -05001278
Behdad Esfahbod9efddb92018-10-02 16:05:26 +02001279 /* - If a base and one or more marks ligate, consider that as a base, NOT
1280 * ligature, such that all following marks can still attach to it.
1281 * https://github.com/harfbuzz/harfbuzz/issues/1109
1282 *
1283 * - If all components of the ligature were marks, we call this a mark ligature.
Behdad Esfahbod3cca9782018-10-02 15:02:16 +02001284 * If it *is* a mark ligature, we don't allocate a new ligature id, and leave
Behdad Esfahboda177d022012-08-28 23:18:22 -04001285 * the ligature to keep its old ligature id. This will allow it to attach to
1286 * a base ligature in GPOS. Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH,
Behdad Esfahbod3cca9782018-10-02 15:02:16 +02001287 * and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA with a
Behdad Esfahboda177d022012-08-28 23:18:22 -04001288 * ligature id and component value of 2. Then if SHADDA,FATHA form a ligature
1289 * later, we don't want them to lose their ligature id/component, otherwise
1290 * GPOS will fail to correctly position the mark ligature on top of the
1291 * LAM,LAM,HEH ligature. See:
1292 * https://bugzilla.gnome.org/show_bug.cgi?id=676343
1293 *
1294 * - If a ligature is formed of components that some of which are also ligatures
1295 * themselves, and those ligature components had marks attached to *their*
1296 * components, we have to attach the marks to the new ligature component
1297 * positions! Now *that*'s tricky! And these marks may be following the
1298 * last component of the whole sequence, so we should loop forward looking
1299 * for them and update them.
1300 *
1301 * Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a
1302 * 'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature
1303 * id and component == 1. Now, during 'liga', the LAM and the LAM-HEH ligature
1304 * form a LAM-LAM-HEH ligature. We need to reassign the SHADDA and FATHA to
1305 * the new ligature with a component value of 2.
1306 *
1307 * This in fact happened to a font... See:
1308 * https://bugzilla.gnome.org/show_bug.cgi?id=437633
1309 */
1310
Behdad Esfahbod9efddb92018-10-02 16:05:26 +02001311 bool is_base_ligature = _hb_glyph_info_is_base_glyph (&buffer->info[match_positions[0]]);
1312 bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->info[match_positions[0]]);
1313 for (unsigned int i = 1; i < count; i++)
Behdad Esfahbod3cca9782018-10-02 15:02:16 +02001314 if (!_hb_glyph_info_is_mark (&buffer->info[match_positions[i]]))
1315 {
Behdad Esfahbod9efddb92018-10-02 16:05:26 +02001316 is_base_ligature = false;
Behdad Esfahbod3cca9782018-10-02 15:02:16 +02001317 is_mark_ligature = false;
1318 break;
1319 }
Behdad Esfahbod9efddb92018-10-02 16:05:26 +02001320 bool is_ligature = !is_base_ligature && !is_mark_ligature;
Behdad Esfahbod3cca9782018-10-02 15:02:16 +02001321
Behdad Esfahbod9efddb92018-10-02 16:05:26 +02001322 unsigned int klass = is_ligature ? HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE : 0;
1323 unsigned int lig_id = is_ligature ? _hb_allocate_lig_id (buffer) : 0;
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +02001324 unsigned int last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
1325 unsigned int last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
Behdad Esfahboda177d022012-08-28 23:18:22 -04001326 unsigned int components_so_far = last_num_components;
1327
Behdad Esfahbod9efddb92018-10-02 16:05:26 +02001328 if (is_ligature)
Behdad Esfahbod7e08f122013-05-27 14:48:34 -04001329 {
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +02001330 _hb_glyph_info_set_lig_props_for_ligature (&buffer->cur(), lig_id, total_component_count);
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +02001331 if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
Behdad Esfahbod3d436d32013-10-28 21:00:37 +01001332 {
Behdad Esfahbod82596692015-11-02 17:44:05 -08001333 _hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER);
Behdad Esfahbod3d436d32013-10-28 21:00:37 +01001334 }
Behdad Esfahbod7e08f122013-05-27 14:48:34 -04001335 }
Behdad Esfahboda0161742013-10-18 00:06:30 +02001336 c->replace_glyph_with_ligature (lig_glyph, klass);
Behdad Esfahboda177d022012-08-28 23:18:22 -04001337
1338 for (unsigned int i = 1; i < count; i++)
1339 {
Behdad Esfahbod7185b272018-05-31 20:03:00 -07001340 while (buffer->idx < match_positions[i] && buffer->successful)
Behdad Esfahboda177d022012-08-28 23:18:22 -04001341 {
Behdad Esfahbod9efddb92018-10-02 16:05:26 +02001342 if (is_ligature)
1343 {
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03301344 unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
Behdad Esfahbod2f02fc72015-12-17 15:21:14 +00001345 if (this_comp == 0)
Behdad Esfahbod100fbea2015-12-17 15:23:09 +00001346 this_comp = last_num_components;
Behdad Esfahboda177d022012-08-28 23:18:22 -04001347 unsigned int new_lig_comp = components_so_far - last_num_components +
Behdad Esfahbod41248cc2019-05-07 20:54:31 -07001348 hb_min (this_comp, last_num_components);
Behdad Esfahbod2f02fc72015-12-17 15:21:14 +00001349 _hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
Behdad Esfahboda177d022012-08-28 23:18:22 -04001350 }
Behdad Esfahbod8450f432021-03-15 15:18:06 -06001351 (void) buffer->next_glyph ();
Behdad Esfahboda177d022012-08-28 23:18:22 -04001352 }
1353
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +02001354 last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
1355 last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
Behdad Esfahboda177d022012-08-28 23:18:22 -04001356 components_so_far += last_num_components;
1357
1358 /* Skip the base glyph */
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +02001359 buffer->idx++;
Behdad Esfahboda177d022012-08-28 23:18:22 -04001360 }
1361
Ebrahim Byagowicc977b62020-03-26 11:18:02 +04301362 if (!is_mark_ligature && last_lig_id)
1363 {
Behdad Esfahboda177d022012-08-28 23:18:22 -04001364 /* Re-adjust components for any marks following. */
Ebrahim Byagowicc977b62020-03-26 11:18:02 +04301365 for (unsigned i = buffer->idx; i < buffer->len; ++i)
1366 {
1367 if (last_lig_id != _hb_glyph_info_get_lig_id (&buffer->info[i])) break;
1368
1369 unsigned this_comp = _hb_glyph_info_get_lig_comp (&buffer->info[i]);
1370 if (!this_comp) break;
1371
1372 unsigned new_lig_comp = components_so_far - last_num_components +
1373 hb_min (this_comp, last_num_components);
1374 _hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
Behdad Esfahboda177d022012-08-28 23:18:22 -04001375 }
1376 }
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001377 return_trace (true);
Behdad Esfahboda177d022012-08-28 23:18:22 -04001378}
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001379
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06001380template <typename HBUINT>
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001381static inline bool match_backtrack (hb_ot_apply_context_t *c,
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001382 unsigned int count,
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06001383 const HBUINT backtrack[],
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001384 match_func_t match_func,
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001385 const void *match_data,
1386 unsigned int *match_start)
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001387{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001388 TRACE_APPLY (nullptr);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -04001389
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001390 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
Behdad Esfahbodb051be52015-01-29 13:40:39 +01001391 skippy_iter.reset (c->buffer->backtrack_len (), count);
Behdad Esfahbodf114b182022-07-06 17:31:46 -06001392 skippy_iter.set_match_func (match_func, match_data);
1393 skippy_iter.set_glyph_data (backtrack);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001394
Behdad Esfahbod4d3aeb82012-01-16 16:43:26 -05001395 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod3122c2c2021-12-04 19:50:33 -08001396 {
1397 unsigned unsafe_from;
1398 if (!skippy_iter.prev (&unsafe_from))
1399 {
Behdad Esfahbod78481b32021-11-21 16:50:34 -07001400 *match_start = unsafe_from;
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001401 return_trace (false);
Behdad Esfahbod3122c2c2021-12-04 19:50:33 -08001402 }
1403 }
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001404
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001405 *match_start = skippy_iter.idx;
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001406 return_trace (true);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001407}
1408
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06001409template <typename HBUINT>
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001410static inline bool match_lookahead (hb_ot_apply_context_t *c,
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001411 unsigned int count,
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06001412 const HBUINT lookahead[],
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001413 match_func_t match_func,
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04001414 const void *match_data,
Behdad Esfahbod78481b32021-11-21 16:50:34 -07001415 unsigned int start_index,
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001416 unsigned int *end_index)
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001417{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001418 TRACE_APPLY (nullptr);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -04001419
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001420 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
Behdad Esfahbod78481b32021-11-21 16:50:34 -07001421 skippy_iter.reset (start_index - 1, count);
Behdad Esfahbodf114b182022-07-06 17:31:46 -06001422 skippy_iter.set_match_func (match_func, match_data);
1423 skippy_iter.set_glyph_data (lookahead);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001424
Behdad Esfahbod370f03e2012-01-16 17:03:55 -05001425 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod3122c2c2021-12-04 19:50:33 -08001426 {
1427 unsigned unsafe_to;
1428 if (!skippy_iter.next (&unsafe_to))
1429 {
Behdad Esfahbod78481b32021-11-21 16:50:34 -07001430 *end_index = unsafe_to;
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001431 return_trace (false);
Behdad Esfahbod3122c2c2021-12-04 19:50:33 -08001432 }
1433 }
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001434
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001435 *end_index = skippy_iter.idx + 1;
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001436 return_trace (true);
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001437}
1438
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04001439
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001440
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001441struct LookupRecord
1442{
Qunxin Liu36ed56b2021-09-23 10:51:21 -07001443 bool serialize (hb_serialize_context_t *c,
1444 const hb_map_t *lookup_map) const
Qunxin Liu0b39c482019-10-22 16:00:43 -07001445 {
1446 TRACE_SERIALIZE (this);
1447 auto *out = c->embed (*this);
Qunxin Liu36ed56b2021-09-23 10:51:21 -07001448 if (unlikely (!out)) return_trace (false);
Qunxin Liu0b39c482019-10-22 16:00:43 -07001449
Qunxin Liu36ed56b2021-09-23 10:51:21 -07001450 return_trace (c->check_assign (out->lookupListIndex, lookup_map->get (lookupListIndex), HB_SERIALIZE_ERROR_INT_OVERFLOW));
Qunxin Liu0b39c482019-10-22 16:00:43 -07001451 }
1452
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301453 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001454 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001455 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001456 return_trace (c->check_struct (this));
Behdad Esfahbodcd3827e2009-08-04 02:09:34 -04001457 }
1458
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001459 HBUINT16 sequenceIndex; /* Index into current glyph
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001460 * sequence--first glyph = 0 */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001461 HBUINT16 lookupListIndex; /* Lookup to apply to that
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001462 * position--zero--based */
Behdad Esfahbod569da922010-05-10 16:38:32 -04001463 public:
1464 DEFINE_SIZE_STATIC (4);
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001465};
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001466
Qunxin Liu36ed56b2021-09-23 10:51:21 -07001467static unsigned serialize_lookuprecord_array (hb_serialize_context_t *c,
1468 const hb_array_t<const LookupRecord> lookupRecords,
1469 const hb_map_t *lookup_map)
1470{
1471 unsigned count = 0;
1472 for (const LookupRecord& r : lookupRecords)
1473 {
1474 if (!lookup_map->has (r.lookupListIndex))
1475 continue;
1476
1477 if (!r.serialize (c, lookup_map))
1478 return 0;
1479
1480 count++;
1481 }
1482 return count;
1483}
1484
Qunxin Liub8a58a02021-01-10 15:50:04 -08001485enum ContextFormat { SimpleContext = 1, ClassBasedContext = 2, CoverageBasedContext = 3 };
1486
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06001487template <typename HBUINT>
Qunxin Liub8a58a02021-01-10 15:50:04 -08001488static void context_closure_recurse_lookups (hb_closure_context_t *c,
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06001489 unsigned inputCount, const HBUINT input[],
Qunxin Liub8a58a02021-01-10 15:50:04 -08001490 unsigned lookupCount,
1491 const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */,
1492 unsigned value,
1493 ContextFormat context_format,
1494 const void *data,
1495 intersected_glyphs_func_t intersected_glyphs_func)
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001496{
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08001497 hb_set_t *covered_seq_indicies = hb_set_create ();
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001498 for (unsigned int i = 0; i < lookupCount; i++)
Qunxin Liub8a58a02021-01-10 15:50:04 -08001499 {
1500 unsigned seqIndex = lookupRecord[i].sequenceIndex;
Garret Riegeradca4ce2021-03-30 13:20:50 -07001501 if (seqIndex >= inputCount) continue;
Qunxin Liub8a58a02021-01-10 15:50:04 -08001502
Garret Riegerf3c1f4f2022-01-28 11:50:22 -08001503 bool has_pos_glyphs = false;
1504 hb_set_t pos_glyphs;
Qunxin Liub8a58a02021-01-10 15:50:04 -08001505
Behdad Esfahbod202e6c42022-05-18 17:12:43 -06001506 if (!hb_set_has (covered_seq_indicies, seqIndex))
Qunxin Liub8a58a02021-01-10 15:50:04 -08001507 {
Garret Riegerf3c1f4f2022-01-28 11:50:22 -08001508 has_pos_glyphs = true;
Qunxin Liub8a58a02021-01-10 15:50:04 -08001509 if (seqIndex == 0)
1510 {
1511 switch (context_format) {
1512 case ContextFormat::SimpleContext:
Garret Riegerf3c1f4f2022-01-28 11:50:22 -08001513 pos_glyphs.add (value);
Qunxin Liub8a58a02021-01-10 15:50:04 -08001514 break;
1515 case ContextFormat::ClassBasedContext:
Garret Riegerbc899652022-01-28 13:54:10 -08001516 intersected_glyphs_func (&c->parent_active_glyphs (), data, value, &pos_glyphs);
Qunxin Liub8a58a02021-01-10 15:50:04 -08001517 break;
1518 case ContextFormat::CoverageBasedContext:
Garret Riegerbc899652022-01-28 13:54:10 -08001519 pos_glyphs.set (c->parent_active_glyphs ());
Qunxin Liub8a58a02021-01-10 15:50:04 -08001520 break;
1521 }
1522 }
1523 else
1524 {
1525 const void *input_data = input;
1526 unsigned input_value = seqIndex - 1;
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08001527 if (context_format != ContextFormat::SimpleContext)
Qunxin Liub8a58a02021-01-10 15:50:04 -08001528 {
1529 input_data = data;
1530 input_value = input[seqIndex - 1];
1531 }
Garret Riegerc6adb902021-03-29 16:08:44 -07001532
Garret Riegerf3c1f4f2022-01-28 11:50:22 -08001533 intersected_glyphs_func (c->glyphs, input_data, input_value, &pos_glyphs);
Qunxin Liub8a58a02021-01-10 15:50:04 -08001534 }
1535 }
1536
Garret Riegerf3c1f4f2022-01-28 11:50:22 -08001537 covered_seq_indicies->add (seqIndex);
1538 if (has_pos_glyphs) {
Behdad Esfahbod4cfc2d62022-05-18 15:32:19 -06001539 c->push_cur_active_glyphs () = std::move (pos_glyphs);
Garret Riegerf3c1f4f2022-01-28 11:50:22 -08001540 } else {
1541 c->push_cur_active_glyphs ().set (*c->glyphs);
1542 }
Garret Riegerc6adb902021-03-29 16:08:44 -07001543
Qunxin Liub8a58a02021-01-10 15:50:04 -08001544 unsigned endIndex = inputCount;
1545 if (context_format == ContextFormat::CoverageBasedContext)
1546 endIndex += 1;
1547
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08001548 c->recurse (lookupRecord[i].lookupListIndex, covered_seq_indicies, seqIndex, endIndex);
Garret Riegerc6adb902021-03-29 16:08:44 -07001549
Qunxin Liu706014f2021-12-01 20:20:12 -08001550 c->pop_cur_done_glyphs ();
Qunxin Liub8a58a02021-01-10 15:50:04 -08001551 }
Qunxin Liub4fc5932020-12-09 10:44:18 -08001552
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08001553 hb_set_destroy (covered_seq_indicies);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001554}
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04001555
Qunxin Liub8a58a02021-01-10 15:50:04 -08001556template <typename context_t>
1557static inline void recurse_lookups (context_t *c,
1558 unsigned int lookupCount,
1559 const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
1560{
1561 for (unsigned int i = 0; i < lookupCount; i++)
1562 c->recurse (lookupRecord[i].lookupListIndex);
1563}
1564
Behdad Esfahbod78481b32021-11-21 16:50:34 -07001565static inline void apply_lookup (hb_ot_apply_context_t *c,
Behdad Esfahbode072c242009-05-18 03:47:31 -04001566 unsigned int count, /* Including the first glyph */
Behdad Esfahbod5ba45042015-11-02 15:43:08 -08001567 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
Behdad Esfahbode072c242009-05-18 03:47:31 -04001568 unsigned int lookupCount,
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001569 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
Behdad Esfahbod78481b32021-11-21 16:50:34 -07001570 unsigned int match_end)
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001571{
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001572 hb_buffer_t *buffer = c->buffer;
jfkthame44f7d6e2017-02-17 03:03:24 +00001573 int end;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001574
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001575 /* All positions are distance from beginning of *output* buffer.
1576 * Adjust. */
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001577 {
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001578 unsigned int bl = buffer->backtrack_len ();
Behdad Esfahbod78481b32021-11-21 16:50:34 -07001579 end = bl + match_end - buffer->idx;
Behdad Esfahbod8751de52013-07-18 16:29:50 -04001580
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001581 int delta = bl - buffer->idx;
1582 /* Convert positions to new indexing. */
1583 for (unsigned int j = 0; j < count; j++)
1584 match_positions[j] += delta;
Behdad Esfahbod8820bb22013-02-14 07:41:03 -05001585 }
Behdad Esfahbode73a0c22009-05-18 04:15:25 -04001586
Behdad Esfahbod7185b272018-05-31 20:03:00 -07001587 for (unsigned int i = 0; i < lookupCount && buffer->successful; i++)
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001588 {
1589 unsigned int idx = lookupRecord[i].sequenceIndex;
1590 if (idx >= count)
1591 continue;
1592
Behdad Esfahbodccd91612022-03-24 13:10:48 -06001593 unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
1594
1595 /* This can happen if earlier recursed lookups deleted many entries. */
1596 if (unlikely (match_positions[idx] >= orig_len))
1597 continue;
1598
Behdad Esfahbode5930722017-11-14 15:47:55 -08001599 if (unlikely (!buffer->move_to (match_positions[idx])))
1600 break;
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001601
Behdad Esfahbodbaf77792017-11-14 21:53:48 -08001602 if (unlikely (buffer->max_ops <= 0))
1603 break;
1604
Behdad Esfahbodbc80e4b2022-07-24 18:48:38 -06001605 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
1606 {
1607 if (buffer->have_output)
1608 c->buffer->sync_so_far ();
1609 c->buffer->message (c->font,
1610 "recursing to lookup %u at %d",
1611 (unsigned) lookupRecord[i].lookupListIndex,
1612 buffer->idx);
1613 }
1614
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001615 if (!c->recurse (lookupRecord[i].lookupListIndex))
1616 continue;
1617
Behdad Esfahbodbc80e4b2022-07-24 18:48:38 -06001618 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
1619 {
1620 if (buffer->have_output)
1621 c->buffer->sync_so_far ();
1622 c->buffer->message (c->font,
Behdad Esfahbod94de3282022-07-24 18:51:55 -06001623 "recursed to lookup %u",
1624 (unsigned) lookupRecord[i].lookupListIndex);
Behdad Esfahbodbc80e4b2022-07-24 18:48:38 -06001625 }
1626
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001627 unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len ();
1628 int delta = new_len - orig_len;
1629
1630 if (!delta)
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03301631 continue;
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001632
Behdad Esfahbod9ac9af72017-03-05 13:51:01 -08001633 /* Recursed lookup changed buffer len. Adjust.
1634 *
1635 * TODO:
1636 *
1637 * Right now, if buffer length increased by n, we assume n new glyphs
1638 * were added right after the current position, and if buffer length
1639 * was decreased by n, we assume n match positions after the current
1640 * one where removed. The former (buffer length increased) case is
1641 * fine, but the decrease case can be improved in at least two ways,
1642 * both of which are significant:
1643 *
1644 * - If recursed-to lookup is MultipleSubst and buffer length
1645 * decreased, then it's current match position that was deleted,
1646 * NOT the one after it.
1647 *
1648 * - If buffer length was decreased by n, it does not necessarily
Behdad Esfahboda85461b2022-04-20 12:13:16 -06001649 * mean that n match positions where removed, as there recursed-to
1650 * lookup might had a different LookupFlag. Here's a constructed
1651 * case of that:
1652 * https://github.com/harfbuzz/harfbuzz/discussions/3538
Behdad Esfahbod9ac9af72017-03-05 13:51:01 -08001653 *
1654 * It should be possible to construct tests for both of these cases.
1655 */
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001656
jfkthame44f7d6e2017-02-17 03:03:24 +00001657 end += delta;
Behdad Esfahbodccd91612022-03-24 13:10:48 -06001658 if (end < int (match_positions[idx]))
Behdad Esfahbod359dead2016-05-06 16:19:19 +01001659 {
Behdad Esfahbod4b4a1b92016-12-21 23:10:43 -06001660 /* End might end up being smaller than match_positions[idx] if the recursed
Behdad Esfahbodccd91612022-03-24 13:10:48 -06001661 * lookup ended up removing many items.
1662 * Just never rewind end beyond start of current position, since that is
1663 * not possible in the recursed lookup. Also adjust delta as such.
1664 *
1665 * https://bugs.chromium.org/p/chromium/issues/detail?id=659496
1666 * https://github.com/harfbuzz/harfbuzz/issues/1611
1667 */
1668 delta += match_positions[idx] - end;
Behdad Esfahbod4b4a1b92016-12-21 23:10:43 -06001669 end = match_positions[idx];
Behdad Esfahbod359dead2016-05-06 16:19:19 +01001670 }
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001671
1672 unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */
1673
1674 if (delta > 0)
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001675 {
Behdad Esfahbod5ba45042015-11-02 15:43:08 -08001676 if (unlikely (delta + count > HB_MAX_CONTEXT_LENGTH))
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001677 break;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001678 }
1679 else
1680 {
Behdad Esfahbodbf2a8452022-03-24 13:09:53 -06001681 /* NOTE: delta is non-positive. */
Behdad Esfahbod41248cc2019-05-07 20:54:31 -07001682 delta = hb_max (delta, (int) next - (int) count);
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001683 next -= delta;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001684 }
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001685
1686 /* Shift! */
1687 memmove (match_positions + next + delta, match_positions + next,
1688 (count - next) * sizeof (match_positions[0]));
1689 next += delta;
1690 count += delta;
1691
1692 /* Fill in new entries. */
1693 for (unsigned int j = idx + 1; j < next; j++)
1694 match_positions[j] = match_positions[j - 1] + 1;
1695
1696 /* And fixup the rest. */
1697 for (; next < count; next++)
1698 match_positions[next] += delta;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001699 }
1700
Behdad Esfahbodcac6c862021-03-15 13:46:54 -06001701 (void) buffer->move_to (end);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001702}
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001703
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04001704
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001705
1706/* Contextual lookups */
1707
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001708struct ContextClosureLookupContext
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001709{
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001710 ContextClosureFuncs funcs;
Qunxin Liub8a58a02021-01-10 15:50:04 -08001711 ContextFormat context_format;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001712 const void *intersects_data;
1713};
1714
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001715struct ContextCollectGlyphsLookupContext
1716{
1717 ContextCollectGlyphsFuncs funcs;
1718 const void *collect_data;
1719};
1720
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001721struct ContextApplyLookupContext
1722{
1723 ContextApplyFuncs funcs;
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04001724 const void *match_data;
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001725};
1726
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06001727template <typename HBUINT>
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001728static inline bool context_intersects (const hb_set_t *glyphs,
1729 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06001730 const HBUINT input[], /* Array of input values--start with second glyph */
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001731 ContextClosureLookupContext &lookup_context)
1732{
Qunxin Liu44d88cf2020-05-08 15:33:34 -07001733 return array_is_subset_of (glyphs,
1734 inputCount ? inputCount - 1 : 0, input,
1735 lookup_context.funcs.intersects, lookup_context.intersects_data);
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001736}
1737
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06001738template <typename HBUINT>
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001739static inline void context_closure_lookup (hb_closure_context_t *c,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001740 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06001741 const HBUINT input[], /* Array of input values--start with second glyph */
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001742 unsigned int lookupCount,
1743 const LookupRecord lookupRecord[],
Qunxin Liub8a58a02021-01-10 15:50:04 -08001744 unsigned value, /* Index of first glyph in Coverage or Class value in ClassDef table */
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001745 ContextClosureLookupContext &lookup_context)
1746{
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001747 if (context_intersects (c->glyphs,
1748 inputCount, input,
1749 lookup_context))
Qunxin Liub8a58a02021-01-10 15:50:04 -08001750 context_closure_recurse_lookups (c,
1751 inputCount, input,
1752 lookupCount, lookupRecord,
1753 value,
1754 lookup_context.context_format,
1755 lookup_context.intersects_data,
1756 lookup_context.funcs.intersected_glyphs);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001757}
1758
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06001759template <typename HBUINT>
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001760static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
1761 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06001762 const HBUINT input[], /* Array of input values--start with second glyph */
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001763 unsigned int lookupCount,
1764 const LookupRecord lookupRecord[],
1765 ContextCollectGlyphsLookupContext &lookup_context)
1766{
Behdad Esfahbod83035932012-12-04 17:08:41 -05001767 collect_array (c, c->input,
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001768 inputCount ? inputCount - 1 : 0, input,
1769 lookup_context.funcs.collect, lookup_context.collect_data);
1770 recurse_lookups (c,
1771 lookupCount, lookupRecord);
1772}
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001773
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06001774template <typename HBUINT>
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001775static inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
1776 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06001777 const HBUINT input[], /* Array of input values--start with second glyph */
Behdad Esfahbod0beb66e2012-12-05 18:46:04 -05001778 unsigned int lookupCount HB_UNUSED,
1779 const LookupRecord lookupRecord[] HB_UNUSED,
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001780 ContextApplyLookupContext &lookup_context)
1781{
1782 return would_match_input (c,
1783 inputCount, input,
1784 lookup_context.funcs.match, lookup_context.match_data);
1785}
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06001786
1787template <typename HBUINT>
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001788static inline bool context_apply_lookup (hb_ot_apply_context_t *c,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001789 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06001790 const HBUINT input[], /* Array of input values--start with second glyph */
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001791 unsigned int lookupCount,
1792 const LookupRecord lookupRecord[],
1793 ContextApplyLookupContext &lookup_context)
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001794{
Behdad Esfahbod78481b32021-11-21 16:50:34 -07001795 unsigned match_end = 0;
1796 unsigned match_positions[HB_MAX_CONTEXT_LENGTH];
1797 if (match_input (c,
1798 inputCount, input,
1799 lookup_context.funcs.match, lookup_context.match_data,
1800 &match_end, match_positions))
1801 {
1802 c->buffer->unsafe_to_break (c->buffer->idx, match_end);
1803 apply_lookup (c,
1804 inputCount, match_positions,
1805 lookupCount, lookupRecord,
1806 match_end);
1807 return true;
1808 }
1809 else
1810 {
1811 c->buffer->unsafe_to_concat (c->buffer->idx, match_end);
1812 return false;
1813 }
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001814}
1815
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06001816template <typename Types>
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001817struct Rule
1818{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301819 bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001820 {
1821 return context_intersects (glyphs,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001822 inputCount, inputZ.arrayZ,
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001823 lookup_context);
1824 }
1825
Qunxin Liub8a58a02021-01-10 15:50:04 -08001826 void closure (hb_closure_context_t *c, unsigned value, ContextClosureLookupContext &lookup_context) const
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001827 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04301828 if (unlikely (c->lookup_limit_exceeded ())) return;
Garret Rieger014e0382020-03-31 16:29:29 -07001829
Behdad Esfahbod51922942022-07-08 14:00:24 -06001830 const auto &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
1831 (inputZ.as_array ((inputCount ? inputCount - 1 : 0)));
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001832 context_closure_lookup (c,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001833 inputCount, inputZ.arrayZ,
1834 lookupCount, lookupRecord.arrayZ,
Qunxin Liub8a58a02021-01-10 15:50:04 -08001835 value, lookup_context);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001836 }
1837
Garret Rieger9fad5402020-09-28 13:24:25 -07001838 void closure_lookups (hb_closure_lookups_context_t *c,
1839 ContextClosureLookupContext &lookup_context) const
Qunxin Liu0b39c482019-10-22 16:00:43 -07001840 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04301841 if (unlikely (c->lookup_limit_exceeded ())) return;
Garret Rieger9fad5402020-09-28 13:24:25 -07001842 if (!intersects (c->glyphs, lookup_context)) return;
Garret Rieger014e0382020-03-31 16:29:29 -07001843
Behdad Esfahbod51922942022-07-08 14:00:24 -06001844 const auto &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
1845 (inputZ.as_array (inputCount ? inputCount - 1 : 0));
Qunxin Liu0b39c482019-10-22 16:00:43 -07001846 recurse_lookups (c, lookupCount, lookupRecord.arrayZ);
1847 }
1848
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301849 void collect_glyphs (hb_collect_glyphs_context_t *c,
1850 ContextCollectGlyphsLookupContext &lookup_context) const
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001851 {
Behdad Esfahbod51922942022-07-08 14:00:24 -06001852 const auto &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
1853 (inputZ.as_array (inputCount ? inputCount - 1 : 0));
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001854 context_collect_glyphs_lookup (c,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001855 inputCount, inputZ.arrayZ,
1856 lookupCount, lookupRecord.arrayZ,
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001857 lookup_context);
1858 }
1859
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301860 bool would_apply (hb_would_apply_context_t *c,
1861 ContextApplyLookupContext &lookup_context) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001862 {
Behdad Esfahbod51922942022-07-08 14:00:24 -06001863 const auto &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
1864 (inputZ.as_array (inputCount ? inputCount - 1 : 0));
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07001865 return context_would_apply_lookup (c,
1866 inputCount, inputZ.arrayZ,
1867 lookupCount, lookupRecord.arrayZ,
1868 lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001869 }
1870
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301871 bool apply (hb_ot_apply_context_t *c,
1872 ContextApplyLookupContext &lookup_context) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001873 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001874 TRACE_APPLY (this);
Behdad Esfahbod51922942022-07-08 14:00:24 -06001875 const auto &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
1876 (inputZ.as_array (inputCount ? inputCount - 1 : 0));
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001877 return_trace (context_apply_lookup (c, inputCount, inputZ.arrayZ, lookupCount, lookupRecord.arrayZ, lookup_context));
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001878 }
1879
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001880 bool serialize (hb_serialize_context_t *c,
1881 const hb_map_t *input_mapping, /* old->new glyphid or class mapping */
1882 const hb_map_t *lookup_map) const
1883 {
1884 TRACE_SERIALIZE (this);
1885 auto *out = c->start_embed (this);
1886 if (unlikely (!c->extend_min (out))) return_trace (false);
1887
1888 out->inputCount = inputCount;
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06001889 const auto input = inputZ.as_array (inputCount - 1);
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001890 for (const auto org : input)
1891 {
1892 HBUINT16 d;
1893 d = input_mapping->get (org);
1894 c->copy (d);
1895 }
1896
Behdad Esfahbod51922942022-07-08 14:00:24 -06001897 const auto &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
1898 (inputZ.as_array ((inputCount ? inputCount - 1 : 0)));
Garret Riegerf51b48c2021-11-02 16:16:52 -07001899
Qunxin Liu36ed56b2021-09-23 10:51:21 -07001900 unsigned count = serialize_lookuprecord_array (c, lookupRecord.as_array (lookupCount), lookup_map);
1901 return_trace (c->check_assign (out->lookupCount, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001902 }
1903
1904 bool subset (hb_subset_context_t *c,
1905 const hb_map_t *lookup_map,
1906 const hb_map_t *klass_map = nullptr) const
1907 {
1908 TRACE_SUBSET (this);
Qunxin Liue88fc412021-11-18 16:53:36 -08001909 if (unlikely (!inputCount)) return_trace (false);
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06001910 const auto input = inputZ.as_array (inputCount - 1);
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001911
1912 const hb_map_t *mapping = klass_map == nullptr ? c->plan->glyph_map : klass_map;
1913 if (!hb_all (input, mapping)) return_trace (false);
1914 return_trace (serialize (c->serializer, mapping, lookup_map));
1915 }
1916
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001917 public:
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301918 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001919 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001920 TRACE_SANITIZE (this);
Behdad Esfahbod5aad8192017-11-03 17:16:26 -04001921 return_trace (inputCount.sanitize (c) &&
1922 lookupCount.sanitize (c) &&
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001923 c->check_range (inputZ.arrayZ,
Behdad Esfahbod9c6921c2018-11-30 15:16:57 -05001924 inputZ.item_size * (inputCount ? inputCount - 1 : 0) +
Behdad Esfahbod6d7c6e12018-02-07 14:09:56 -06001925 LookupRecord::static_size * lookupCount));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001926 }
1927
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001928 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001929 HBUINT16 inputCount; /* Total number of glyphs in input
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001930 * glyph sequence--includes the first
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001931 * glyph */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001932 HBUINT16 lookupCount; /* Number of LookupRecords */
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06001933 UnsizedArrayOf<typename Types::HBUINT>
Ebrahim Byagowice114d62019-12-31 15:53:02 +03301934 inputZ; /* Array of match inputs--start with
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001935 * second glyph */
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001936/*UnsizedArrayOf<LookupRecord>
1937 lookupRecordX;*/ /* Array of LookupRecords--in
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001938 * design order */
Behdad Esfahbod569da922010-05-10 16:38:32 -04001939 public:
Behdad Esfahbod6d7c6e12018-02-07 14:09:56 -06001940 DEFINE_SIZE_ARRAY (4, inputZ);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001941};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001942
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06001943template <typename Types>
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001944struct RuleSet
1945{
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06001946 using Rule = OT::Rule<Types>;
1947
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301948 bool intersects (const hb_set_t *glyphs,
1949 ContextClosureLookupContext &lookup_context) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001950 {
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001951 return
1952 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07001953 | hb_map (hb_add (this))
1954 | hb_map ([&] (const Rule &_) { return _.intersects (glyphs, lookup_context); })
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001955 | hb_any
1956 ;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001957 }
1958
Qunxin Liub8a58a02021-01-10 15:50:04 -08001959 void closure (hb_closure_context_t *c, unsigned value,
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301960 ContextClosureLookupContext &lookup_context) const
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001961 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04301962 if (unlikely (c->lookup_limit_exceeded ())) return;
Garret Rieger014e0382020-03-31 16:29:29 -07001963
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001964 return
1965 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07001966 | hb_map (hb_add (this))
Qunxin Liub8a58a02021-01-10 15:50:04 -08001967 | hb_apply ([&] (const Rule &_) { _.closure (c, value, lookup_context); })
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001968 ;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001969 }
1970
Garret Rieger9fad5402020-09-28 13:24:25 -07001971 void closure_lookups (hb_closure_lookups_context_t *c,
1972 ContextClosureLookupContext &lookup_context) const
Qunxin Liu0b39c482019-10-22 16:00:43 -07001973 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04301974 if (unlikely (c->lookup_limit_exceeded ())) return;
Qunxin Liu0b39c482019-10-22 16:00:43 -07001975 + hb_iter (rule)
1976 | hb_map (hb_add (this))
Garret Riegere31c2692020-09-28 16:51:25 -07001977 | hb_apply ([&] (const Rule &_) { _.closure_lookups (c, lookup_context); })
Qunxin Liu0b39c482019-10-22 16:00:43 -07001978 ;
1979 }
1980
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301981 void collect_glyphs (hb_collect_glyphs_context_t *c,
1982 ContextCollectGlyphsLookupContext &lookup_context) const
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001983 {
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001984 return
1985 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07001986 | hb_map (hb_add (this))
1987 | hb_apply ([&] (const Rule &_) { _.collect_glyphs (c, lookup_context); })
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001988 ;
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001989 }
1990
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301991 bool would_apply (hb_would_apply_context_t *c,
1992 ContextApplyLookupContext &lookup_context) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001993 {
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001994 return
1995 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07001996 | hb_map (hb_add (this))
1997 | hb_map ([&] (const Rule &_) { return _.would_apply (c, lookup_context); })
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001998 | hb_any
1999 ;
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002000 }
2001
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302002 bool apply (hb_ot_apply_context_t *c,
2003 ContextApplyLookupContext &lookup_context) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002004 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002005 TRACE_APPLY (this);
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07002006 return_trace (
2007 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002008 | hb_map (hb_add (this))
2009 | hb_map ([&] (const Rule &_) { return _.apply (c, lookup_context); })
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07002010 | hb_any
2011 )
2012 ;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002013 }
2014
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002015 bool subset (hb_subset_context_t *c,
2016 const hb_map_t *lookup_map,
2017 const hb_map_t *klass_map = nullptr) const
2018 {
2019 TRACE_SUBSET (this);
2020
2021 auto snap = c->serializer->snapshot ();
2022 auto *out = c->serializer->start_embed (*this);
2023 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
2024
Behdad Esfahbodad28f972021-03-31 12:49:14 -06002025 for (const Offset16To<Rule>& _ : rule)
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002026 {
2027 if (!_) continue;
Garret Riegerc2cc5662021-09-22 14:15:55 -07002028 auto o_snap = c->serializer->snapshot ();
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002029 auto *o = out->rule.serialize_append (c->serializer);
2030 if (unlikely (!o)) continue;
2031
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002032 if (!o->serialize_subset (c, _, this, lookup_map, klass_map))
2033 {
Ebrahim Byagowi5a7cc7f2020-07-29 08:33:32 +04302034 out->rule.pop ();
2035 c->serializer->revert (o_snap);
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002036 }
2037 }
2038
2039 bool ret = bool (out->rule);
2040 if (!ret) c->serializer->revert (snap);
2041
2042 return_trace (ret);
2043 }
2044
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302045 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002046 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002047 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002048 return_trace (rule.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002049 }
2050
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002051 protected:
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06002052 Array16OfOffset16To<Rule>
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04002053 rule; /* Array of Rule tables
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002054 * ordered by preference */
Behdad Esfahboded074222010-05-10 18:08:46 -04002055 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04002056 DEFINE_SIZE_ARRAY (2, rule);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002057};
2058
2059
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06002060template <typename Types>
2061struct ContextFormat1_4
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002062{
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06002063 using RuleSet = OT::RuleSet<Types>;
2064
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302065 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002066 {
2067 struct ContextClosureLookupContext lookup_context = {
Qunxin Liub8a58a02021-01-10 15:50:04 -08002068 {intersects_glyph, intersected_glyph},
2069 ContextFormat::SimpleContext,
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002070 nullptr
2071 };
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002072
2073 return
2074 + hb_zip (this+coverage, ruleSet)
2075 | hb_filter (*glyphs, hb_first)
2076 | hb_map (hb_second)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002077 | hb_map (hb_add (this))
2078 | hb_map ([&] (const RuleSet &_) { return _.intersects (glyphs, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002079 | hb_any
2080 ;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002081 }
2082
Qunxin Liub4fc5932020-12-09 10:44:18 -08002083 bool may_have_non_1to1 () const
2084 { return true; }
2085
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302086 void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002087 {
Behdad Esfahbod00dfbbc2022-07-21 11:39:32 -06002088 hb_set_t& cur_active_glyphs = c->push_cur_active_glyphs ();
2089 get_coverage ().intersect_set (c->previous_parent_active_glyphs (), cur_active_glyphs);
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08002090
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002091 struct ContextClosureLookupContext lookup_context = {
Qunxin Liub8a58a02021-01-10 15:50:04 -08002092 {intersects_glyph, intersected_glyph},
2093 ContextFormat::SimpleContext,
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02002094 nullptr
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002095 };
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002096
Qunxin Liub8a58a02021-01-10 15:50:04 -08002097 + hb_zip (this+coverage, hb_range ((unsigned) ruleSet.len))
Garret Rieger4e2f4092022-01-31 12:20:32 -08002098 | hb_filter ([&] (hb_codepoint_t _) {
2099 return c->previous_parent_active_glyphs ().has (_);
2100 }, hb_first)
Qunxin Liub8a58a02021-01-10 15:50:04 -08002101 | hb_map ([&](const hb_pair_t<hb_codepoint_t, unsigned> _) { return hb_pair_t<unsigned, const RuleSet&> (_.first, this+ruleSet[_.second]); })
2102 | hb_apply ([&] (const hb_pair_t<unsigned, const RuleSet&>& _) { _.second.closure (c, _.first, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002103 ;
Garret Riegerbc899652022-01-28 13:54:10 -08002104
2105 c->pop_cur_done_glyphs ();
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002106 }
2107
Qunxin Liu0b39c482019-10-22 16:00:43 -07002108 void closure_lookups (hb_closure_lookups_context_t *c) const
2109 {
Garret Rieger9fad5402020-09-28 13:24:25 -07002110 struct ContextClosureLookupContext lookup_context = {
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08002111 {intersects_glyph, intersected_glyph},
2112 ContextFormat::SimpleContext,
Garret Rieger9fad5402020-09-28 13:24:25 -07002113 nullptr
2114 };
2115
2116 + hb_zip (this+coverage, ruleSet)
2117 | hb_filter (*c->glyphs, hb_first)
2118 | hb_map (hb_second)
Qunxin Liu0b39c482019-10-22 16:00:43 -07002119 | hb_map (hb_add (this))
Garret Riegere31c2692020-09-28 16:51:25 -07002120 | hb_apply ([&] (const RuleSet &_) { _.closure_lookups (c, lookup_context); })
Qunxin Liu0b39c482019-10-22 16:00:43 -07002121 ;
2122 }
2123
Qunxin Liu8200e482020-02-26 13:11:42 -08002124 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
2125
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302126 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002127 {
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07002128 (this+coverage).collect_coverage (c->input);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05002129
2130 struct ContextCollectGlyphsLookupContext lookup_context = {
2131 {collect_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02002132 nullptr
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05002133 };
2134
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002135 + hb_iter (ruleSet)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002136 | hb_map (hb_add (this))
2137 | hb_apply ([&] (const RuleSet &_) { _.collect_glyphs (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002138 ;
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002139 }
2140
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302141 bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002142 {
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05002143 const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002144 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002145 {match_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02002146 nullptr
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002147 };
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07002148 return rule_set.would_apply (c, lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002149 }
2150
Ebrahim Byagowie4120082018-12-17 21:31:01 +03302151 const Coverage &get_coverage () const { return this+coverage; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002152
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302153 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002154 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002155 TRACE_APPLY (this);
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05002156 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -04002157 if (likely (index == NOT_COVERED))
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002158 return_trace (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002159
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002160 const RuleSet &rule_set = this+ruleSet[index];
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002161 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002162 {match_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02002163 nullptr
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002164 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002165 return_trace (rule_set.apply (c, lookup_context));
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002166 }
2167
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302168 bool subset (hb_subset_context_t *c) const
Behdad Esfahbod339d3602018-09-03 17:33:34 -07002169 {
2170 TRACE_SUBSET (this);
Garret Riegere5835052020-09-29 11:05:08 -07002171 const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002172 const hb_map_t &glyph_map = *c->plan->glyph_map;
2173
2174 auto *out = c->serializer->start_embed (*this);
2175 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
2176 out->format = format;
2177
2178 const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
2179 hb_sorted_vector_t<hb_codepoint_t> new_coverage;
2180 + hb_zip (this+coverage, ruleSet)
2181 | hb_filter (glyphset, hb_first)
2182 | hb_filter (subset_offset_array (c, out->ruleSet, this, lookup_map), hb_second)
2183 | hb_map (hb_first)
2184 | hb_map (glyph_map)
2185 | hb_sink (new_coverage)
2186 ;
2187
Garret Rieger085aa652021-06-14 16:47:45 -07002188 out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002189 return_trace (bool (new_coverage));
Behdad Esfahbod339d3602018-09-03 17:33:34 -07002190 }
2191
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302192 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002193 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002194 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002195 return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002196 }
2197
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002198 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002199 HBUINT16 format; /* Format identifier--format = 1 */
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06002200 typename Types::template OffsetTo<Coverage>
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002201 coverage; /* Offset to Coverage table--from
2202 * beginning of table */
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06002203 Array16Of<typename Types::template OffsetTo<RuleSet>>
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002204 ruleSet; /* Array of RuleSet tables
2205 * ordered by Coverage Index */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04002206 public:
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06002207 DEFINE_SIZE_ARRAY (2 + 2 * Types::size, ruleSet);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002208};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002209
2210
Behdad Esfahboda90c5af2022-07-08 13:11:47 -06002211template <typename Types>
2212struct ContextFormat2_5
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002213{
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06002214 using RuleSet = OT::RuleSet<SmallTypes>;
2215
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302216 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002217 {
2218 if (!(this+coverage).intersects (glyphs))
2219 return false;
2220
2221 const ClassDef &class_def = this+classDef;
2222
2223 struct ContextClosureLookupContext lookup_context = {
Qunxin Liub8a58a02021-01-10 15:50:04 -08002224 {intersects_class, intersected_class_glyphs},
2225 ContextFormat::ClassBasedContext,
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002226 &class_def
2227 };
2228
Qunxin Liu540f19b2021-10-29 17:11:53 -07002229 hb_set_t retained_coverage_glyphs;
Behdad Esfahbod00dfbbc2022-07-21 11:39:32 -06002230 (this+coverage).intersect_set (*glyphs, retained_coverage_glyphs);
Qunxin Liu540f19b2021-10-29 17:11:53 -07002231
2232 hb_set_t coverage_glyph_classes;
2233 class_def.intersected_classes (&retained_coverage_glyphs, &coverage_glyph_classes);
2234
2235
Behdad Esfahbod668d2d52019-03-29 22:48:38 -07002236 return
Behdad Esfahbod26111a12020-06-28 02:59:47 -07002237 + hb_iter (ruleSet)
2238 | hb_map (hb_add (this))
2239 | hb_enumerate
2240 | hb_map ([&] (const hb_pair_t<unsigned, const RuleSet &> p)
Behdad Esfahbode5306922019-03-29 23:31:07 -07002241 { return class_def.intersects_class (glyphs, p.first) &&
Qunxin Liu540f19b2021-10-29 17:11:53 -07002242 coverage_glyph_classes.has (p.first) &&
Behdad Esfahbod26111a12020-06-28 02:59:47 -07002243 p.second.intersects (glyphs, lookup_context); })
Behdad Esfahbod668d2d52019-03-29 22:48:38 -07002244 | hb_any
2245 ;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002246 }
2247
Qunxin Liub4fc5932020-12-09 10:44:18 -08002248 bool may_have_non_1to1 () const
2249 { return true; }
2250
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302251 void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002252 {
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002253 if (!(this+coverage).intersects (c->glyphs))
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002254 return;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002255
Behdad Esfahbod00dfbbc2022-07-21 11:39:32 -06002256 hb_set_t& cur_active_glyphs = c->push_cur_active_glyphs ();
2257 get_coverage ().intersect_set (c->previous_parent_active_glyphs (),
Garret Rieger4e2f4092022-01-31 12:20:32 -08002258 cur_active_glyphs);
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08002259
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002260 const ClassDef &class_def = this+classDef;
2261
2262 struct ContextClosureLookupContext lookup_context = {
Qunxin Liub8a58a02021-01-10 15:50:04 -08002263 {intersects_class, intersected_class_glyphs},
2264 ContextFormat::ClassBasedContext,
Behdad Esfahbod11fba792013-01-02 23:36:37 -06002265 &class_def
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002266 };
2267
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07002268 + hb_enumerate (ruleSet)
Behdad Esfahbod78d35f02019-05-15 18:15:05 -07002269 | hb_filter ([&] (unsigned _)
Garret Riegerbc899652022-01-28 13:54:10 -08002270 { return class_def.intersects_class (&c->parent_active_glyphs (), _); },
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07002271 hb_first)
Behdad Esfahboda90c5af2022-07-08 13:11:47 -06002272 | hb_apply ([&] (const hb_pair_t<unsigned, const typename Types::template OffsetTo<RuleSet>&> _)
Qunxin Liub8a58a02021-01-10 15:50:04 -08002273 {
2274 const RuleSet& rule_set = this+_.second;
2275 rule_set.closure (c, _.first, lookup_context);
2276 })
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07002277 ;
Garret Riegerbc899652022-01-28 13:54:10 -08002278
2279 c->pop_cur_done_glyphs ();
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002280 }
2281
Qunxin Liu0b39c482019-10-22 16:00:43 -07002282 void closure_lookups (hb_closure_lookups_context_t *c) const
2283 {
Garret Rieger9fad5402020-09-28 13:24:25 -07002284 if (!(this+coverage).intersects (c->glyphs))
2285 return;
2286
2287 const ClassDef &class_def = this+classDef;
2288
2289 struct ContextClosureLookupContext lookup_context = {
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08002290 {intersects_class, intersected_class_glyphs},
2291 ContextFormat::ClassBasedContext,
Garret Rieger9fad5402020-09-28 13:24:25 -07002292 &class_def
2293 };
2294
Qunxin Liu0b39c482019-10-22 16:00:43 -07002295 + hb_iter (ruleSet)
2296 | hb_map (hb_add (this))
Garret Rieger9fad5402020-09-28 13:24:25 -07002297 | hb_enumerate
2298 | hb_filter ([&] (const hb_pair_t<unsigned, const RuleSet &> p)
2299 { return class_def.intersects_class (c->glyphs, p.first); })
2300 | hb_map (hb_second)
2301 | hb_apply ([&] (const RuleSet & _)
2302 { _.closure_lookups (c, lookup_context); });
Qunxin Liu0b39c482019-10-22 16:00:43 -07002303 }
2304
Qunxin Liu8200e482020-02-26 13:11:42 -08002305 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
2306
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302307 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002308 {
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07002309 (this+coverage).collect_coverage (c->input);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05002310
Behdad Esfahbod11fba792013-01-02 23:36:37 -06002311 const ClassDef &class_def = this+classDef;
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05002312 struct ContextCollectGlyphsLookupContext lookup_context = {
2313 {collect_class},
Behdad Esfahbod11fba792013-01-02 23:36:37 -06002314 &class_def
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05002315 };
2316
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002317 + hb_iter (ruleSet)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002318 | hb_map (hb_add (this))
2319 | hb_apply ([&] (const RuleSet &_) { _.collect_glyphs (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002320 ;
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002321 }
2322
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302323 bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002324 {
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002325 const ClassDef &class_def = this+classDef;
Behdad Esfahbod2dc11412012-11-24 19:16:34 -05002326 unsigned int index = class_def.get_class (c->glyphs[0]);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002327 const RuleSet &rule_set = this+ruleSet[index];
2328 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002329 {match_class},
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002330 &class_def
2331 };
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07002332 return rule_set.would_apply (c, lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002333 }
2334
Ebrahim Byagowie4120082018-12-17 21:31:01 +03302335 const Coverage &get_coverage () const { return this+coverage; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002336
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06002337 unsigned cache_cost () const
2338 {
2339 unsigned c = (this+classDef).cost () * ruleSet.len;
2340 return c >= 4 ? c : 0;
2341 }
Behdad Esfahbod5963cf42022-06-07 09:12:45 -06002342 bool cache_func (hb_ot_apply_context_t *c, bool enter) const
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06002343 {
Behdad Esfahbod5963cf42022-06-07 09:12:45 -06002344 if (enter)
2345 {
2346 if (!HB_BUFFER_TRY_ALLOCATE_VAR (c->buffer, syllable))
2347 return false;
2348 auto &info = c->buffer->info;
2349 unsigned count = c->buffer->len;
2350 for (unsigned i = 0; i < count; i++)
2351 info[i].syllable() = 255;
2352 c->new_syllables = 255;
2353 return true;
2354 }
2355 else
2356 {
2357 c->new_syllables = (unsigned) -1;
2358 HB_BUFFER_DEALLOCATE_VAR (c->buffer, syllable);
2359 return true;
2360 }
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06002361 }
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06002362
2363 bool apply (hb_ot_apply_context_t *c, bool cached = false) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002364 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002365 TRACE_APPLY (this);
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05002366 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002367 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002368
2369 const ClassDef &class_def = this+classDef;
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06002370
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002371 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06002372 {cached ? match_class_cached : match_class},
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04002373 &class_def
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002374 };
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06002375
2376 if (cached && c->buffer->cur().syllable() < 255)
2377 index = c->buffer->cur().syllable ();
2378 else
2379 {
2380 index = class_def.get_class (c->buffer->cur().codepoint);
2381 if (cached && index < 255)
2382 c->buffer->cur().syllable() = index;
2383 }
2384 const RuleSet &rule_set = this+ruleSet[index];
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002385 return_trace (rule_set.apply (c, lookup_context));
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002386 }
2387
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302388 bool subset (hb_subset_context_t *c) const
Behdad Esfahbod339d3602018-09-03 17:33:34 -07002389 {
2390 TRACE_SUBSET (this);
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002391 auto *out = c->serializer->start_embed (*this);
2392 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
2393 out->format = format;
2394 if (unlikely (!out->coverage.serialize_subset (c, coverage, this)))
2395 return_trace (false);
2396
2397 hb_map_t klass_map;
2398 out->classDef.serialize_subset (c, classDef, this, &klass_map);
2399
Qunxin Liu540f19b2021-10-29 17:11:53 -07002400 const hb_set_t* glyphset = c->plan->glyphset_gsub ();
2401 hb_set_t retained_coverage_glyphs;
Behdad Esfahbod00dfbbc2022-07-21 11:39:32 -06002402 (this+coverage).intersect_set (*glyphset, retained_coverage_glyphs);
Garret Riegerf51b48c2021-11-02 16:16:52 -07002403
Qunxin Liu540f19b2021-10-29 17:11:53 -07002404 hb_set_t coverage_glyph_classes;
2405 (this+classDef).intersected_classes (&retained_coverage_glyphs, &coverage_glyph_classes);
2406
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002407 const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
2408 bool ret = true;
Qunxin Liu540f19b2021-10-29 17:11:53 -07002409 int non_zero_index = -1, index = 0;
Behdad Esfahbod6d941942021-02-19 17:08:10 -07002410 for (const auto& _ : + hb_enumerate (ruleSet)
2411 | hb_filter (klass_map, hb_first))
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002412 {
2413 auto *o = out->ruleSet.serialize_append (c->serializer);
2414 if (unlikely (!o))
2415 {
Ebrahim Byagowi5a7cc7f2020-07-29 08:33:32 +04302416 ret = false;
2417 break;
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002418 }
2419
Qunxin Liu540f19b2021-10-29 17:11:53 -07002420 if (coverage_glyph_classes.has (_.first) &&
2421 o->serialize_subset (c, _.second, this, lookup_map, &klass_map))
Ebrahim Byagowi5a7cc7f2020-07-29 08:33:32 +04302422 non_zero_index = index;
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002423
2424 index++;
2425 }
2426
Qunxin Liu540f19b2021-10-29 17:11:53 -07002427 if (!ret || non_zero_index == -1) return_trace (false);
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002428
2429 //prune empty trailing ruleSets
2430 --index;
2431 while (index > non_zero_index)
2432 {
2433 out->ruleSet.pop ();
2434 index--;
2435 }
2436
2437 return_trace (bool (out->ruleSet));
Behdad Esfahbod339d3602018-09-03 17:33:34 -07002438 }
2439
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302440 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002441 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002442 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002443 return_trace (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002444 }
2445
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002446 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002447 HBUINT16 format; /* Format identifier--format = 2 */
Behdad Esfahboda90c5af2022-07-08 13:11:47 -06002448 typename Types::template OffsetTo<Coverage>
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002449 coverage; /* Offset to Coverage table--from
2450 * beginning of table */
Behdad Esfahboda90c5af2022-07-08 13:11:47 -06002451 typename Types::template OffsetTo<ClassDef>
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002452 classDef; /* Offset to glyph ClassDef table--from
2453 * beginning of table */
Behdad Esfahboda90c5af2022-07-08 13:11:47 -06002454 Array16Of<typename Types::template OffsetTo<RuleSet>>
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002455 ruleSet; /* Array of RuleSet tables
2456 * ordered by class */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04002457 public:
Behdad Esfahboda90c5af2022-07-08 13:11:47 -06002458 DEFINE_SIZE_ARRAY (4 + 2 * Types::size, ruleSet);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002459};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002460
2461
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002462struct ContextFormat3
2463{
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06002464 using RuleSet = OT::RuleSet<SmallTypes>;
2465
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302466 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002467 {
Behdad Esfahbodfb059082018-11-30 20:45:40 -05002468 if (!(this+coverageZ[0]).intersects (glyphs))
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002469 return false;
2470
2471 struct ContextClosureLookupContext lookup_context = {
Qunxin Liub8a58a02021-01-10 15:50:04 -08002472 {intersects_coverage, intersected_coverage_glyphs},
2473 ContextFormat::CoverageBasedContext,
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002474 this
2475 };
2476 return context_intersects (glyphs,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02002477 glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002478 lookup_context);
2479 }
2480
Qunxin Liub4fc5932020-12-09 10:44:18 -08002481 bool may_have_non_1to1 () const
2482 { return true; }
2483
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302484 void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002485 {
Behdad Esfahbodfb059082018-11-30 20:45:40 -05002486 if (!(this+coverageZ[0]).intersects (c->glyphs))
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002487 return;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002488
Behdad Esfahbod00dfbbc2022-07-21 11:39:32 -06002489 hb_set_t& cur_active_glyphs = c->push_cur_active_glyphs ();
2490 get_coverage ().intersect_set (c->previous_parent_active_glyphs (),
Garret Rieger4e2f4092022-01-31 12:20:32 -08002491 cur_active_glyphs);
2492
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08002493
Behdad Esfahbod0382b712018-11-02 12:23:26 -04002494 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002495 struct ContextClosureLookupContext lookup_context = {
Qunxin Liub8a58a02021-01-10 15:50:04 -08002496 {intersects_coverage, intersected_coverage_glyphs},
2497 ContextFormat::CoverageBasedContext,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002498 this
2499 };
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002500 context_closure_lookup (c,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02002501 glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002502 lookupCount, lookupRecord,
Qunxin Liub8a58a02021-01-10 15:50:04 -08002503 0, lookup_context);
Garret Riegerbc899652022-01-28 13:54:10 -08002504
2505 c->pop_cur_done_glyphs ();
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002506 }
2507
Qunxin Liu0b39c482019-10-22 16:00:43 -07002508 void closure_lookups (hb_closure_lookups_context_t *c) const
2509 {
Garret Riegera5c0ec72020-09-25 14:57:20 -07002510 if (!intersects (c->glyphs))
2511 return;
Qunxin Liu0b39c482019-10-22 16:00:43 -07002512 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
2513 recurse_lookups (c, lookupCount, lookupRecord);
2514 }
2515
Qunxin Liu8200e482020-02-26 13:11:42 -08002516 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
2517
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302518 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002519 {
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07002520 (this+coverageZ[0]).collect_coverage (c->input);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05002521
Behdad Esfahbod0382b712018-11-02 12:23:26 -04002522 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05002523 struct ContextCollectGlyphsLookupContext lookup_context = {
2524 {collect_coverage},
Behdad Esfahbode75943d2012-11-30 08:38:24 +02002525 this
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05002526 };
2527
2528 context_collect_glyphs_lookup (c,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02002529 glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05002530 lookupCount, lookupRecord,
2531 lookup_context);
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002532 }
2533
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302534 bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002535 {
Behdad Esfahbod0382b712018-11-02 12:23:26 -04002536 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002537 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002538 {match_coverage},
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002539 this
2540 };
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07002541 return context_would_apply_lookup (c,
2542 glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
2543 lookupCount, lookupRecord,
2544 lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002545 }
2546
Ebrahim Byagowie4120082018-12-17 21:31:01 +03302547 const Coverage &get_coverage () const { return this+coverageZ[0]; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002548
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302549 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002550 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002551 TRACE_APPLY (this);
Behdad Esfahbodfb059082018-11-30 20:45:40 -05002552 unsigned int index = (this+coverageZ[0]).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002553 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04002554
Behdad Esfahbod0382b712018-11-02 12:23:26 -04002555 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002556 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002557 {match_coverage},
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04002558 this
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002559 };
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02002560 return_trace (context_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, lookup_context));
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002561 }
2562
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302563 bool subset (hb_subset_context_t *c) const
Behdad Esfahbod339d3602018-09-03 17:33:34 -07002564 {
2565 TRACE_SUBSET (this);
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002566 auto *out = c->serializer->start_embed (this);
2567 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
2568
2569 out->format = format;
2570 out->glyphCount = glyphCount;
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002571
Behdad Esfahbod26111a12020-06-28 02:59:47 -07002572 auto coverages = coverageZ.as_array (glyphCount);
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002573
Behdad Esfahbodad28f972021-03-31 12:49:14 -06002574 for (const Offset16To<Coverage>& offset : coverages)
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002575 {
Behdad Esfahbod6d941942021-02-19 17:08:10 -07002576 /* TODO(subset) This looks like should not be necessary to write this way. */
Behdad Esfahbod9b4b5842021-03-31 13:27:21 -06002577 auto *o = c->serializer->allocate_size<Offset16To<Coverage>> (Offset16To<Coverage>::static_size);
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002578 if (unlikely (!o)) return_trace (false);
2579 if (!o->serialize_subset (c, offset, this)) return_trace (false);
2580 }
2581
Behdad Esfahbod51922942022-07-08 14:00:24 -06002582 const auto& lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>> (coverageZ.as_array (glyphCount));
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002583 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 -07002584
Ebrahim Byagowia79d0e42020-05-21 07:32:58 +04302585
Qunxin Liu36ed56b2021-09-23 10:51:21 -07002586 unsigned count = serialize_lookuprecord_array (c->serializer, lookupRecord.as_array (lookupCount), lookup_map);
2587 return_trace (c->serializer->check_assign (out->lookupCount, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
Behdad Esfahbod339d3602018-09-03 17:33:34 -07002588 }
2589
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302590 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002591 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002592 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002593 if (!c->check_struct (this)) return_trace (false);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002594 unsigned int count = glyphCount;
Behdad Esfahbodfb059082018-11-30 20:45:40 -05002595 if (!count) return_trace (false); /* We want to access coverageZ[0] freely. */
Behdad Esfahbod9507b052018-09-10 23:18:07 +02002596 if (!c->check_array (coverageZ.arrayZ, count)) return_trace (false);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002597 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002598 if (!coverageZ[i].sanitize (c, this)) return_trace (false);
Behdad Esfahbod0382b712018-11-02 12:23:26 -04002599 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
Behdad Esfahbod9507b052018-09-10 23:18:07 +02002600 return_trace (c->check_array (lookupRecord, lookupCount));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002601 }
2602
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002603 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002604 HBUINT16 format; /* Format identifier--format = 3 */
2605 HBUINT16 glyphCount; /* Number of glyphs in the input glyph
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002606 * sequence */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002607 HBUINT16 lookupCount; /* Number of LookupRecords */
Behdad Esfahbodad28f972021-03-31 12:49:14 -06002608 UnsizedArrayOf<Offset16To<Coverage>>
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02002609 coverageZ; /* Array of offsets to Coverage
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002610 * table in glyph sequence order */
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02002611/*UnsizedArrayOf<LookupRecord>
2612 lookupRecordX;*/ /* Array of LookupRecords--in
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002613 * design order */
Behdad Esfahbod569da922010-05-10 16:38:32 -04002614 public:
Behdad Esfahbod6d7c6e12018-02-07 14:09:56 -06002615 DEFINE_SIZE_ARRAY (6, coverageZ);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002616};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002617
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002618struct Context
2619{
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -07002620 template <typename context_t, typename ...Ts>
Behdad Esfahbod83e3eab2019-05-07 20:58:43 -07002621 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002622 {
Behdad Esfahbod00f6a8e2014-12-12 20:36:49 -08002623 TRACE_DISPATCH (this, u.format);
Behdad Esfahbodf396fbb2015-10-09 12:25:55 -04002624 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002625 switch (u.format) {
Behdad Esfahbod6d555ce2021-11-02 00:18:22 -06002626 case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
2627 case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
2628 case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
Behdad Esfahbod5a9c7932022-07-22 21:33:15 -06002629#ifndef HB_NO_BEYOND_64K
Behdad Esfahbod1bf8fa22022-07-08 14:22:21 -06002630 case 4: return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...));
Behdad Esfahbodd1f58e52022-07-08 13:25:07 -06002631 case 5: return_trace (c->dispatch (u.format5, std::forward<Ts> (ds)...));
2632#endif
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002633 default:return_trace (c->default_return_value ());
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002634 }
2635 }
2636
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002637 protected:
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002638 union {
Behdad Esfahboda90c5af2022-07-08 13:11:47 -06002639 HBUINT16 format; /* Format identifier */
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06002640 ContextFormat1_4<SmallTypes> format1;
Behdad Esfahboda90c5af2022-07-08 13:11:47 -06002641 ContextFormat2_5<SmallTypes> format2;
2642 ContextFormat3 format3;
Behdad Esfahbod5a9c7932022-07-22 21:33:15 -06002643#ifndef HB_NO_BEYOND_64K
Behdad Esfahbod1bf8fa22022-07-08 14:22:21 -06002644 ContextFormat1_4<MediumTypes> format4;
Behdad Esfahbodd1f58e52022-07-08 13:25:07 -06002645 ContextFormat2_5<MediumTypes> format5;
2646#endif
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002647 } u;
2648};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002649
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002650
2651/* Chaining Contextual lookups */
2652
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002653struct ChainContextClosureLookupContext
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002654{
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002655 ContextClosureFuncs funcs;
Qunxin Liub8a58a02021-01-10 15:50:04 -08002656 ContextFormat context_format;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002657 const void *intersects_data[3];
2658};
2659
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002660struct ChainContextCollectGlyphsLookupContext
2661{
2662 ContextCollectGlyphsFuncs funcs;
2663 const void *collect_data[3];
2664};
2665
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002666struct ChainContextApplyLookupContext
2667{
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06002668 ChainContextApplyFuncs funcs;
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04002669 const void *match_data[3];
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04002670};
2671
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06002672template <typename HBUINT>
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002673static inline bool chain_context_intersects (const hb_set_t *glyphs,
2674 unsigned int backtrackCount,
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06002675 const HBUINT backtrack[],
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002676 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06002677 const HBUINT input[], /* Array of input values--start with second glyph */
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002678 unsigned int lookaheadCount,
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06002679 const HBUINT lookahead[],
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002680 ChainContextClosureLookupContext &lookup_context)
2681{
Qunxin Liu44d88cf2020-05-08 15:33:34 -07002682 return array_is_subset_of (glyphs,
2683 backtrackCount, backtrack,
2684 lookup_context.funcs.intersects, lookup_context.intersects_data[0])
2685 && array_is_subset_of (glyphs,
2686 inputCount ? inputCount - 1 : 0, input,
2687 lookup_context.funcs.intersects, lookup_context.intersects_data[1])
2688 && array_is_subset_of (glyphs,
2689 lookaheadCount, lookahead,
2690 lookup_context.funcs.intersects, lookup_context.intersects_data[2]);
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002691}
2692
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06002693template <typename HBUINT>
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002694static inline void chain_context_closure_lookup (hb_closure_context_t *c,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002695 unsigned int backtrackCount,
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06002696 const HBUINT backtrack[],
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002697 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06002698 const HBUINT input[], /* Array of input values--start with second glyph */
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002699 unsigned int lookaheadCount,
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06002700 const HBUINT lookahead[],
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002701 unsigned int lookupCount,
2702 const LookupRecord lookupRecord[],
Qunxin Liub8a58a02021-01-10 15:50:04 -08002703 unsigned value,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002704 ChainContextClosureLookupContext &lookup_context)
2705{
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002706 if (chain_context_intersects (c->glyphs,
2707 backtrackCount, backtrack,
2708 inputCount, input,
2709 lookaheadCount, lookahead,
2710 lookup_context))
Qunxin Liub8a58a02021-01-10 15:50:04 -08002711 context_closure_recurse_lookups (c,
2712 inputCount, input,
2713 lookupCount, lookupRecord,
2714 value,
2715 lookup_context.context_format,
2716 lookup_context.intersects_data[1],
2717 lookup_context.funcs.intersected_glyphs);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002718}
2719
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06002720template <typename HBUINT>
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002721static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03302722 unsigned int backtrackCount,
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06002723 const HBUINT backtrack[],
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03302724 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06002725 const HBUINT input[], /* Array of input values--start with second glyph */
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03302726 unsigned int lookaheadCount,
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06002727 const HBUINT lookahead[],
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03302728 unsigned int lookupCount,
2729 const LookupRecord lookupRecord[],
2730 ChainContextCollectGlyphsLookupContext &lookup_context)
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002731{
Behdad Esfahbod83035932012-12-04 17:08:41 -05002732 collect_array (c, c->before,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002733 backtrackCount, backtrack,
2734 lookup_context.funcs.collect, lookup_context.collect_data[0]);
Behdad Esfahbod83035932012-12-04 17:08:41 -05002735 collect_array (c, c->input,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002736 inputCount ? inputCount - 1 : 0, input,
2737 lookup_context.funcs.collect, lookup_context.collect_data[1]);
Behdad Esfahbod83035932012-12-04 17:08:41 -05002738 collect_array (c, c->after,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002739 lookaheadCount, lookahead,
2740 lookup_context.funcs.collect, lookup_context.collect_data[2]);
2741 recurse_lookups (c,
2742 lookupCount, lookupRecord);
2743}
2744
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06002745template <typename HBUINT>
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002746static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c,
2747 unsigned int backtrackCount,
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06002748 const HBUINT backtrack[] HB_UNUSED,
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002749 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06002750 const HBUINT input[], /* Array of input values--start with second glyph */
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002751 unsigned int lookaheadCount,
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06002752 const HBUINT lookahead[] HB_UNUSED,
Behdad Esfahbod0beb66e2012-12-05 18:46:04 -05002753 unsigned int lookupCount HB_UNUSED,
2754 const LookupRecord lookupRecord[] HB_UNUSED,
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002755 ChainContextApplyLookupContext &lookup_context)
2756{
Behdad Esfahbodd9b204d2012-08-23 16:22:28 -04002757 return (c->zero_context ? !backtrackCount && !lookaheadCount : true)
Behdad Esfahbod1f2bb172012-08-23 16:10:37 -04002758 && would_match_input (c,
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002759 inputCount, input,
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06002760 lookup_context.funcs.match[1], lookup_context.match_data[1]);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002761}
2762
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06002763template <typename HBUINT>
Behdad Esfahbodfd034492018-01-17 16:46:51 -08002764static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002765 unsigned int backtrackCount,
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06002766 const HBUINT backtrack[],
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002767 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06002768 const HBUINT input[], /* Array of input values--start with second glyph */
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002769 unsigned int lookaheadCount,
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06002770 const HBUINT lookahead[],
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002771 unsigned int lookupCount,
2772 const LookupRecord lookupRecord[],
2773 ChainContextApplyLookupContext &lookup_context)
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04002774{
Behdad Esfahbod60006d32022-01-20 15:29:28 -07002775 unsigned end_index = c->buffer->idx;
Behdad Esfahbod78481b32021-11-21 16:50:34 -07002776 unsigned match_end = 0;
2777 unsigned match_positions[HB_MAX_CONTEXT_LENGTH];
Behdad Esfahbod60006d32022-01-20 15:29:28 -07002778 if (!(match_input (c,
2779 inputCount, input,
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06002780 lookup_context.funcs.match[1], lookup_context.match_data[1],
Behdad Esfahbod60006d32022-01-20 15:29:28 -07002781 &match_end, match_positions) && (end_index = match_end)
2782 && match_lookahead (c,
2783 lookaheadCount, lookahead,
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06002784 lookup_context.funcs.match[2], lookup_context.match_data[2],
Behdad Esfahbod60006d32022-01-20 15:29:28 -07002785 match_end, &end_index)))
Behdad Esfahbod78481b32021-11-21 16:50:34 -07002786 {
Behdad Esfahbod60006d32022-01-20 15:29:28 -07002787 c->buffer->unsafe_to_concat (c->buffer->idx, end_index);
2788 return false;
Behdad Esfahbod78481b32021-11-21 16:50:34 -07002789 }
Behdad Esfahbod60006d32022-01-20 15:29:28 -07002790
2791 unsigned start_index = c->buffer->out_len;
2792 if (!match_backtrack (c,
2793 backtrackCount, backtrack,
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06002794 lookup_context.funcs.match[0], lookup_context.match_data[0],
Behdad Esfahbod60006d32022-01-20 15:29:28 -07002795 &start_index))
Behdad Esfahbod78481b32021-11-21 16:50:34 -07002796 {
2797 c->buffer->unsafe_to_concat_from_outbuffer (start_index, end_index);
2798 return false;
2799 }
Behdad Esfahbod60006d32022-01-20 15:29:28 -07002800
2801 c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index);
2802 apply_lookup (c,
2803 inputCount, match_positions,
2804 lookupCount, lookupRecord,
2805 match_end);
2806 return true;
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04002807}
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04002808
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06002809template <typename Types>
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002810struct ChainRule
2811{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302812 bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002813 {
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06002814 const auto &input = StructAfter<decltype (inputX)> (backtrack);
2815 const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002816 return chain_context_intersects (glyphs,
2817 backtrack.len, backtrack.arrayZ,
Behdad Esfahbodeffc7ce2018-09-13 20:21:54 +02002818 input.lenP1, input.arrayZ,
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002819 lookahead.len, lookahead.arrayZ,
2820 lookup_context);
2821 }
2822
Qunxin Liub8a58a02021-01-10 15:50:04 -08002823 void closure (hb_closure_context_t *c, unsigned value,
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302824 ChainContextClosureLookupContext &lookup_context) const
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002825 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04302826 if (unlikely (c->lookup_limit_exceeded ())) return;
Garret Rieger4ad686b2020-03-25 23:32:28 -07002827
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06002828 const auto &input = StructAfter<decltype (inputX)> (backtrack);
2829 const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
2830 const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002831 chain_context_closure_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002832 backtrack.len, backtrack.arrayZ,
Behdad Esfahbodeffc7ce2018-09-13 20:21:54 +02002833 input.lenP1, input.arrayZ,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002834 lookahead.len, lookahead.arrayZ,
2835 lookup.len, lookup.arrayZ,
Qunxin Liub8a58a02021-01-10 15:50:04 -08002836 value,
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002837 lookup_context);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002838 }
2839
Garret Riegerad241f92020-09-28 15:26:13 -07002840 void closure_lookups (hb_closure_lookups_context_t *c,
2841 ChainContextClosureLookupContext &lookup_context) const
Qunxin Liu0b39c482019-10-22 16:00:43 -07002842 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04302843 if (unlikely (c->lookup_limit_exceeded ())) return;
Garret Riegerad241f92020-09-28 15:26:13 -07002844 if (!intersects (c->glyphs, lookup_context)) return;
Garret Rieger4ad686b2020-03-25 23:32:28 -07002845
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06002846 const auto &input = StructAfter<decltype (inputX)> (backtrack);
2847 const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
2848 const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
Qunxin Liu0b39c482019-10-22 16:00:43 -07002849 recurse_lookups (c, lookup.len, lookup.arrayZ);
2850 }
2851
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302852 void collect_glyphs (hb_collect_glyphs_context_t *c,
2853 ChainContextCollectGlyphsLookupContext &lookup_context) const
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002854 {
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06002855 const auto &input = StructAfter<decltype (inputX)> (backtrack);
2856 const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
2857 const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002858 chain_context_collect_glyphs_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002859 backtrack.len, backtrack.arrayZ,
Behdad Esfahbodeffc7ce2018-09-13 20:21:54 +02002860 input.lenP1, input.arrayZ,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002861 lookahead.len, lookahead.arrayZ,
2862 lookup.len, lookup.arrayZ,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002863 lookup_context);
2864 }
2865
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302866 bool would_apply (hb_would_apply_context_t *c,
2867 ChainContextApplyLookupContext &lookup_context) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002868 {
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06002869 const auto &input = StructAfter<decltype (inputX)> (backtrack);
2870 const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
2871 const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07002872 return chain_context_would_apply_lookup (c,
2873 backtrack.len, backtrack.arrayZ,
2874 input.lenP1, input.arrayZ,
2875 lookahead.len, lookahead.arrayZ, lookup.len,
2876 lookup.arrayZ, lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002877 }
2878
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302879 bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002880 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002881 TRACE_APPLY (this);
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06002882 const auto &input = StructAfter<decltype (inputX)> (backtrack);
2883 const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
2884 const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002885 return_trace (chain_context_apply_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002886 backtrack.len, backtrack.arrayZ,
Behdad Esfahbodeffc7ce2018-09-13 20:21:54 +02002887 input.lenP1, input.arrayZ,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002888 lookahead.len, lookahead.arrayZ, lookup.len,
2889 lookup.arrayZ, lookup_context));
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002890 }
2891
Qunxin Liub66094a2019-09-30 16:19:18 -07002892 template<typename Iterator,
2893 hb_requires (hb_is_iterator (Iterator))>
2894 void serialize_array (hb_serialize_context_t *c,
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04302895 HBUINT16 len,
2896 Iterator it) const
Qunxin Liub66094a2019-09-30 16:19:18 -07002897 {
2898 c->copy (len);
2899 for (const auto g : it)
Behdad Esfahbod83b66bf2021-02-23 13:04:25 -07002900 c->copy ((HBUINT16) g);
Qunxin Liub66094a2019-09-30 16:19:18 -07002901 }
2902
Qunxin Liu36ed56b2021-09-23 10:51:21 -07002903 bool serialize (hb_serialize_context_t *c,
2904 const hb_map_t *lookup_map,
2905 const hb_map_t *backtrack_map,
2906 const hb_map_t *input_map = nullptr,
2907 const hb_map_t *lookahead_map = nullptr) const
Qunxin Liub66094a2019-09-30 16:19:18 -07002908 {
2909 TRACE_SERIALIZE (this);
2910 auto *out = c->start_embed (this);
Qunxin Liu36ed56b2021-09-23 10:51:21 -07002911 if (unlikely (!out)) return_trace (false);
Qunxin Liub66094a2019-09-30 16:19:18 -07002912
2913 const hb_map_t *mapping = backtrack_map;
2914 serialize_array (c, backtrack.len, + backtrack.iter ()
2915 | hb_map (mapping));
2916
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06002917 const auto &input = StructAfter<decltype (inputX)> (backtrack);
Qunxin Liub66094a2019-09-30 16:19:18 -07002918 if (input_map) mapping = input_map;
2919 serialize_array (c, input.lenP1, + input.iter ()
2920 | hb_map (mapping));
2921
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06002922 const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
Qunxin Liub66094a2019-09-30 16:19:18 -07002923 if (lookahead_map) mapping = lookahead_map;
2924 serialize_array (c, lookahead.len, + lookahead.iter ()
2925 | hb_map (mapping));
2926
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06002927 const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
Qunxin Liu593e58c2020-05-20 18:00:25 -07002928
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06002929 HBUINT16* lookupCount = c->embed (&(lookup.len));
Qunxin Liu36ed56b2021-09-23 10:51:21 -07002930 if (!lookupCount) return_trace (false);
Garret Rieger8f47dd52020-11-04 11:05:22 -08002931
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06002932 unsigned count = serialize_lookuprecord_array (c, lookup.as_array (), lookup_map);
Qunxin Liu36ed56b2021-09-23 10:51:21 -07002933 return_trace (c->check_assign (*lookupCount, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
Qunxin Liub66094a2019-09-30 16:19:18 -07002934 }
2935
2936 bool subset (hb_subset_context_t *c,
Qunxin Liu593e58c2020-05-20 18:00:25 -07002937 const hb_map_t *lookup_map,
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04302938 const hb_map_t *backtrack_map = nullptr,
2939 const hb_map_t *input_map = nullptr,
2940 const hb_map_t *lookahead_map = nullptr) const
Qunxin Liub66094a2019-09-30 16:19:18 -07002941 {
2942 TRACE_SUBSET (this);
2943
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06002944 const auto &input = StructAfter<decltype (inputX)> (backtrack);
2945 const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
Qunxin Liub2fcca62019-10-24 15:15:26 -07002946
Qunxin Liub66094a2019-09-30 16:19:18 -07002947 if (!backtrack_map)
2948 {
Garret Riegere5835052020-09-29 11:05:08 -07002949 const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
Qunxin Liub66094a2019-09-30 16:19:18 -07002950 if (!hb_all (backtrack, glyphset) ||
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04302951 !hb_all (input, glyphset) ||
2952 !hb_all (lookahead, glyphset))
2953 return_trace (false);
Qunxin Liub66094a2019-09-30 16:19:18 -07002954
Qunxin Liu36ed56b2021-09-23 10:51:21 -07002955 serialize (c->serializer, lookup_map, c->plan->glyph_map);
Qunxin Liub66094a2019-09-30 16:19:18 -07002956 }
2957 else
2958 {
2959 if (!hb_all (backtrack, backtrack_map) ||
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04302960 !hb_all (input, input_map) ||
2961 !hb_all (lookahead, lookahead_map))
2962 return_trace (false);
Ebrahim Byagowiaca63902019-10-22 00:06:46 +03302963
Qunxin Liu36ed56b2021-09-23 10:51:21 -07002964 serialize (c->serializer, lookup_map, backtrack_map, input_map, lookahead_map);
Qunxin Liub66094a2019-09-30 16:19:18 -07002965 }
2966
2967 return_trace (true);
2968 }
2969
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302970 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002971 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002972 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002973 if (!backtrack.sanitize (c)) return_trace (false);
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06002974 const auto &input = StructAfter<decltype (inputX)> (backtrack);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002975 if (!input.sanitize (c)) return_trace (false);
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06002976 const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002977 if (!lookahead.sanitize (c)) return_trace (false);
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06002978 const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002979 return_trace (lookup.sanitize (c));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002980 }
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002981
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002982 protected:
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06002983 Array16Of<typename Types::HBUINT>
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04002984 backtrack; /* Array of backtracking values
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002985 * (to be matched before the input
2986 * sequence) */
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06002987 HeadlessArrayOf<typename Types::HBUINT>
Behdad Esfahbode8cbaaf2009-05-18 02:03:58 -04002988 inputX; /* Array of input values (start with
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002989 * second glyph) */
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06002990 Array16Of<typename Types::HBUINT>
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04002991 lookaheadX; /* Array of lookahead values's (to be
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04002992 * matched after the input sequence) */
Behdad Esfahbod5639e252021-03-31 16:04:43 -06002993 Array16Of<LookupRecord>
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04002994 lookupX; /* Array of LookupRecords--in
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002995 * design order) */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04002996 public:
Behdad Esfahbodbea34c72010-05-10 17:28:16 -04002997 DEFINE_SIZE_MIN (8);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002998};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002999
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06003000template <typename Types>
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04003001struct ChainRuleSet
3002{
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06003003 using ChainRule = OT::ChainRule<Types>;
3004
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303005 bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07003006 {
Behdad Esfahbod05f21302019-03-29 22:40:13 -07003007 return
3008 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07003009 | hb_map (hb_add (this))
3010 | hb_map ([&] (const ChainRule &_) { return _.intersects (glyphs, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07003011 | hb_any
3012 ;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07003013 }
Qunxin Liub8a58a02021-01-10 15:50:04 -08003014 void closure (hb_closure_context_t *c, unsigned value, ChainContextClosureLookupContext &lookup_context) const
Behdad Esfahbod31081f72012-04-23 16:54:58 -04003015 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04303016 if (unlikely (c->lookup_limit_exceeded ())) return;
Garret Rieger4ad686b2020-03-25 23:32:28 -07003017
Behdad Esfahbod05f21302019-03-29 22:40:13 -07003018 return
3019 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07003020 | hb_map (hb_add (this))
Qunxin Liub8a58a02021-01-10 15:50:04 -08003021 | hb_apply ([&] (const ChainRule &_) { _.closure (c, value, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07003022 ;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04003023 }
3024
Garret Riegerad241f92020-09-28 15:26:13 -07003025 void closure_lookups (hb_closure_lookups_context_t *c,
3026 ChainContextClosureLookupContext &lookup_context) const
Qunxin Liu0b39c482019-10-22 16:00:43 -07003027 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04303028 if (unlikely (c->lookup_limit_exceeded ())) return;
Garret Rieger4ad686b2020-03-25 23:32:28 -07003029
Qunxin Liu0b39c482019-10-22 16:00:43 -07003030 + hb_iter (rule)
3031 | hb_map (hb_add (this))
Garret Riegere31c2692020-09-28 16:51:25 -07003032 | hb_apply ([&] (const ChainRule &_) { _.closure_lookups (c, lookup_context); })
Qunxin Liu0b39c482019-10-22 16:00:43 -07003033 ;
3034 }
3035
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303036 void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05003037 {
Behdad Esfahbod05f21302019-03-29 22:40:13 -07003038 return
3039 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07003040 | hb_map (hb_add (this))
3041 | hb_apply ([&] (const ChainRule &_) { _.collect_glyphs (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07003042 ;
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05003043 }
3044
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303045 bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003046 {
Behdad Esfahbod05f21302019-03-29 22:40:13 -07003047 return
3048 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07003049 | hb_map (hb_add (this))
3050 | hb_map ([&] (const ChainRule &_) { return _.would_apply (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07003051 | hb_any
3052 ;
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003053 }
3054
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303055 bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04003056 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05003057 TRACE_APPLY (this);
Behdad Esfahbod05f21302019-03-29 22:40:13 -07003058 return_trace (
3059 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07003060 | hb_map (hb_add (this))
3061 | hb_map ([&] (const ChainRule &_) { return _.apply (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07003062 | hb_any
3063 )
3064 ;
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04003065 }
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003066
Qunxin Liub66094a2019-09-30 16:19:18 -07003067 bool subset (hb_subset_context_t *c,
Qunxin Liu593e58c2020-05-20 18:00:25 -07003068 const hb_map_t *lookup_map,
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04303069 const hb_map_t *backtrack_klass_map = nullptr,
3070 const hb_map_t *input_klass_map = nullptr,
3071 const hb_map_t *lookahead_klass_map = nullptr) const
Qunxin Liub66094a2019-09-30 16:19:18 -07003072 {
3073 TRACE_SUBSET (this);
3074
3075 auto snap = c->serializer->snapshot ();
3076 auto *out = c->serializer->start_embed (*this);
3077 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
3078
Behdad Esfahbodad28f972021-03-31 12:49:14 -06003079 for (const Offset16To<ChainRule>& _ : rule)
Qunxin Liub66094a2019-09-30 16:19:18 -07003080 {
3081 if (!_) continue;
Garret Riegerc2cc5662021-09-22 14:15:55 -07003082 auto o_snap = c->serializer->snapshot ();
Qunxin Liub66094a2019-09-30 16:19:18 -07003083 auto *o = out->rule.serialize_append (c->serializer);
3084 if (unlikely (!o)) continue;
Ebrahim Byagowiaca63902019-10-22 00:06:46 +03303085
ariza188a0a42020-03-07 11:02:36 -08003086 if (!o->serialize_subset (c, _, this,
Qunxin Liu593e58c2020-05-20 18:00:25 -07003087 lookup_map,
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04303088 backtrack_klass_map,
3089 input_klass_map,
3090 lookahead_klass_map))
Qunxin Liub66094a2019-09-30 16:19:18 -07003091 {
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04303092 out->rule.pop ();
3093 c->serializer->revert (o_snap);
Qunxin Liub66094a2019-09-30 16:19:18 -07003094 }
3095 }
3096
3097 bool ret = bool (out->rule);
3098 if (!ret) c->serializer->revert (snap);
Ebrahim Byagowiaca63902019-10-22 00:06:46 +03303099
Qunxin Liub66094a2019-09-30 16:19:18 -07003100 return_trace (ret);
3101 }
3102
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303103 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03003104 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05003105 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003106 return_trace (rule.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04003107 }
3108
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04003109 protected:
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06003110 Array16OfOffset16To<ChainRule>
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04003111 rule; /* Array of ChainRule tables
3112 * ordered by preference */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04003113 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04003114 DEFINE_SIZE_ARRAY (2, rule);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003115};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003116
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06003117template <typename Types>
3118struct ChainContextFormat1_4
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04003119{
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06003120 using ChainRuleSet = OT::ChainRuleSet<Types>;
3121
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303122 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07003123 {
3124 struct ChainContextClosureLookupContext lookup_context = {
Qunxin Liub8a58a02021-01-10 15:50:04 -08003125 {intersects_glyph, intersected_glyph},
3126 ContextFormat::SimpleContext,
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07003127 {nullptr, nullptr, nullptr}
3128 };
Behdad Esfahbod05f21302019-03-29 22:40:13 -07003129
3130 return
3131 + hb_zip (this+coverage, ruleSet)
3132 | hb_filter (*glyphs, hb_first)
3133 | hb_map (hb_second)
Behdad Esfahbod23768672019-05-15 21:57:26 -07003134 | hb_map (hb_add (this))
3135 | hb_map ([&] (const ChainRuleSet &_) { return _.intersects (glyphs, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07003136 | hb_any
3137 ;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07003138 }
3139
Qunxin Liub4fc5932020-12-09 10:44:18 -08003140 bool may_have_non_1to1 () const
3141 { return true; }
3142
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303143 void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04003144 {
Behdad Esfahbod00dfbbc2022-07-21 11:39:32 -06003145 hb_set_t& cur_active_glyphs = c->push_cur_active_glyphs ();
3146 get_coverage ().intersect_set (c->previous_parent_active_glyphs (),
Garret Rieger4e2f4092022-01-31 12:20:32 -08003147 cur_active_glyphs);
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08003148
Behdad Esfahbod31081f72012-04-23 16:54:58 -04003149 struct ChainContextClosureLookupContext lookup_context = {
Qunxin Liub8a58a02021-01-10 15:50:04 -08003150 {intersects_glyph, intersected_glyph},
3151 ContextFormat::SimpleContext,
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02003152 {nullptr, nullptr, nullptr}
Behdad Esfahbod31081f72012-04-23 16:54:58 -04003153 };
Behdad Esfahbod05f21302019-03-29 22:40:13 -07003154
Qunxin Liub8a58a02021-01-10 15:50:04 -08003155 + hb_zip (this+coverage, hb_range ((unsigned) ruleSet.len))
Garret Rieger4e2f4092022-01-31 12:20:32 -08003156 | hb_filter ([&] (hb_codepoint_t _) {
3157 return c->previous_parent_active_glyphs ().has (_);
3158 }, hb_first)
Qunxin Liub8a58a02021-01-10 15:50:04 -08003159 | hb_map ([&](const hb_pair_t<hb_codepoint_t, unsigned> _) { return hb_pair_t<unsigned, const ChainRuleSet&> (_.first, this+ruleSet[_.second]); })
3160 | hb_apply ([&] (const hb_pair_t<unsigned, const ChainRuleSet&>& _) { _.second.closure (c, _.first, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07003161 ;
Garret Riegerbc899652022-01-28 13:54:10 -08003162
3163 c->pop_cur_done_glyphs ();
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04003164 }
3165
Qunxin Liu0b39c482019-10-22 16:00:43 -07003166 void closure_lookups (hb_closure_lookups_context_t *c) const
3167 {
Garret Riegerad241f92020-09-28 15:26:13 -07003168 struct ChainContextClosureLookupContext lookup_context = {
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08003169 {intersects_glyph, intersected_glyph},
3170 ContextFormat::SimpleContext,
Garret Riegerad241f92020-09-28 15:26:13 -07003171 {nullptr, nullptr, nullptr}
3172 };
3173
3174 + hb_zip (this+coverage, ruleSet)
3175 | hb_filter (*c->glyphs, hb_first)
3176 | hb_map (hb_second)
Qunxin Liu0b39c482019-10-22 16:00:43 -07003177 | hb_map (hb_add (this))
Garret Riegere31c2692020-09-28 16:51:25 -07003178 | hb_apply ([&] (const ChainRuleSet &_) { _.closure_lookups (c, lookup_context); })
Qunxin Liu0b39c482019-10-22 16:00:43 -07003179 ;
3180 }
3181
Qunxin Liu8200e482020-02-26 13:11:42 -08003182 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
3183
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303184 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbod26514d52012-11-23 18:13:48 -05003185 {
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07003186 (this+coverage).collect_coverage (c->input);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05003187
3188 struct ChainContextCollectGlyphsLookupContext lookup_context = {
3189 {collect_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02003190 {nullptr, nullptr, nullptr}
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05003191 };
3192
Behdad Esfahbod05f21302019-03-29 22:40:13 -07003193 + hb_iter (ruleSet)
Behdad Esfahbod23768672019-05-15 21:57:26 -07003194 | hb_map (hb_add (this))
3195 | hb_apply ([&] (const ChainRuleSet &_) { _.collect_glyphs (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07003196 ;
Behdad Esfahbod26514d52012-11-23 18:13:48 -05003197 }
3198
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303199 bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003200 {
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05003201 const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003202 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06003203 {{match_glyph, match_glyph, match_glyph}},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02003204 {nullptr, nullptr, nullptr}
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003205 };
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07003206 return rule_set.would_apply (c, lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003207 }
3208
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303209 const Coverage &get_coverage () const { return this+coverage; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05003210
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303211 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04003212 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05003213 TRACE_APPLY (this);
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05003214 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003215 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04003216
3217 const ChainRuleSet &rule_set = this+ruleSet[index];
Behdad Esfahbod31081f72012-04-23 16:54:58 -04003218 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06003219 {{match_glyph, match_glyph, match_glyph}},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02003220 {nullptr, nullptr, nullptr}
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04003221 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003222 return_trace (rule_set.apply (c, lookup_context));
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003223 }
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04003224
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303225 bool subset (hb_subset_context_t *c) const
Behdad Esfahbod339d3602018-09-03 17:33:34 -07003226 {
3227 TRACE_SUBSET (this);
Garret Riegere5835052020-09-29 11:05:08 -07003228 const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
Qunxin Liub66094a2019-09-30 16:19:18 -07003229 const hb_map_t &glyph_map = *c->plan->glyph_map;
3230
3231 auto *out = c->serializer->start_embed (*this);
3232 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
3233 out->format = format;
3234
Qunxin Liu593e58c2020-05-20 18:00:25 -07003235 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 -07003236 hb_sorted_vector_t<hb_codepoint_t> new_coverage;
3237 + hb_zip (this+coverage, ruleSet)
3238 | hb_filter (glyphset, hb_first)
Qunxin Liu593e58c2020-05-20 18:00:25 -07003239 | hb_filter (subset_offset_array (c, out->ruleSet, this, lookup_map), hb_second)
Qunxin Liub66094a2019-09-30 16:19:18 -07003240 | hb_map (hb_first)
3241 | hb_map (glyph_map)
3242 | hb_sink (new_coverage)
3243 ;
3244
Garret Rieger085aa652021-06-14 16:47:45 -07003245 out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
Qunxin Liub66094a2019-09-30 16:19:18 -07003246 return_trace (bool (new_coverage));
Behdad Esfahbod339d3602018-09-03 17:33:34 -07003247 }
3248
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303249 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03003250 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05003251 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003252 return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04003253 }
3254
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04003255 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01003256 HBUINT16 format; /* Format identifier--format = 1 */
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06003257 typename Types::template OffsetTo<Coverage>
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04003258 coverage; /* Offset to Coverage table--from
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003259 * beginning of table */
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06003260 Array16Of<typename Types::template OffsetTo<ChainRuleSet>>
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04003261 ruleSet; /* Array of ChainRuleSet tables
3262 * ordered by Coverage Index */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04003263 public:
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06003264 DEFINE_SIZE_ARRAY (2 + 2 * Types::size, ruleSet);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003265};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003266
Behdad Esfahboda90c5af2022-07-08 13:11:47 -06003267template <typename Types>
3268struct ChainContextFormat2_5
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04003269{
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06003270 using ChainRuleSet = OT::ChainRuleSet<SmallTypes>;
3271
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303272 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07003273 {
3274 if (!(this+coverage).intersects (glyphs))
3275 return false;
3276
3277 const ClassDef &backtrack_class_def = this+backtrackClassDef;
3278 const ClassDef &input_class_def = this+inputClassDef;
3279 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
3280
3281 struct ChainContextClosureLookupContext lookup_context = {
Qunxin Liub8a58a02021-01-10 15:50:04 -08003282 {intersects_class, intersected_class_glyphs},
3283 ContextFormat::ClassBasedContext,
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07003284 {&backtrack_class_def,
3285 &input_class_def,
3286 &lookahead_class_def}
3287 };
3288
Qunxin Liu540f19b2021-10-29 17:11:53 -07003289 hb_set_t retained_coverage_glyphs;
Behdad Esfahbod00dfbbc2022-07-21 11:39:32 -06003290 (this+coverage).intersect_set (*glyphs, retained_coverage_glyphs);
Qunxin Liu540f19b2021-10-29 17:11:53 -07003291
3292 hb_set_t coverage_glyph_classes;
3293 input_class_def.intersected_classes (&retained_coverage_glyphs, &coverage_glyph_classes);
3294
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07003295 return
Behdad Esfahbod26111a12020-06-28 02:59:47 -07003296 + hb_iter (ruleSet)
3297 | hb_map (hb_add (this))
3298 | hb_enumerate
3299 | hb_map ([&] (const hb_pair_t<unsigned, const ChainRuleSet &> p)
Behdad Esfahbod78d35f02019-05-15 18:15:05 -07003300 { return input_class_def.intersects_class (glyphs, p.first) &&
Qunxin Liu540f19b2021-10-29 17:11:53 -07003301 coverage_glyph_classes.has (p.first) &&
Behdad Esfahbod26111a12020-06-28 02:59:47 -07003302 p.second.intersects (glyphs, lookup_context); })
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07003303 | hb_any
3304 ;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07003305 }
Qunxin Liub4fc5932020-12-09 10:44:18 -08003306
3307 bool may_have_non_1to1 () const
3308 { return true; }
3309
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303310 void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04003311 {
Behdad Esfahbod31081f72012-04-23 16:54:58 -04003312 if (!(this+coverage).intersects (c->glyphs))
Behdad Esfahbod5caece62012-04-23 23:03:12 -04003313 return;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04003314
Behdad Esfahbod00dfbbc2022-07-21 11:39:32 -06003315 hb_set_t& cur_active_glyphs = c->push_cur_active_glyphs ();
3316 get_coverage ().intersect_set (c->previous_parent_active_glyphs (),
Garret Rieger4e2f4092022-01-31 12:20:32 -08003317 cur_active_glyphs);
3318
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08003319
Behdad Esfahbod31081f72012-04-23 16:54:58 -04003320 const ClassDef &backtrack_class_def = this+backtrackClassDef;
3321 const ClassDef &input_class_def = this+inputClassDef;
3322 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
3323
3324 struct ChainContextClosureLookupContext lookup_context = {
Qunxin Liub8a58a02021-01-10 15:50:04 -08003325 {intersects_class, intersected_class_glyphs},
3326 ContextFormat::ClassBasedContext,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04003327 {&backtrack_class_def,
3328 &input_class_def,
3329 &lookahead_class_def}
3330 };
3331
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07003332 + hb_enumerate (ruleSet)
Behdad Esfahbod78d35f02019-05-15 18:15:05 -07003333 | hb_filter ([&] (unsigned _)
Garret Riegerbc899652022-01-28 13:54:10 -08003334 { return input_class_def.intersects_class (&c->parent_active_glyphs (), _); },
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07003335 hb_first)
Behdad Esfahboda90c5af2022-07-08 13:11:47 -06003336 | hb_apply ([&] (const hb_pair_t<unsigned, const typename Types::template OffsetTo<ChainRuleSet>&> _)
Qunxin Liub8a58a02021-01-10 15:50:04 -08003337 {
3338 const ChainRuleSet& chainrule_set = this+_.second;
3339 chainrule_set.closure (c, _.first, lookup_context);
3340 })
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07003341 ;
Garret Riegerbc899652022-01-28 13:54:10 -08003342
3343 c->pop_cur_done_glyphs ();
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04003344 }
3345
Qunxin Liu0b39c482019-10-22 16:00:43 -07003346 void closure_lookups (hb_closure_lookups_context_t *c) const
3347 {
Garret Riegerad241f92020-09-28 15:26:13 -07003348 if (!(this+coverage).intersects (c->glyphs))
3349 return;
3350
3351 const ClassDef &backtrack_class_def = this+backtrackClassDef;
3352 const ClassDef &input_class_def = this+inputClassDef;
3353 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
3354
3355 struct ChainContextClosureLookupContext lookup_context = {
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08003356 {intersects_class, intersected_class_glyphs},
3357 ContextFormat::ClassBasedContext,
Garret Riegerad241f92020-09-28 15:26:13 -07003358 {&backtrack_class_def,
3359 &input_class_def,
3360 &lookahead_class_def}
3361 };
3362
Qunxin Liu0b39c482019-10-22 16:00:43 -07003363 + hb_iter (ruleSet)
3364 | hb_map (hb_add (this))
Garret Riegerad241f92020-09-28 15:26:13 -07003365 | hb_enumerate
Behdad Esfahbod6e1afac2021-02-09 18:48:46 -07003366 | hb_filter([&] (unsigned klass)
3367 { return input_class_def.intersects_class (c->glyphs, klass); }, hb_first)
Garret Riegerad241f92020-09-28 15:26:13 -07003368 | hb_map (hb_second)
3369 | hb_apply ([&] (const ChainRuleSet &_)
3370 { _.closure_lookups (c, lookup_context); })
Qunxin Liu0b39c482019-10-22 16:00:43 -07003371 ;
3372 }
3373
Qunxin Liu8200e482020-02-26 13:11:42 -08003374 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
3375
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303376 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbod26514d52012-11-23 18:13:48 -05003377 {
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07003378 (this+coverage).collect_coverage (c->input);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05003379
Behdad Esfahbod11fba792013-01-02 23:36:37 -06003380 const ClassDef &backtrack_class_def = this+backtrackClassDef;
3381 const ClassDef &input_class_def = this+inputClassDef;
3382 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
3383
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05003384 struct ChainContextCollectGlyphsLookupContext lookup_context = {
3385 {collect_class},
Behdad Esfahbod11fba792013-01-02 23:36:37 -06003386 {&backtrack_class_def,
3387 &input_class_def,
3388 &lookahead_class_def}
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05003389 };
3390
Behdad Esfahbod05f21302019-03-29 22:40:13 -07003391 + hb_iter (ruleSet)
Behdad Esfahbod23768672019-05-15 21:57:26 -07003392 | hb_map (hb_add (this))
3393 | hb_apply ([&] (const ChainRuleSet &_) { _.collect_glyphs (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07003394 ;
Behdad Esfahbod26514d52012-11-23 18:13:48 -05003395 }
3396
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303397 bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003398 {
Behdad Esfahbod11fba792013-01-02 23:36:37 -06003399 const ClassDef &backtrack_class_def = this+backtrackClassDef;
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003400 const ClassDef &input_class_def = this+inputClassDef;
Behdad Esfahbod11fba792013-01-02 23:36:37 -06003401 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003402
Behdad Esfahbod2dc11412012-11-24 19:16:34 -05003403 unsigned int index = input_class_def.get_class (c->glyphs[0]);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003404 const ChainRuleSet &rule_set = this+ruleSet[index];
3405 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06003406 {{match_class, match_class, match_class}},
Behdad Esfahbod11fba792013-01-02 23:36:37 -06003407 {&backtrack_class_def,
3408 &input_class_def,
3409 &lookahead_class_def}
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003410 };
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07003411 return rule_set.would_apply (c, lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003412 }
3413
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303414 const Coverage &get_coverage () const { return this+coverage; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05003415
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06003416 unsigned cache_cost () const
3417 {
Behdad Esfahbod21346af2022-06-07 14:41:39 -06003418 unsigned c = (this+lookaheadClassDef).cost () * ruleSet.len;
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06003419 return c >= 4 ? c : 0;
3420 }
Behdad Esfahbod5963cf42022-06-07 09:12:45 -06003421 bool cache_func (hb_ot_apply_context_t *c, bool enter) const
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06003422 {
Behdad Esfahbod5963cf42022-06-07 09:12:45 -06003423 if (enter)
3424 {
3425 if (!HB_BUFFER_TRY_ALLOCATE_VAR (c->buffer, syllable))
3426 return false;
3427 auto &info = c->buffer->info;
3428 unsigned count = c->buffer->len;
3429 for (unsigned i = 0; i < count; i++)
3430 info[i].syllable() = 255;
3431 c->new_syllables = 255;
3432 return true;
3433 }
3434 else
3435 {
3436 c->new_syllables = (unsigned) -1;
3437 HB_BUFFER_DEALLOCATE_VAR (c->buffer, syllable);
3438 return true;
3439 }
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06003440 }
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06003441
3442 bool apply (hb_ot_apply_context_t *c, bool cached = false) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04003443 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05003444 TRACE_APPLY (this);
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05003445 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003446 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04003447
3448 const ClassDef &backtrack_class_def = this+backtrackClassDef;
3449 const ClassDef &input_class_def = this+inputClassDef;
3450 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
3451
Behdad Esfahboda90c5af2022-07-08 13:11:47 -06003452 /* For ChainContextFormat2_5 we cache the LookaheadClassDef instead of InputClassDef.
Behdad Esfahbodbfee6832022-06-07 11:41:05 -06003453 * The reason is that most heavy fonts want to identify a glyph in context and apply
3454 * a lookup to it. In this scenario, the length of the input sequence is one, whereas
3455 * the lookahead / backtrack are typically longer. The one glyph in input sequence is
3456 * looked-up below and no input glyph is looked up in individual rules, whereas the
3457 * lookahead and backtrack glyphs are tried. Since we match lookahead before backtrack,
3458 * we should cache lookahead. This decisions showed a 20% improvement in shaping of
3459 * the Gulzar font.
3460 */
3461
Behdad Esfahbod31081f72012-04-23 16:54:58 -04003462 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06003463 {{cached && &backtrack_class_def == &input_class_def ? match_class_cached : match_class,
Behdad Esfahbodbfee6832022-06-07 11:41:05 -06003464 cached && &input_class_def == &lookahead_class_def ? match_class_cached : match_class,
3465 cached ? match_class_cached : match_class}},
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04003466 {&backtrack_class_def,
3467 &input_class_def,
3468 &lookahead_class_def}
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04003469 };
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06003470
Behdad Esfahbodbfee6832022-06-07 11:41:05 -06003471 index = input_class_def.get_class (c->buffer->cur().codepoint);
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06003472 const ChainRuleSet &rule_set = this+ruleSet[index];
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003473 return_trace (rule_set.apply (c, lookup_context));
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003474 }
3475
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303476 bool subset (hb_subset_context_t *c) const
Behdad Esfahbod339d3602018-09-03 17:33:34 -07003477 {
3478 TRACE_SUBSET (this);
Qunxin Liub66094a2019-09-30 16:19:18 -07003479 auto *out = c->serializer->start_embed (*this);
3480 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
3481 out->format = format;
ariza188a0a42020-03-07 11:02:36 -08003482 out->coverage.serialize_subset (c, coverage, this);
Qunxin Liub66094a2019-09-30 16:19:18 -07003483
3484 hb_map_t backtrack_klass_map;
Qunxin Liub66094a2019-09-30 16:19:18 -07003485 hb_map_t input_klass_map;
Qunxin Liub66094a2019-09-30 16:19:18 -07003486 hb_map_t lookahead_klass_map;
Behdad Esfahboddfa9d7a2021-02-11 11:08:52 -07003487
3488 out->backtrackClassDef.serialize_subset (c, backtrackClassDef, this, &backtrack_klass_map);
3489 // TODO: subset inputClassDef based on glyphs survived in Coverage subsetting
3490 out->inputClassDef.serialize_subset (c, inputClassDef, this, &input_klass_map);
ariza188a0a42020-03-07 11:02:36 -08003491 out->lookaheadClassDef.serialize_subset (c, lookaheadClassDef, this, &lookahead_klass_map);
Behdad Esfahboddfa9d7a2021-02-11 11:08:52 -07003492
3493 if (unlikely (!c->serializer->propagate_error (backtrack_klass_map,
3494 input_klass_map,
3495 lookahead_klass_map)))
Garret Rieger06dbb6a2020-07-31 15:56:14 -07003496 return_trace (false);
Qunxin Liub66094a2019-09-30 16:19:18 -07003497
Qunxin Liu540f19b2021-10-29 17:11:53 -07003498 const hb_set_t* glyphset = c->plan->glyphset_gsub ();
3499 hb_set_t retained_coverage_glyphs;
Behdad Esfahbod00dfbbc2022-07-21 11:39:32 -06003500 (this+coverage).intersect_set (*glyphset, retained_coverage_glyphs);
Qunxin Liu540f19b2021-10-29 17:11:53 -07003501
3502 hb_set_t coverage_glyph_classes;
3503 (this+inputClassDef).intersected_classes (&retained_coverage_glyphs, &coverage_glyph_classes);
3504
Garret Riegerdc375552020-09-25 13:08:46 -07003505 int non_zero_index = -1, index = 0;
Qunxin Liub66094a2019-09-30 16:19:18 -07003506 bool ret = true;
Qunxin Liu593e58c2020-05-20 18:00:25 -07003507 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 -07003508 auto last_non_zero = c->serializer->snapshot ();
Qunxin Liu540f19b2021-10-29 17:11:53 -07003509 for (const auto& _ : + hb_enumerate (ruleSet)
3510 | hb_filter (input_klass_map, hb_first))
Qunxin Liub66094a2019-09-30 16:19:18 -07003511 {
3512 auto *o = out->ruleSet.serialize_append (c->serializer);
3513 if (unlikely (!o))
3514 {
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04303515 ret = false;
3516 break;
Qunxin Liub66094a2019-09-30 16:19:18 -07003517 }
Qunxin Liu540f19b2021-10-29 17:11:53 -07003518 if (coverage_glyph_classes.has (_.first) &&
3519 o->serialize_subset (c, _.second, this,
Qunxin Liu593e58c2020-05-20 18:00:25 -07003520 lookup_map,
3521 &backtrack_klass_map,
3522 &input_klass_map,
3523 &lookahead_klass_map))
Garret Riegerdc375552020-09-25 13:08:46 -07003524 {
3525 last_non_zero = c->serializer->snapshot ();
Ebrahim Byagowi5a7cc7f2020-07-29 08:33:32 +04303526 non_zero_index = index;
Garret Riegerdc375552020-09-25 13:08:46 -07003527 }
Qunxin Liu593e58c2020-05-20 18:00:25 -07003528
3529 index++;
Qunxin Liub66094a2019-09-30 16:19:18 -07003530 }
3531
Qunxin Liu540f19b2021-10-29 17:11:53 -07003532 if (!ret || non_zero_index == -1) return_trace (false);
Qunxin Liub66094a2019-09-30 16:19:18 -07003533
Garret Riegerdc375552020-09-25 13:08:46 -07003534 // prune empty trailing ruleSets
3535 if (index > non_zero_index) {
3536 c->serializer->revert (last_non_zero);
3537 out->ruleSet.len = non_zero_index + 1;
Qunxin Liub66094a2019-09-30 16:19:18 -07003538 }
3539
3540 return_trace (bool (out->ruleSet));
Behdad Esfahbod339d3602018-09-03 17:33:34 -07003541 }
3542
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303543 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03003544 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05003545 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003546 return_trace (coverage.sanitize (c, this) &&
3547 backtrackClassDef.sanitize (c, this) &&
3548 inputClassDef.sanitize (c, this) &&
3549 lookaheadClassDef.sanitize (c, this) &&
3550 ruleSet.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04003551 }
3552
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04003553 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01003554 HBUINT16 format; /* Format identifier--format = 2 */
Behdad Esfahboda90c5af2022-07-08 13:11:47 -06003555 typename Types::template OffsetTo<Coverage>
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04003556 coverage; /* Offset to Coverage table--from
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003557 * beginning of table */
Behdad Esfahboda90c5af2022-07-08 13:11:47 -06003558 typename Types::template OffsetTo<ClassDef>
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04003559 backtrackClassDef; /* Offset to glyph ClassDef table
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003560 * containing backtrack sequence
3561 * data--from beginning of table */
Behdad Esfahboda90c5af2022-07-08 13:11:47 -06003562 typename Types::template OffsetTo<ClassDef>
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04003563 inputClassDef; /* Offset to glyph ClassDef
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003564 * table containing input sequence
3565 * data--from beginning of table */
Behdad Esfahboda90c5af2022-07-08 13:11:47 -06003566 typename Types::template OffsetTo<ClassDef>
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04003567 lookaheadClassDef; /* Offset to glyph ClassDef table
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003568 * containing lookahead sequence
3569 * data--from beginning of table */
Behdad Esfahboda90c5af2022-07-08 13:11:47 -06003570 Array16Of<typename Types::template OffsetTo<ChainRuleSet>>
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04003571 ruleSet; /* Array of ChainRuleSet tables
3572 * ordered by class */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04003573 public:
Behdad Esfahboda90c5af2022-07-08 13:11:47 -06003574 DEFINE_SIZE_ARRAY (4 + 4 * Types::size, ruleSet);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003575};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003576
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04003577struct ChainContextFormat3
3578{
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06003579 using RuleSet = OT::RuleSet<SmallTypes>;
3580
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303581 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07003582 {
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003583 const auto &input = StructAfter<decltype (inputX)> (backtrack);
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07003584
3585 if (!(this+input[0]).intersects (glyphs))
3586 return false;
3587
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003588 const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07003589 struct ChainContextClosureLookupContext lookup_context = {
Qunxin Liub8a58a02021-01-10 15:50:04 -08003590 {intersects_coverage, intersected_coverage_glyphs},
3591 ContextFormat::CoverageBasedContext,
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07003592 {this, this, this}
3593 };
3594 return chain_context_intersects (glyphs,
3595 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
3596 input.len, (const HBUINT16 *) input.arrayZ + 1,
3597 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
3598 lookup_context);
3599 }
3600
Qunxin Liub4fc5932020-12-09 10:44:18 -08003601 bool may_have_non_1to1 () const
3602 { return true; }
3603
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303604 void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04003605 {
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003606 const auto &input = StructAfter<decltype (inputX)> (backtrack);
Behdad Esfahbod5caece62012-04-23 23:03:12 -04003607
3608 if (!(this+input[0]).intersects (c->glyphs))
3609 return;
3610
Behdad Esfahbod00dfbbc2022-07-21 11:39:32 -06003611 hb_set_t& cur_active_glyphs = c->push_cur_active_glyphs ();
3612 get_coverage ().intersect_set (c->previous_parent_active_glyphs (),
Garret Rieger4e2f4092022-01-31 12:20:32 -08003613 cur_active_glyphs);
3614
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08003615
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003616 const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
3617 const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
Behdad Esfahbod5caece62012-04-23 23:03:12 -04003618 struct ChainContextClosureLookupContext lookup_context = {
Qunxin Liub8a58a02021-01-10 15:50:04 -08003619 {intersects_coverage, intersected_coverage_glyphs},
3620 ContextFormat::CoverageBasedContext,
Behdad Esfahbod5caece62012-04-23 23:03:12 -04003621 {this, this, this}
3622 };
3623 chain_context_closure_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07003624 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
3625 input.len, (const HBUINT16 *) input.arrayZ + 1,
3626 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
3627 lookup.len, lookup.arrayZ,
Qunxin Liub8a58a02021-01-10 15:50:04 -08003628 0, lookup_context);
Garret Riegerbc899652022-01-28 13:54:10 -08003629
3630 c->pop_cur_done_glyphs ();
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04003631 }
3632
Qunxin Liu0b39c482019-10-22 16:00:43 -07003633 void closure_lookups (hb_closure_lookups_context_t *c) const
3634 {
Garret Riegera5c0ec72020-09-25 14:57:20 -07003635 if (!intersects (c->glyphs))
3636 return;
3637
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003638 const auto &input = StructAfter<decltype (inputX)> (backtrack);
3639 const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
3640 const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
Qunxin Liu0b39c482019-10-22 16:00:43 -07003641 recurse_lookups (c, lookup.len, lookup.arrayZ);
3642 }
3643
Qunxin Liu8200e482020-02-26 13:11:42 -08003644 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
3645
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303646 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbod26514d52012-11-23 18:13:48 -05003647 {
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003648 const auto &input = StructAfter<decltype (inputX)> (backtrack);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05003649
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07003650 (this+input[0]).collect_coverage (c->input);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05003651
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003652 const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
3653 const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
3654
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05003655 struct ChainContextCollectGlyphsLookupContext lookup_context = {
3656 {collect_coverage},
3657 {this, this, this}
3658 };
3659 chain_context_collect_glyphs_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07003660 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
3661 input.len, (const HBUINT16 *) input.arrayZ + 1,
3662 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
3663 lookup.len, lookup.arrayZ,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05003664 lookup_context);
Behdad Esfahbod26514d52012-11-23 18:13:48 -05003665 }
3666
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303667 bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003668 {
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003669 const auto &input = StructAfter<decltype (inputX)> (backtrack);
3670 const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
3671 const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003672 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06003673 {{match_coverage, match_coverage, match_coverage}},
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003674 {this, this, this}
3675 };
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07003676 return chain_context_would_apply_lookup (c,
3677 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
3678 input.len, (const HBUINT16 *) input.arrayZ + 1,
3679 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
3680 lookup.len, lookup.arrayZ, lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003681 }
3682
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303683 const Coverage &get_coverage () const
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05003684 {
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003685 const auto &input = StructAfter<decltype (inputX)> (backtrack);
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05003686 return this+input[0];
3687 }
3688
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303689 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04003690 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05003691 TRACE_APPLY (this);
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003692 const auto &input = StructAfter<decltype (inputX)> (backtrack);
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04003693
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05003694 unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003695 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003696
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003697 const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
3698 const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04003699 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06003700 {{match_coverage, match_coverage, match_coverage}},
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04003701 {this, this, this}
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04003702 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003703 return_trace (chain_context_apply_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07003704 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
3705 input.len, (const HBUINT16 *) input.arrayZ + 1,
3706 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
3707 lookup.len, lookup.arrayZ, lookup_context));
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003708 }
3709
Qunxin Liub66094a2019-09-30 16:19:18 -07003710 template<typename Iterator,
3711 hb_requires (hb_is_iterator (Iterator))>
Ebrahim Byagowi07acd1a2020-03-08 23:39:24 +03303712 bool serialize_coverage_offsets (hb_subset_context_t *c, Iterator it, const void* base) const
Qunxin Liub66094a2019-09-30 16:19:18 -07003713 {
3714 TRACE_SERIALIZE (this);
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06003715 auto *out = c->serializer->start_embed<Array16OfOffset16To<Coverage>> ();
Qunxin Liub66094a2019-09-30 16:19:18 -07003716
Garret Rieger90eb1a42020-09-25 12:36:32 -07003717 if (unlikely (!c->serializer->allocate_size<HBUINT16> (HBUINT16::static_size)))
Garret Rieger940e1c62020-09-28 17:22:01 -07003718 return_trace (false);
Qunxin Liub66094a2019-09-30 16:19:18 -07003719
Garret Rieger940e1c62020-09-28 17:22:01 -07003720 for (auto& offset : it) {
3721 auto *o = out->serialize_append (c->serializer);
3722 if (unlikely (!o) || !o->serialize_subset (c, offset, base))
3723 return_trace (false);
3724 }
Qunxin Liub66094a2019-09-30 16:19:18 -07003725
Garret Rieger940e1c62020-09-28 17:22:01 -07003726 return_trace (true);
Qunxin Liub66094a2019-09-30 16:19:18 -07003727 }
3728
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303729 bool subset (hb_subset_context_t *c) const
Behdad Esfahbod339d3602018-09-03 17:33:34 -07003730 {
3731 TRACE_SUBSET (this);
Qunxin Liub66094a2019-09-30 16:19:18 -07003732
3733 auto *out = c->serializer->start_embed (this);
3734 if (unlikely (!out)) return_trace (false);
3735 if (unlikely (!c->serializer->embed (this->format))) return_trace (false);
3736
ariza188a0a42020-03-07 11:02:36 -08003737 if (!serialize_coverage_offsets (c, backtrack.iter (), this))
Qunxin Liub66094a2019-09-30 16:19:18 -07003738 return_trace (false);
Ebrahim Byagowiaca63902019-10-22 00:06:46 +03303739
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003740 const auto &input = StructAfter<decltype (inputX)> (backtrack);
ariza188a0a42020-03-07 11:02:36 -08003741 if (!serialize_coverage_offsets (c, input.iter (), this))
Qunxin Liub66094a2019-09-30 16:19:18 -07003742 return_trace (false);
3743
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003744 const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
ariza188a0a42020-03-07 11:02:36 -08003745 if (!serialize_coverage_offsets (c, lookahead.iter (), this))
Qunxin Liub66094a2019-09-30 16:19:18 -07003746 return_trace (false);
Ebrahim Byagowiaca63902019-10-22 00:06:46 +03303747
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003748 const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
Qunxin Liu37379f82021-09-02 11:54:37 -07003749 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 -07003750
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003751 HBUINT16 *lookupCount = c->serializer->copy<HBUINT16> (lookup.len);
Qunxin Liu36ed56b2021-09-23 10:51:21 -07003752 if (!lookupCount) return_trace (false);
Qunxin Liu37379f82021-09-02 11:54:37 -07003753
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003754 unsigned count = serialize_lookuprecord_array (c->serializer, lookup.as_array (), lookup_map);
Qunxin Liu36ed56b2021-09-23 10:51:21 -07003755 return_trace (c->serializer->check_assign (*lookupCount, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
Behdad Esfahbod339d3602018-09-03 17:33:34 -07003756 }
3757
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303758 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03003759 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05003760 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003761 if (!backtrack.sanitize (c, this)) return_trace (false);
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003762 const auto &input = StructAfter<decltype (inputX)> (backtrack);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003763 if (!input.sanitize (c, this)) return_trace (false);
3764 if (!input.len) return_trace (false); /* To be consistent with Context. */
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003765 const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003766 if (!lookahead.sanitize (c, this)) return_trace (false);
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003767 const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003768 return_trace (lookup.sanitize (c));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04003769 }
3770
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04003771 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01003772 HBUINT16 format; /* Format identifier--format = 3 */
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06003773 Array16OfOffset16To<Coverage>
Behdad Esfahbod13ed4402009-05-18 02:14:37 -04003774 backtrack; /* Array of coverage tables
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003775 * in backtracking sequence, in glyph
3776 * sequence order */
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06003777 Array16OfOffset16To<Coverage>
Behdad Esfahbod13ed4402009-05-18 02:14:37 -04003778 inputX ; /* Array of coverage
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003779 * tables in input sequence, in glyph
3780 * sequence order */
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06003781 Array16OfOffset16To<Coverage>
Behdad Esfahbod13ed4402009-05-18 02:14:37 -04003782 lookaheadX; /* Array of coverage tables
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003783 * in lookahead sequence, in glyph
3784 * sequence order */
Behdad Esfahbod5639e252021-03-31 16:04:43 -06003785 Array16Of<LookupRecord>
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04003786 lookupX; /* Array of LookupRecords--in
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04003787 * design order) */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04003788 public:
Behdad Esfahbodbea34c72010-05-10 17:28:16 -04003789 DEFINE_SIZE_MIN (10);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003790};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003791
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04003792struct ChainContext
3793{
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -07003794 template <typename context_t, typename ...Ts>
Behdad Esfahbod83e3eab2019-05-07 20:58:43 -07003795 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04003796 {
Behdad Esfahbod00f6a8e2014-12-12 20:36:49 -08003797 TRACE_DISPATCH (this, u.format);
Behdad Esfahbodf396fbb2015-10-09 12:25:55 -04003798 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04003799 switch (u.format) {
Behdad Esfahbod6d555ce2021-11-02 00:18:22 -06003800 case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
3801 case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
3802 case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
Behdad Esfahbod5a9c7932022-07-22 21:33:15 -06003803#ifndef HB_NO_BEYOND_64K
Behdad Esfahbod1bf8fa22022-07-08 14:22:21 -06003804 case 4: return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...));
Behdad Esfahbodd1f58e52022-07-08 13:25:07 -06003805 case 5: return_trace (c->dispatch (u.format5, std::forward<Ts> (ds)...));
3806#endif
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003807 default:return_trace (c->default_return_value ());
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003808 }
3809 }
3810
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04003811 protected:
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003812 union {
Behdad Esfahboda90c5af2022-07-08 13:11:47 -06003813 HBUINT16 format; /* Format identifier */
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06003814 ChainContextFormat1_4<SmallTypes> format1;
Behdad Esfahboda90c5af2022-07-08 13:11:47 -06003815 ChainContextFormat2_5<SmallTypes> format2;
3816 ChainContextFormat3 format3;
Behdad Esfahbod5a9c7932022-07-22 21:33:15 -06003817#ifndef HB_NO_BEYOND_64K
Behdad Esfahbod1bf8fa22022-07-08 14:22:21 -06003818 ChainContextFormat1_4<MediumTypes> format4;
Behdad Esfahbodd1f58e52022-07-08 13:25:07 -06003819 ChainContextFormat2_5<MediumTypes> format5;
3820#endif
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003821 } u;
3822};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003823
3824
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003825template <typename T>
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003826struct ExtensionFormat1
3827{
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303828 unsigned int get_type () const { return extensionLookupType; }
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003829
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003830 template <typename X>
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303831 const X& get_subtable () const
Behdad Esfahbodad28f972021-03-31 12:49:14 -06003832 { return this + reinterpret_cast<const Offset32To<typename T::SubTable> &> (extensionOffset); }
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003833
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -07003834 template <typename context_t, typename ...Ts>
Behdad Esfahbod83e3eab2019-05-07 20:58:43 -07003835 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003836 {
3837 TRACE_DISPATCH (this, format);
Behdad Esfahbodf396fbb2015-10-09 12:25:55 -04003838 if (unlikely (!c->may_dispatch (this, this))) return_trace (c->no_dispatch_return_value ());
Behdad Esfahbod6d555ce2021-11-02 00:18:22 -06003839 return_trace (get_subtable<typename T::SubTable> ().dispatch (c, get_type (), std::forward<Ts> (ds)...));
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003840 }
3841
Qunxin Liu8200e482020-02-26 13:11:42 -08003842 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
3843 { dispatch (c); }
3844
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003845 /* This is called from may_dispatch() above with hb_sanitize_context_t. */
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303846 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03003847 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05003848 TRACE_SANITIZE (this);
Behdad Esfahbod949f6af2018-01-15 20:44:10 -05003849 return_trace (c->check_struct (this) &&
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07003850 extensionLookupType != T::SubTable::Extension);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04003851 }
3852
Garret Rieger08a49972020-10-06 13:02:12 -07003853 bool subset (hb_subset_context_t *c) const
3854 {
3855 TRACE_SUBSET (this);
3856
3857 auto *out = c->serializer->start_embed (this);
3858 if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
3859
3860 out->format = format;
3861 out->extensionLookupType = extensionLookupType;
3862
3863 const auto& src_offset =
Behdad Esfahbodad28f972021-03-31 12:49:14 -06003864 reinterpret_cast<const Offset32To<typename T::SubTable> &> (extensionOffset);
Garret Rieger08a49972020-10-06 13:02:12 -07003865 auto& dest_offset =
Behdad Esfahbodad28f972021-03-31 12:49:14 -06003866 reinterpret_cast<Offset32To<typename T::SubTable> &> (out->extensionOffset);
Garret Rieger08a49972020-10-06 13:02:12 -07003867
3868 return_trace (dest_offset.serialize_subset (c, src_offset, this, get_type ()));
3869 }
3870
Garret Rieger8d611a72022-07-22 22:49:40 +00003871 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01003872 HBUINT16 format; /* Format identifier. Set to 1. */
3873 HBUINT16 extensionLookupType; /* Lookup type of subtable referenced
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003874 * by ExtensionOffset (i.e. the
3875 * extension subtable). */
Behdad Esfahbodcd9bc732019-05-10 13:17:41 -07003876 Offset32 extensionOffset; /* Offset to the extension subtable,
Behdad Esfahbod81f2af42010-04-22 00:58:49 -04003877 * of lookup type subtable. */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04003878 public:
3879 DEFINE_SIZE_STATIC (8);
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003880};
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003881
Behdad Esfahbod653eeb22012-11-23 16:57:36 -05003882template <typename T>
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003883struct Extension
3884{
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303885 unsigned int get_type () const
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003886 {
3887 switch (u.format) {
Behdad Esfahboddacebca2010-05-10 19:45:41 -04003888 case 1: return u.format1.get_type ();
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003889 default:return 0;
3890 }
3891 }
Behdad Esfahbod7dddd4e2012-11-23 17:04:55 -05003892 template <typename X>
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303893 const X& get_subtable () const
Behdad Esfahbod7dddd4e2012-11-23 17:04:55 -05003894 {
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003895 switch (u.format) {
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07003896 case 1: return u.format1.template get_subtable<typename T::SubTable> ();
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04303897 default:return Null (typename T::SubTable);
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003898 }
Behdad Esfahbod7dddd4e2012-11-23 17:04:55 -05003899 }
3900
Garret Rieger08a49972020-10-06 13:02:12 -07003901 // Specialization of dispatch for subset. dispatch() normally just
3902 // dispatches to the sub table this points too, but for subset
3903 // we need to run subset on this subtable too.
3904 template <typename ...Ts>
3905 typename hb_subset_context_t::return_t dispatch (hb_subset_context_t *c, Ts&&... ds) const
3906 {
3907 switch (u.format) {
3908 case 1: return u.format1.subset (c);
3909 default: return c->default_return_value ();
3910 }
3911 }
3912
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -07003913 template <typename context_t, typename ...Ts>
Behdad Esfahbod83e3eab2019-05-07 20:58:43 -07003914 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
Behdad Esfahbod653eeb22012-11-23 16:57:36 -05003915 {
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003916 TRACE_DISPATCH (this, u.format);
Behdad Esfahbodf396fbb2015-10-09 12:25:55 -04003917 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04003918 switch (u.format) {
Behdad Esfahbod6d555ce2021-11-02 00:18:22 -06003919 case 1: return_trace (u.format1.dispatch (c, std::forward<Ts> (ds)...));
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003920 default:return_trace (c->default_return_value ());
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04003921 }
3922 }
3923
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04003924 protected:
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003925 union {
Behdad Esfahbod6b191782018-01-10 03:07:30 +01003926 HBUINT16 format; /* Format identifier */
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003927 ExtensionFormat1<T> format1;
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003928 } u;
3929};
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003930
3931
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04003932/*
3933 * GSUB/GPOS Common
3934 */
3935
Behdad Esfahbod97e59132018-10-10 11:41:05 -04003936struct hb_ot_layout_lookup_accelerator_t
3937{
3938 template <typename TLookup>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303939 void init (const TLookup &lookup)
Behdad Esfahbod97e59132018-10-10 11:41:05 -04003940 {
3941 digest.init ();
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07003942 lookup.collect_coverage (&digest);
Behdad Esfahbod78c09bf2018-10-10 11:50:46 -04003943
3944 subtables.init ();
Behdad Esfahbodf9b643f2022-06-04 07:29:40 -06003945 OT::hb_accelerate_subtables_context_t c_accelerate_subtables (subtables);
3946 lookup.dispatch (&c_accelerate_subtables);
Behdad Esfahbod39820af2022-06-07 10:18:38 -06003947
3948#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06003949 cache_user_idx = c_accelerate_subtables.cache_user_idx;
3950 for (unsigned i = 0; i < subtables.length; i++)
3951 if (i != cache_user_idx)
3952 subtables[i].apply_cached_func = subtables[i].apply_func;
Behdad Esfahbod39820af2022-06-07 10:18:38 -06003953#endif
Behdad Esfahbod97e59132018-10-10 11:41:05 -04003954 }
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303955 void fini () { subtables.fini (); }
Behdad Esfahbod97e59132018-10-10 11:41:05 -04003956
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303957 bool may_have (hb_codepoint_t g) const
Behdad Esfahbod97e59132018-10-10 11:41:05 -04003958 { return digest.may_have (g); }
3959
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06003960 bool apply (hb_ot_apply_context_t *c, bool use_cache) const
Behdad Esfahbode78549e2018-10-10 11:54:48 -04003961 {
Behdad Esfahbod39820af2022-06-07 10:18:38 -06003962#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06003963 if (use_cache)
3964 {
3965 for (unsigned int i = 0; i < subtables.length; i++)
3966 if (subtables[i].apply_cached (c))
3967 return true;
3968 }
3969 else
Behdad Esfahbod39820af2022-06-07 10:18:38 -06003970#endif
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06003971 {
3972 for (unsigned int i = 0; i < subtables.length; i++)
3973 if (subtables[i].apply (c))
3974 return true;
3975 }
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03303976 return false;
Behdad Esfahbode78549e2018-10-10 11:54:48 -04003977 }
3978
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06003979 bool cache_enter (OT::hb_ot_apply_context_t *c) const
3980 {
Behdad Esfahbod39820af2022-06-07 10:18:38 -06003981#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06003982 return cache_user_idx != (unsigned) -1 &&
3983 subtables[cache_user_idx].cache_enter (c);
Behdad Esfahbod39820af2022-06-07 10:18:38 -06003984#else
3985 return false;
3986#endif
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06003987 }
3988 void cache_leave (OT::hb_ot_apply_context_t *c) const
3989 {
Behdad Esfahbod39820af2022-06-07 10:18:38 -06003990#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06003991 subtables[cache_user_idx].cache_leave (c);
Behdad Esfahbod39820af2022-06-07 10:18:38 -06003992#endif
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06003993 }
3994
3995
Behdad Esfahbode78549e2018-10-10 11:54:48 -04003996 private:
Behdad Esfahbod97e59132018-10-10 11:41:05 -04003997 hb_set_digest_t digest;
Behdad Esfahbodf9b643f2022-06-04 07:29:40 -06003998 hb_accelerate_subtables_context_t::array_t subtables;
Behdad Esfahbod39820af2022-06-07 10:18:38 -06003999#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06004000 unsigned cache_user_idx = (unsigned) -1;
Behdad Esfahbod39820af2022-06-07 10:18:38 -06004001#endif
Behdad Esfahbod97e59132018-10-10 11:41:05 -04004002};
4003
Behdad Esfahbod5fd0a3f2022-07-11 13:10:04 -06004004template <typename Types>
4005struct GSUBGPOSVersion1_2
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04004006{
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004007 friend struct GSUBGPOS;
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04004008
Garret Rieger8d611a72022-07-22 22:49:40 +00004009 protected:
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004010 FixedVersion<>version; /* Version of the GSUB/GPOS table--initially set
4011 * to 0x00010000u */
Behdad Esfahbod5fd0a3f2022-07-11 13:10:04 -06004012 typename Types:: template OffsetTo<ScriptList>
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004013 scriptList; /* ScriptList table */
Behdad Esfahbod5fd0a3f2022-07-11 13:10:04 -06004014 typename Types::template OffsetTo<FeatureList>
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004015 featureList; /* FeatureList table */
Behdad Esfahbod5fd0a3f2022-07-11 13:10:04 -06004016 typename Types::template OffsetTo<LookupList<Types>>
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004017 lookupList; /* LookupList table */
4018 Offset32To<FeatureVariations>
4019 featureVars; /* Offset to Feature Variations
4020 table--from beginning of table
4021 * (may be NULL). Introduced
4022 * in version 0x00010001. */
4023 public:
Behdad Esfahbod5fd0a3f2022-07-11 13:10:04 -06004024 DEFINE_SIZE_MIN (4 + 3 * Types::size);
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04004025
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004026 unsigned int get_size () const
Behdad Esfahboda8498732019-06-19 19:26:22 -07004027 {
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004028 return min_size +
4029 (version.to_int () >= 0x00010001u ? featureVars.static_size : 0);
Qunxin Liu0b39c482019-10-22 16:00:43 -07004030 }
4031
Garret Rieger8d611a72022-07-22 22:49:40 +00004032 const typename Types::template OffsetTo<LookupList<Types>>* get_lookup_list_offset () const
4033 {
4034 return &lookupList;
4035 }
4036
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07004037 template <typename TLookup>
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004038 bool sanitize (hb_sanitize_context_t *c) const
Qunxin Liu973c47f2020-06-11 11:27:57 -07004039 {
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004040 TRACE_SANITIZE (this);
Behdad Esfahbod99f017f2022-07-11 13:13:19 -06004041 typedef List16OfOffsetTo<TLookup, typename Types::HBUINT> TLookupList;
4042 if (unlikely (!(scriptList.sanitize (c, this) &&
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004043 featureList.sanitize (c, this) &&
Behdad Esfahbod9ef9fc02022-07-11 13:29:23 -06004044 reinterpret_cast<const typename Types::template OffsetTo<TLookupList> &> (lookupList).sanitize (c, this))))
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004045 return_trace (false);
Qunxin Liu973c47f2020-06-11 11:27:57 -07004046
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004047#ifndef HB_NO_VAR
4048 if (unlikely (!(version.to_int () < 0x00010001u || featureVars.sanitize (c, this))))
4049 return_trace (false);
4050#endif
Behdad Esfahbod4119f732022-06-08 06:34:48 -06004051
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004052 return_trace (true);
Qunxin Liu56ca4352021-01-28 15:21:26 -08004053 }
4054
Qunxin Liu973c47f2020-06-11 11:27:57 -07004055 template <typename TLookup>
Qunxin Liue565d1f2019-11-01 10:21:36 -07004056 bool subset (hb_subset_layout_context_t *c) const
Behdad Esfahbodbfa72a92018-09-01 18:34:50 -07004057 {
4058 TRACE_SUBSET (this);
Qunxin Liue565d1f2019-11-01 10:21:36 -07004059 auto *out = c->subset_context->serializer->embed (*this);
Behdad Esfahbodbfa72a92018-09-01 18:34:50 -07004060 if (unlikely (!out)) return_trace (false);
Behdad Esfahbod1b6d0c42018-12-13 18:10:48 -05004061
Behdad Esfahbod9ef9fc02022-07-11 13:29:23 -06004062 typedef LookupOffsetList<TLookup, typename Types::HBUINT> TLookupList;
4063 reinterpret_cast<typename Types::template OffsetTo<TLookupList> &> (out->lookupList)
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04304064 .serialize_subset (c->subset_context,
Behdad Esfahbod9ef9fc02022-07-11 13:29:23 -06004065 reinterpret_cast<const typename Types::template OffsetTo<TLookupList> &> (lookupList),
Qunxin Liue565d1f2019-11-01 10:21:36 -07004066 this,
Qunxin Liue565d1f2019-11-01 10:21:36 -07004067 c);
4068
Behdad Esfahbod9ef9fc02022-07-11 13:29:23 -06004069 reinterpret_cast<typename Types::template OffsetTo<RecordListOfFeature> &> (out->featureList)
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04304070 .serialize_subset (c->subset_context,
Behdad Esfahbod9ef9fc02022-07-11 13:29:23 -06004071 reinterpret_cast<const typename Types::template OffsetTo<RecordListOfFeature> &> (featureList),
Qunxin Liue565d1f2019-11-01 10:21:36 -07004072 this,
Qunxin Liue565d1f2019-11-01 10:21:36 -07004073 c);
4074
4075 out->scriptList.serialize_subset (c->subset_context,
4076 scriptList,
4077 this,
Qunxin Liue565d1f2019-11-01 10:21:36 -07004078 c);
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07004079
Behdad Esfahboda8498732019-06-19 19:26:22 -07004080#ifndef HB_NO_VAR
Behdad Esfahbodbfa72a92018-09-01 18:34:50 -07004081 if (version.to_int () >= 0x00010001u)
Qunxin Liue565d1f2019-11-01 10:21:36 -07004082 {
ariza188a0a42020-03-07 11:02:36 -08004083 bool ret = out->featureVars.serialize_subset (c->subset_context, featureVars, this, c);
Behdad Esfahbod99f017f2022-07-11 13:13:19 -06004084 if (!ret && version.major == 1)
Qunxin Liue565d1f2019-11-01 10:21:36 -07004085 {
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04304086 out->version.major = 1;
4087 out->version.minor = 0;
Qunxin Liue565d1f2019-11-01 10:21:36 -07004088 }
4089 }
Behdad Esfahboda8498732019-06-19 19:26:22 -07004090#endif
Behdad Esfahbod1b6d0c42018-12-13 18:10:48 -05004091
Behdad Esfahbodbfa72a92018-09-01 18:34:50 -07004092 return_trace (true);
4093 }
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004094};
4095
4096struct GSUBGPOS
4097{
4098 unsigned int get_size () const
4099 {
4100 switch (u.version.major) {
4101 case 1: return u.version1.get_size ();
Behdad Esfahbod5a9c7932022-07-22 21:33:15 -06004102#ifndef HB_NO_BEYOND_64K
Behdad Esfahbod99f017f2022-07-11 13:13:19 -06004103 case 2: return u.version2.get_size ();
4104#endif
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004105 default: return u.version.static_size;
4106 }
4107 }
4108
4109 template <typename TLookup>
4110 bool sanitize (hb_sanitize_context_t *c) const
4111 {
4112 TRACE_SANITIZE (this);
4113 if (unlikely (!u.version.sanitize (c))) return_trace (false);
4114 switch (u.version.major) {
4115 case 1: return_trace (u.version1.sanitize<TLookup> (c));
Behdad Esfahbod5a9c7932022-07-22 21:33:15 -06004116#ifndef HB_NO_BEYOND_64K
Behdad Esfahbod99f017f2022-07-11 13:13:19 -06004117 case 2: return_trace (u.version2.sanitize<TLookup> (c));
4118#endif
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004119 default: return_trace (true);
4120 }
4121 }
4122
4123 template <typename TLookup>
4124 bool subset (hb_subset_layout_context_t *c) const
4125 {
4126 switch (u.version.major) {
4127 case 1: return u.version1.subset<TLookup> (c);
Behdad Esfahbod5a9c7932022-07-22 21:33:15 -06004128#ifndef HB_NO_BEYOND_64K
Behdad Esfahbod99f017f2022-07-11 13:13:19 -06004129 case 2: return u.version2.subset<TLookup> (c);
4130#endif
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004131 default: return false;
4132 }
4133 }
4134
4135 const ScriptList &get_script_list () const
4136 {
4137 switch (u.version.major) {
4138 case 1: return this+u.version1.scriptList;
Behdad Esfahbod5a9c7932022-07-22 21:33:15 -06004139#ifndef HB_NO_BEYOND_64K
Behdad Esfahbod99f017f2022-07-11 13:13:19 -06004140 case 2: return this+u.version2.scriptList;
4141#endif
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004142 default: return Null (ScriptList);
4143 }
4144 }
4145 const FeatureList &get_feature_list () const
4146 {
4147 switch (u.version.major) {
4148 case 1: return this+u.version1.featureList;
Behdad Esfahbod5a9c7932022-07-22 21:33:15 -06004149#ifndef HB_NO_BEYOND_64K
Behdad Esfahbod99f017f2022-07-11 13:13:19 -06004150 case 2: return this+u.version2.featureList;
4151#endif
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004152 default: return Null (FeatureList);
4153 }
4154 }
4155 unsigned int get_lookup_count () const
4156 {
4157 switch (u.version.major) {
4158 case 1: return (this+u.version1.lookupList).len;
Behdad Esfahbod5a9c7932022-07-22 21:33:15 -06004159#ifndef HB_NO_BEYOND_64K
Behdad Esfahbod99f017f2022-07-11 13:13:19 -06004160 case 2: return (this+u.version2.lookupList).len;
4161#endif
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004162 default: return 0;
4163 }
4164 }
4165 const Lookup& get_lookup (unsigned int i) const
4166 {
4167 switch (u.version.major) {
4168 case 1: return (this+u.version1.lookupList)[i];
Behdad Esfahbod5a9c7932022-07-22 21:33:15 -06004169#ifndef HB_NO_BEYOND_64K
Behdad Esfahbod99f017f2022-07-11 13:13:19 -06004170 case 2: return (this+u.version2.lookupList)[i];
4171#endif
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004172 default: return Null (Lookup);
4173 }
4174 }
4175 const FeatureVariations &get_feature_variations () const
4176 {
4177 switch (u.version.major) {
4178 case 1: return (u.version.to_int () >= 0x00010001u ? this+u.version1.featureVars : Null (FeatureVariations));
Behdad Esfahbod5a9c7932022-07-22 21:33:15 -06004179#ifndef HB_NO_BEYOND_64K
Behdad Esfahbod99f017f2022-07-11 13:13:19 -06004180 case 2: return this+u.version2.featureVars;
4181#endif
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004182 default: return Null (FeatureVariations);
4183 }
4184 }
4185
4186 bool has_data () const { return u.version.to_int (); }
4187 unsigned int get_script_count () const
4188 { return get_script_list ().len; }
4189 const Tag& get_script_tag (unsigned int i) const
4190 { return get_script_list ().get_tag (i); }
4191 unsigned int get_script_tags (unsigned int start_offset,
4192 unsigned int *script_count /* IN/OUT */,
4193 hb_tag_t *script_tags /* OUT */) const
4194 { return get_script_list ().get_tags (start_offset, script_count, script_tags); }
4195 const Script& get_script (unsigned int i) const
4196 { return get_script_list ()[i]; }
4197 bool find_script_index (hb_tag_t tag, unsigned int *index) const
4198 { return get_script_list ().find_index (tag, index); }
4199
4200 unsigned int get_feature_count () const
4201 { return get_feature_list ().len; }
4202 hb_tag_t get_feature_tag (unsigned int i) const
4203 { return i == Index::NOT_FOUND_INDEX ? HB_TAG_NONE : get_feature_list ().get_tag (i); }
4204 unsigned int get_feature_tags (unsigned int start_offset,
4205 unsigned int *feature_count /* IN/OUT */,
4206 hb_tag_t *feature_tags /* OUT */) const
4207 { return get_feature_list ().get_tags (start_offset, feature_count, feature_tags); }
4208 const Feature& get_feature (unsigned int i) const
4209 { return get_feature_list ()[i]; }
4210 bool find_feature_index (hb_tag_t tag, unsigned int *index) const
4211 { return get_feature_list ().find_index (tag, index); }
4212
4213 bool find_variations_index (const int *coords, unsigned int num_coords,
4214 unsigned int *index) const
4215 {
4216#ifdef HB_NO_VAR
4217 *index = FeatureVariations::NOT_FOUND_INDEX;
4218 return false;
4219#endif
4220 return get_feature_variations ().find_index (coords, num_coords, index);
4221 }
4222 const Feature& get_feature_variation (unsigned int feature_index,
4223 unsigned int variations_index) const
4224 {
4225#ifndef HB_NO_VAR
4226 if (FeatureVariations::NOT_FOUND_INDEX != variations_index &&
4227 u.version.to_int () >= 0x00010001u)
4228 {
4229 const Feature *feature = get_feature_variations ().find_substitute (variations_index,
4230 feature_index);
4231 if (feature)
4232 return *feature;
4233 }
4234#endif
4235 return get_feature (feature_index);
4236 }
4237
4238 void feature_variation_collect_lookups (const hb_set_t *feature_indexes,
4239 hb_set_t *lookup_indexes /* OUT */) const
4240 {
4241#ifndef HB_NO_VAR
4242 get_feature_variations ().collect_lookups (feature_indexes, lookup_indexes);
4243#endif
4244 }
4245
4246 template <typename TLookup>
4247 void closure_lookups (hb_face_t *face,
4248 const hb_set_t *glyphs,
4249 hb_set_t *lookup_indexes /* IN/OUT */) const
4250 {
4251 hb_set_t visited_lookups, inactive_lookups;
4252 OT::hb_closure_lookups_context_t c (face, glyphs, &visited_lookups, &inactive_lookups);
4253
4254 c.set_recurse_func (TLookup::template dispatch_recurse_func<hb_closure_lookups_context_t>);
4255
4256 for (unsigned lookup_index : + hb_iter (lookup_indexes))
4257 reinterpret_cast<const TLookup &> (get_lookup (lookup_index)).closure_lookups (&c, lookup_index);
4258
4259 hb_set_union (lookup_indexes, &visited_lookups);
4260 hb_set_subtract (lookup_indexes, &inactive_lookups);
4261 }
4262
4263 void prune_langsys (const hb_map_t *duplicate_feature_map,
4264 hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *script_langsys_map,
4265 hb_set_t *new_feature_indexes /* OUT */) const
4266 {
4267 hb_prune_langsys_context_t c (this, script_langsys_map, duplicate_feature_map, new_feature_indexes);
4268
4269 unsigned count = get_script_count ();
4270 for (unsigned script_index = 0; script_index < count; script_index++)
4271 {
4272 const Script& s = get_script (script_index);
4273 s.prune_langsys (&c, script_index);
4274 }
4275 }
4276
Garret Rieger718bf5a2020-09-29 13:16:01 -07004277 void prune_features (const hb_map_t *lookup_indices, /* IN */
Qunxin Liu56ca4352021-01-28 15:21:26 -08004278 hb_set_t *feature_indices /* IN/OUT */) const
Qunxin Liu8ffc9ad2019-10-31 15:59:02 -07004279 {
Garret Rieger718bf5a2020-09-29 13:16:01 -07004280#ifndef HB_NO_VAR
4281 // This is the set of feature indices which have alternate versions defined
4282 // if the FeatureVariation's table and the alternate version(s) intersect the
4283 // set of lookup indices.
4284 hb_set_t alternate_feature_indices;
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004285 get_feature_variations ().closure_features (lookup_indices, &alternate_feature_indices);
Behdad Esfahbodfad452b2021-08-16 20:48:24 -06004286 if (unlikely (alternate_feature_indices.in_error()))
4287 {
4288 feature_indices->err ();
Garret Rieger718bf5a2020-09-29 13:16:01 -07004289 return;
4290 }
4291#endif
4292
4293 for (unsigned i : feature_indices->iter())
Qunxin Liu8ffc9ad2019-10-31 15:59:02 -07004294 {
Qunxin Liud7c012a2020-02-26 13:11:42 -08004295 const Feature& f = get_feature (i);
Garret Riegerc35d7862021-04-01 14:32:38 -07004296 hb_tag_t tag = get_feature_tag (i);
4297 if (tag == HB_TAG ('p', 'r', 'e', 'f'))
4298 // Note: Never ever drop feature 'pref', even if it's empty.
4299 // HarfBuzz chooses shaper for Khmer based on presence of this
4300 // feature. See thread at:
4301 // http://lists.freedesktop.org/archives/harfbuzz/2012-November/002660.html
4302 continue;
Garret Rieger718bf5a2020-09-29 13:16:01 -07004303
Qunxin Liuca418ca2021-11-17 16:42:08 -08004304
4305 if (!f.featureParams.is_null () &&
4306 tag == HB_TAG ('s', 'i', 'z', 'e'))
4307 continue;
4308
4309 if (!f.intersects_lookup_indexes (lookup_indices)
Behdad Esfahbod29025292021-03-02 15:05:22 -07004310#ifndef HB_NO_VAR
4311 && !alternate_feature_indices.has (i)
4312#endif
4313 )
4314 feature_indices->del (i);
Qunxin Liu8ffc9ad2019-10-31 15:59:02 -07004315 }
Qunxin Liu8ffc9ad2019-10-31 15:59:02 -07004316 }
4317
Behdad Esfahbod963413f2018-08-26 00:47:55 -07004318 template <typename T>
4319 struct accelerator_t
4320 {
Behdad Esfahbodac1bb3e2022-01-20 11:47:17 -07004321 accelerator_t (hb_face_t *face)
Behdad Esfahbod963413f2018-08-26 00:47:55 -07004322 {
Ebrahim Byagowiba22df32020-03-10 10:42:20 +03304323 this->table = hb_sanitize_context_t ().reference_table<T> (face);
Behdad Esfahbod56719472020-06-05 12:57:23 -07004324 if (unlikely (this->table->is_blocklisted (this->table.get_blob (), face)))
Behdad Esfahbod574d8882018-11-25 16:51:22 -05004325 {
4326 hb_blob_destroy (this->table.get_blob ());
4327 this->table = hb_blob_get_empty ();
4328 }
Behdad Esfahbod963413f2018-08-26 00:47:55 -07004329
Behdad Esfahbodb9291002018-08-26 01:15:47 -07004330 this->lookup_count = table->get_lookup_count ();
Behdad Esfahbod963413f2018-08-26 00:47:55 -07004331
Behdad Esfahbod2337f0d2021-07-08 10:58:50 -06004332 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 -07004333 if (unlikely (!this->accels))
Dominik Röttschesa5f6f862020-10-23 14:25:05 +03004334 {
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03304335 this->lookup_count = 0;
Behdad Esfahbod53806e52020-11-25 11:51:37 -07004336 this->table.destroy ();
Dominik Röttschesa5f6f862020-10-23 14:25:05 +03004337 this->table = hb_blob_get_empty ();
4338 }
Behdad Esfahbod963413f2018-08-26 00:47:55 -07004339
4340 for (unsigned int i = 0; i < this->lookup_count; i++)
Behdad Esfahbodb9291002018-08-26 01:15:47 -07004341 this->accels[i].init (table->get_lookup (i));
Behdad Esfahbod963413f2018-08-26 00:47:55 -07004342 }
Behdad Esfahbodac1bb3e2022-01-20 11:47:17 -07004343 ~accelerator_t ()
Behdad Esfahbod963413f2018-08-26 00:47:55 -07004344 {
Behdad Esfahbodb9291002018-08-26 01:15:47 -07004345 for (unsigned int i = 0; i < this->lookup_count; i++)
4346 this->accels[i].fini ();
Behdad Esfahbod2337f0d2021-07-08 10:58:50 -06004347 hb_free (this->accels);
Behdad Esfahbodda6aa3b2018-11-11 11:40:57 -05004348 this->table.destroy ();
Behdad Esfahbod963413f2018-08-26 00:47:55 -07004349 }
4350
Behdad Esfahbod5d0078a2018-11-10 23:52:15 -05004351 hb_blob_ptr_t<T> table;
Behdad Esfahbodb9291002018-08-26 01:15:47 -07004352 unsigned int lookup_count;
4353 hb_ot_layout_lookup_accelerator_t *accels;
Behdad Esfahbod963413f2018-08-26 00:47:55 -07004354 };
4355
Behdad Esfahbod212aba62009-05-24 00:50:27 -04004356 protected:
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004357 union {
Behdad Esfahbod5fd0a3f2022-07-11 13:10:04 -06004358 FixedVersion<> version; /* Version identifier */
4359 GSUBGPOSVersion1_2<SmallTypes> version1;
Behdad Esfahbod5a9c7932022-07-22 21:33:15 -06004360#ifndef HB_NO_BEYOND_64K
Behdad Esfahbod99f017f2022-07-11 13:13:19 -06004361 GSUBGPOSVersion1_2<MediumTypes> version2;
4362#endif
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004363 } u;
Behdad Esfahbodb3651232010-05-10 16:57:29 -04004364 public:
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004365 DEFINE_SIZE_MIN (4);
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04004366};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04004367
Behdad Esfahbod6f20f722009-05-17 20:28:01 -04004368
Behdad Esfahbod7d52e662012-11-16 18:49:54 -08004369} /* namespace OT */
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -04004370
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04004371
Behdad Esfahbodc77ae402018-08-25 22:36:36 -07004372#endif /* HB_OT_LAYOUT_GSUBGPOS_HH */