blob: 07a6db7778150760ff29a4f9f3d557d2051d0c31 [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 {
Behdad Esfahbodc6a4b602022-11-30 14:09:59 -0700103 if (unlikely (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
Behdad Esfahbod4401dd22023-01-05 14:13:57 -0700118 done_lookups_glyph_set->get (lookup_index)->clear ();
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
Behdad Esfahbod167b7c62023-01-05 14:48:20 -0700156 active_glyphs_stack.pop ();
Qunxin Liub4fc5932020-12-09 10:44:18 -0800157 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 Esfahbodb29fbd12023-02-06 13:08:52 -0700535 enum match_t {
536 MATCH,
537 NOT_MATCH,
538 SKIP
539 };
540
541 match_t match (hb_glyph_info_t &info)
542 {
543 matcher_t::may_skip_t skip = matcher.may_skip (c, info);
544 if (unlikely (skip == matcher_t::SKIP_YES))
545 return SKIP;
546
547 matcher_t::may_match_t match = matcher.may_match (info, get_glyph_data ());
548 if (match == matcher_t::MATCH_YES ||
549 (match == matcher_t::MATCH_MAYBE &&
550 skip == matcher_t::SKIP_NO))
551 return MATCH;
552
553 if (skip == matcher_t::SKIP_NO)
554 return NOT_MATCH;
555
556 return SKIP;
557 }
558
Behdad Esfahbod3122c2c2021-12-04 19:50:33 -0800559 bool next (unsigned *unsafe_to = nullptr)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500560 {
Behdad Esfahbod506ffeb2012-01-18 16:07:53 -0500561 assert (num_items > 0);
Behdad Esfahbodc15efde2022-11-23 21:14:28 -0700562 /* The alternate condition below is faster at string boundaries,
563 * but produces subpar "unsafe-to-concat" values. */
Behdad Esfahbod0c70bc72022-11-24 11:48:48 -0700564 signed stop = (signed) end - (signed) num_items;
Behdad Esfahbod1fa64c02022-11-23 21:38:51 -0700565 if (c->buffer->flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT)
Behdad Esfahbod0c70bc72022-11-24 11:48:48 -0700566 stop = (signed) end - 1;
567 while ((signed) idx < stop)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500568 {
Behdad Esfahboda4a48fe2012-01-17 18:08:41 -0500569 idx++;
Behdad Esfahbodb29fbd12023-02-06 13:08:52 -0700570 switch (match (c->buffer->info[idx]))
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500571 {
Behdad Esfahbodb29fbd12023-02-06 13:08:52 -0700572 case MATCH:
573 {
574 num_items--;
575 advance_glyph_data ();
576 return true;
577 }
578 case NOT_MATCH:
579 {
580 if (unsafe_to)
581 *unsafe_to = idx + 1;
582 return false;
583 }
584 case SKIP:
585 continue;
Behdad Esfahbod3122c2c2021-12-04 19:50:33 -0800586 }
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500587 }
Behdad Esfahbod3122c2c2021-12-04 19:50:33 -0800588 if (unsafe_to)
589 *unsafe_to = end;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500590 return false;
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500591 }
Behdad Esfahbod3122c2c2021-12-04 19:50:33 -0800592 bool prev (unsigned *unsafe_from = nullptr)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500593 {
Behdad Esfahbod506ffeb2012-01-18 16:07:53 -0500594 assert (num_items > 0);
Behdad Esfahbodc15efde2022-11-23 21:14:28 -0700595 /* The alternate condition below is faster at string boundaries,
596 * but produces subpar "unsafe-to-concat" values. */
Behdad Esfahbod0c70bc72022-11-24 11:48:48 -0700597 unsigned stop = num_items - 1;
Behdad Esfahbod1fa64c02022-11-23 21:38:51 -0700598 if (c->buffer->flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT)
599 stop = 1 - 1;
Behdad Esfahbod42681bd2022-11-23 21:36:43 -0700600 while (idx > stop)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500601 {
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500602 idx--;
Behdad Esfahbodb29fbd12023-02-06 13:08:52 -0700603 switch (match (c->buffer->out_info[idx]))
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500604 {
Behdad Esfahbodb29fbd12023-02-06 13:08:52 -0700605 case MATCH:
606 {
607 num_items--;
608 advance_glyph_data ();
609 return true;
610 }
611 case NOT_MATCH:
612 {
613 if (unsafe_from)
614 *unsafe_from = hb_max (1u, idx) - 1u;
615 return false;
616 }
617 case SKIP:
618 continue;
Behdad Esfahbod3122c2c2021-12-04 19:50:33 -0800619 }
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500620 }
Behdad Esfahbod3122c2c2021-12-04 19:50:33 -0800621 if (unsafe_from)
622 *unsafe_from = 0;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500623 return false;
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500624 }
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500625
Behdad Esfahbod429b3872022-07-06 17:37:11 -0600626 hb_codepoint_t
627 get_glyph_data ()
628 {
629 if (match_glyph_data16) return *match_glyph_data16;
Behdad Esfahbod5a9c7932022-07-22 21:33:15 -0600630#ifndef HB_NO_BEYOND_64K
Behdad Esfahbod429b3872022-07-06 17:37:11 -0600631 else
632 if (match_glyph_data24) return *match_glyph_data24;
633#endif
634 return 0;
635 }
636 void
637 advance_glyph_data ()
638 {
639 if (match_glyph_data16) match_glyph_data16++;
Behdad Esfahbod5a9c7932022-07-22 21:33:15 -0600640#ifndef HB_NO_BEYOND_64K
Behdad Esfahbod429b3872022-07-06 17:37:11 -0600641 else
642 if (match_glyph_data24) match_glyph_data24++;
643#endif
644 }
645 void
646 backup_glyph_data ()
647 {
648 if (match_glyph_data16) match_glyph_data16--;
Behdad Esfahbod5a9c7932022-07-22 21:33:15 -0600649#ifndef HB_NO_BEYOND_64K
Behdad Esfahbod429b3872022-07-06 17:37:11 -0600650 else
651 if (match_glyph_data24) match_glyph_data24--;
652#endif
653 }
654
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500655 unsigned int idx;
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400656 protected:
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800657 hb_ot_apply_context_t *c;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500658 matcher_t matcher;
Behdad Esfahbod429b3872022-07-06 17:37:11 -0600659 const HBUINT16 *match_glyph_data16;
Behdad Esfahbod5a9c7932022-07-22 21:33:15 -0600660#ifndef HB_NO_BEYOND_64K
Behdad Esfahbod429b3872022-07-06 17:37:11 -0600661 const HBUINT24 *match_glyph_data24;
662#endif
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500663
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500664 unsigned int num_items;
Behdad Esfahbod69626692015-01-29 13:08:41 +0100665 unsigned int end;
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500666 };
667
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100668
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330669 const char *get_name () { return "APPLY"; }
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800670 typedef return_t (*recurse_func_t) (hb_ot_apply_context_t *c, unsigned int lookup_index);
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100671 template <typename T>
Behdad Esfahbodc14efb82019-05-05 09:54:58 -0700672 return_t dispatch (const T &obj) { return obj.apply (this); }
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330673 static return_t default_return_value () { return false; }
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100674 bool stop_sublookup_iteration (return_t r) const { return r; }
Behdad Esfahbod12757b62018-01-26 18:14:05 -0800675 return_t recurse (unsigned int sub_lookup_index)
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100676 {
Behdad Esfahbodbaf77792017-11-14 21:53:48 -0800677 if (unlikely (nesting_level_left == 0 || !recurse_func || buffer->max_ops-- <= 0))
Behdad Esfahbod9a2a8572022-05-31 04:25:20 -0600678 {
679 buffer->shaping_failed = true;
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100680 return default_return_value ();
Behdad Esfahbod9a2a8572022-05-31 04:25:20 -0600681 }
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100682
683 nesting_level_left--;
Behdad Esfahbod12757b62018-01-26 18:14:05 -0800684 bool ret = recurse_func (this, sub_lookup_index);
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100685 nesting_level_left++;
686 return ret;
687 }
688
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100689 skipping_iterator_t iter_input, iter_context;
690
Behdad Esfahbod880f50f2022-05-20 16:50:00 -0600691 unsigned int table_index; /* GSUB/GPOS */
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100692 hb_font_t *font;
693 hb_face_t *face;
694 hb_buffer_t *buffer;
Behdad Esfahbodf4a8b702022-05-30 05:30:37 -0600695 recurse_func_t recurse_func = nullptr;
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100696 const GDEF &gdef;
697 const VariationStore &var_store;
Behdad Esfahbod880f50f2022-05-20 16:50:00 -0600698 VariationStore::cache_t *var_store_cache;
Behdad Esfahbod76c82142022-11-18 12:30:46 -0700699 hb_set_digest_t digest;
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100700
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100701 hb_direction_t direction;
Behdad Esfahbod97aa1ce2022-05-29 10:32:59 -0600702 hb_mask_t lookup_mask = 1;
703 unsigned int lookup_index = (unsigned) -1;
704 unsigned int lookup_props = 0;
705 unsigned int nesting_level_left = HB_MAX_NESTING_LEVEL;
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100706
Behdad Esfahbod80de4bc2018-09-10 16:24:52 +0200707 bool has_glyph_classes;
Behdad Esfahbod97aa1ce2022-05-29 10:32:59 -0600708 bool auto_zwnj = true;
709 bool auto_zwj = true;
710 bool per_syllable = false;
711 bool random = false;
712 uint32_t random_state = 1;
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600713 unsigned new_syllables = (unsigned) -1;
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100714
Behdad Esfahbod8708b9e2023-02-06 14:51:25 -0700715 signed last_base = -1; // GPOS uses
716 unsigned last_base_until = 0; // GPOS uses
717
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800718 hb_ot_apply_context_t (unsigned int table_index_,
Ebrahim Byagowid0e2add2020-07-18 22:14:52 +0430719 hb_font_t *font_,
720 hb_buffer_t *buffer_) :
Behdad Esfahbod880f50f2022-05-20 16:50:00 -0600721 table_index (table_index_),
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100722 font (font_), face (font->face), buffer (buffer_),
Behdad Esfahbod7dcf8e12019-06-26 13:44:10 -0700723 gdef (
724#ifndef HB_NO_OT_LAYOUT
725 *face->table.GDEF->table
726#else
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +0430727 Null (GDEF)
Behdad Esfahbod7dcf8e12019-06-26 13:44:10 -0700728#endif
729 ),
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100730 var_store (gdef.get_var_store ()),
Behdad Esfahbod3eb7eff2022-05-21 15:25:53 -0600731 var_store_cache (
732#ifndef HB_NO_VAR
733 table_index == 1 && font->num_coords ? var_store.create_cache () : nullptr
734#else
735 nullptr
736#endif
737 ),
Behdad Esfahbod76c82142022-11-18 12:30:46 -0700738 digest (buffer_->digest ()),
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100739 direction (buffer_->props.direction),
Behdad Esfahbod76c82142022-11-18 12:30:46 -0700740 has_glyph_classes (gdef.has_glyph_classes ())
Behdad Esfahbod880f50f2022-05-20 16:50:00 -0600741 { init_iters (); }
742
Behdad Esfahbod3eb7eff2022-05-21 15:25:53 -0600743 ~hb_ot_apply_context_t ()
744 {
745#ifndef HB_NO_VAR
746 VariationStore::destroy_cache (var_store_cache);
747#endif
748 }
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100749
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330750 void init_iters ()
Behdad Esfahbod365576d2015-01-29 13:59:42 +0100751 {
Behdad Esfahbod365576d2015-01-29 13:59:42 +0100752 iter_input.init (this, false);
753 iter_context.init (this, true);
754 }
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100755
Behdad Esfahbod8708b9e2023-02-06 14:51:25 -0700756 void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; last_base = -1; last_base_until = 0; init_iters (); }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330757 void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; init_iters (); }
758 void set_auto_zwnj (bool auto_zwnj_) { auto_zwnj = auto_zwnj_; init_iters (); }
Behdad Esfahbod044d7a02022-03-28 12:38:56 -0600759 void set_per_syllable (bool per_syllable_) { per_syllable = per_syllable_; init_iters (); }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330760 void set_random (bool random_) { random = random_; }
761 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
762 void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; }
763 void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; init_iters (); }
Behdad Esfahbod9516cbd2018-09-23 22:00:34 -0400764
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330765 uint32_t random_number ()
Behdad Esfahbod08260c72018-09-11 10:51:19 +0200766 {
Behdad Esfahbodcfdea882018-09-11 10:57:48 +0200767 /* http://www.cplusplus.com/reference/random/minstd_rand/ */
768 random_state = random_state * 48271 % 2147483647;
769 return random_state;
Behdad Esfahbod08260c72018-09-11 10:51:19 +0200770 }
771
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330772 bool match_properties_mark (hb_codepoint_t glyph,
773 unsigned int glyph_props,
774 unsigned int match_props) const
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400775 {
776 /* If using mark filtering sets, the high short of
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700777 * match_props has the set index.
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400778 */
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700779 if (match_props & LookupFlag::UseMarkFilteringSet)
780 return gdef.mark_set_covers (match_props >> 16, glyph);
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400781
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700782 /* The second byte of match_props has the meaning
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400783 * "ignore marks of attachment type different than
784 * the attachment type specified."
785 */
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700786 if (match_props & LookupFlag::MarkAttachmentType)
787 return (match_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400788
789 return true;
790 }
791
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330792 bool check_glyph_property (const hb_glyph_info_t *info,
793 unsigned int match_props) const
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400794 {
Behdad Esfahbodb98c5db2014-07-16 13:44:01 -0400795 hb_codepoint_t glyph = info->codepoint;
796 unsigned int glyph_props = _hb_glyph_info_get_glyph_props (info);
797
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400798 /* Not covered, if, for example, glyph class is ligature and
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700799 * match_props includes LookupFlags::IgnoreLigatures
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400800 */
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700801 if (glyph_props & match_props & LookupFlag::IgnoreFlags)
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400802 return false;
803
Behdad Esfahbod5a08ecf2012-11-16 13:34:29 -0800804 if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK))
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700805 return match_properties_mark (glyph, glyph_props, match_props);
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400806
807 return true;
808 }
809
Behdad Esfahbodfa12f1a2022-01-12 15:08:34 -0700810 void _set_glyph_class (hb_codepoint_t glyph_index,
Ebrahim Byagowi9748ae72020-08-11 17:52:48 +0430811 unsigned int class_guess = 0,
812 bool ligature = false,
Behdad Esfahbod8b2a2112022-11-16 16:57:44 -0700813 bool component = false)
Behdad Esfahbod60da7632012-07-16 16:13:32 -0400814 {
Behdad Esfahbod8b2a2112022-11-16 16:57:44 -0700815 digest.add (glyph_index);
816
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600817 if (new_syllables != (unsigned) -1)
818 buffer->cur().syllable() = new_syllables;
819
Behdad Esfahbod9408e0d2022-01-12 15:07:34 -0700820 unsigned int props = _hb_glyph_info_get_glyph_props (&buffer->cur());
821 props |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED;
Behdad Esfahbod09675a82013-10-18 01:05:58 +0200822 if (ligature)
Behdad Esfahbod832a6f92014-06-04 16:57:42 -0400823 {
Behdad Esfahbod9408e0d2022-01-12 15:07:34 -0700824 props |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED;
Behdad Esfahbod832a6f92014-06-04 16:57:42 -0400825 /* In the only place that the MULTIPLIED bit is used, Uniscribe
826 * seems to only care about the "last" transformation between
Bruce Mitchener257d0e52018-10-19 22:49:21 +0700827 * Ligature and Multiple substitutions. Ie. if you ligate, expand,
Behdad Esfahbod832a6f92014-06-04 16:57:42 -0400828 * and ligate again, it forgives the multiplication and acts as
829 * if only ligation happened. As such, clear MULTIPLIED bit.
830 */
Behdad Esfahbod9408e0d2022-01-12 15:07:34 -0700831 props &= ~HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
Behdad Esfahbod832a6f92014-06-04 16:57:42 -0400832 }
833 if (component)
Behdad Esfahbod9408e0d2022-01-12 15:07:34 -0700834 props |= HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
Behdad Esfahbod2fca1422012-07-30 18:46:41 -0400835 if (likely (has_glyph_classes))
Behdad Esfahbod96c969c2022-01-12 15:06:40 -0700836 {
Behdad Esfahbod9408e0d2022-01-12 15:07:34 -0700837 props &= HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE;
838 _hb_glyph_info_set_glyph_props (&buffer->cur(), props | gdef.get_glyph_props (glyph_index));
Behdad Esfahbod96c969c2022-01-12 15:06:40 -0700839 }
Behdad Esfahbod05bd1b62012-07-30 19:30:01 -0400840 else if (class_guess)
Behdad Esfahbod96c969c2022-01-12 15:06:40 -0700841 {
Behdad Esfahbod9408e0d2022-01-12 15:07:34 -0700842 props &= HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE;
843 _hb_glyph_info_set_glyph_props (&buffer->cur(), props | class_guess);
Behdad Esfahbod96c969c2022-01-12 15:06:40 -0700844 }
845 else
Behdad Esfahbod9408e0d2022-01-12 15:07:34 -0700846 _hb_glyph_info_set_glyph_props (&buffer->cur(), props);
Behdad Esfahbod60da7632012-07-16 16:13:32 -0400847 }
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500848
Behdad Esfahbod8b2a2112022-11-16 16:57:44 -0700849 void replace_glyph (hb_codepoint_t glyph_index)
Behdad Esfahbod3ec77d62012-06-08 21:44:06 -0400850 {
Behdad Esfahbodfa12f1a2022-01-12 15:08:34 -0700851 _set_glyph_class (glyph_index);
Behdad Esfahbod3f1998a2021-03-15 13:33:44 -0600852 (void) buffer->replace_glyph (glyph_index);
Behdad Esfahbod98370e82010-10-27 17:39:01 -0400853 }
Behdad Esfahbod8b2a2112022-11-16 16:57:44 -0700854 void replace_glyph_inplace (hb_codepoint_t glyph_index)
Behdad Esfahbod7fbbf862012-07-30 18:36:42 -0400855 {
Behdad Esfahbodfa12f1a2022-01-12 15:08:34 -0700856 _set_glyph_class (glyph_index);
Behdad Esfahbod7fbbf862012-07-30 18:36:42 -0400857 buffer->cur().codepoint = glyph_index;
858 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330859 void replace_glyph_with_ligature (hb_codepoint_t glyph_index,
Behdad Esfahbod8b2a2112022-11-16 16:57:44 -0700860 unsigned int class_guess)
Behdad Esfahboda0161742013-10-18 00:06:30 +0200861 {
Behdad Esfahbodfa12f1a2022-01-12 15:08:34 -0700862 _set_glyph_class (glyph_index, class_guess, true);
Behdad Esfahbod3f1998a2021-03-15 13:33:44 -0600863 (void) buffer->replace_glyph (glyph_index);
Behdad Esfahboda0161742013-10-18 00:06:30 +0200864 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330865 void output_glyph_for_component (hb_codepoint_t glyph_index,
Behdad Esfahbod8b2a2112022-11-16 16:57:44 -0700866 unsigned int class_guess)
Behdad Esfahboda0161742013-10-18 00:06:30 +0200867 {
Behdad Esfahbodfa12f1a2022-01-12 15:08:34 -0700868 _set_glyph_class (glyph_index, class_guess, false, true);
Behdad Esfahbod34a12042021-03-15 14:39:06 -0600869 (void) buffer->output_glyph (glyph_index);
Behdad Esfahboda0161742013-10-18 00:06:30 +0200870 }
Behdad Esfahbod1376fb72010-04-29 02:19:21 -0400871};
872
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -0400873
Behdad Esfahbodf9b643f2022-06-04 07:29:40 -0600874struct hb_accelerate_subtables_context_t :
875 hb_dispatch_context_t<hb_accelerate_subtables_context_t>
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400876{
877 template <typename Type>
Behdad Esfahbodbba57652022-11-18 14:52:17 -0700878 static inline bool apply_to (const void *obj, hb_ot_apply_context_t *c)
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400879 {
880 const Type *typed_obj = (const Type *) obj;
881 return typed_obj->apply (c);
882 }
883
Behdad Esfahbod39820af2022-06-07 10:18:38 -0600884#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600885 template <typename T>
Behdad Esfahbodbba57652022-11-18 14:52:17 -0700886 static inline auto apply_cached_ (const T *obj, hb_ot_apply_context_t *c, hb_priority<1>) HB_RETURN (bool, obj->apply (c, true) )
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600887 template <typename T>
Behdad Esfahbodbba57652022-11-18 14:52:17 -0700888 static inline auto apply_cached_ (const T *obj, hb_ot_apply_context_t *c, hb_priority<0>) HB_RETURN (bool, obj->apply (c) )
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600889 template <typename Type>
Behdad Esfahbodbba57652022-11-18 14:52:17 -0700890 static inline bool apply_cached_to (const void *obj, hb_ot_apply_context_t *c)
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600891 {
892 const Type *typed_obj = (const Type *) obj;
893 return apply_cached_ (typed_obj, c, hb_prioritize);
894 }
895
896 template <typename T>
Behdad Esfahbodbba57652022-11-18 14:52:17 -0700897 static inline auto cache_func_ (const T *obj, 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 -0600898 template <typename T>
Behdad Esfahbodbba57652022-11-18 14:52:17 -0700899 static inline bool cache_func_ (const T *obj, hb_ot_apply_context_t *c, bool enter, hb_priority<0>) { return false; }
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600900 template <typename Type>
Behdad Esfahbodbba57652022-11-18 14:52:17 -0700901 static inline bool cache_func_to (const void *obj, hb_ot_apply_context_t *c, bool enter)
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600902 {
903 const Type *typed_obj = (const Type *) obj;
Behdad Esfahbod5963cf42022-06-07 09:12:45 -0600904 return cache_func_ (typed_obj, c, enter, hb_prioritize);
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600905 }
Behdad Esfahbod39820af2022-06-07 10:18:38 -0600906#endif
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600907
Behdad Esfahbodbba57652022-11-18 14:52:17 -0700908 typedef bool (*hb_apply_func_t) (const void *obj, hb_ot_apply_context_t *c);
909 typedef bool (*hb_cache_func_t) (const void *obj, hb_ot_apply_context_t *c, bool enter);
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400910
911 struct hb_applicable_t
912 {
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600913 friend struct hb_accelerate_subtables_context_t;
914 friend struct hb_ot_layout_lookup_accelerator_t;
915
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400916 template <typename T>
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600917 void init (const T &obj_,
Behdad Esfahbod39820af2022-06-07 10:18:38 -0600918 hb_apply_func_t apply_func_
919#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
920 , hb_apply_func_t apply_cached_func_
921 , hb_cache_func_t cache_func_
922#endif
923 )
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400924 {
925 obj = &obj_;
926 apply_func = apply_func_;
Behdad Esfahbod39820af2022-06-07 10:18:38 -0600927#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600928 apply_cached_func = apply_cached_func_;
Behdad Esfahbod5963cf42022-06-07 09:12:45 -0600929 cache_func = cache_func_;
Behdad Esfahbod39820af2022-06-07 10:18:38 -0600930#endif
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400931 digest.init ();
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -0700932 obj_.get_coverage ().collect_coverage (&digest);
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400933 }
934
Behdad Esfahbodbba57652022-11-18 14:52:17 -0700935 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400936 {
937 return digest.may_have (c->buffer->cur().codepoint) && apply_func (obj, c);
938 }
Behdad Esfahbod39820af2022-06-07 10:18:38 -0600939#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
Behdad Esfahbodbba57652022-11-18 14:52:17 -0700940 bool apply_cached (hb_ot_apply_context_t *c) const
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600941 {
942 return digest.may_have (c->buffer->cur().codepoint) && apply_cached_func (obj, c);
943 }
Behdad Esfahbodbba57652022-11-18 14:52:17 -0700944 bool cache_enter (hb_ot_apply_context_t *c) const
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600945 {
Behdad Esfahbod5963cf42022-06-07 09:12:45 -0600946 return cache_func (obj, c, true);
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600947 }
Behdad Esfahbodbba57652022-11-18 14:52:17 -0700948 void cache_leave (hb_ot_apply_context_t *c) const
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600949 {
Behdad Esfahbod5963cf42022-06-07 09:12:45 -0600950 cache_func (obj, c, false);
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600951 }
Behdad Esfahbod39820af2022-06-07 10:18:38 -0600952#endif
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400953
954 private:
955 const void *obj;
956 hb_apply_func_t apply_func;
Behdad Esfahbod39820af2022-06-07 10:18:38 -0600957#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600958 hb_apply_func_t apply_cached_func;
Behdad Esfahbod5963cf42022-06-07 09:12:45 -0600959 hb_cache_func_t cache_func;
Behdad Esfahbod39820af2022-06-07 10:18:38 -0600960#endif
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400961 hb_set_digest_t digest;
962 };
963
Behdad Esfahbod39820af2022-06-07 10:18:38 -0600964#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600965 template <typename T>
966 auto cache_cost (const T &obj, hb_priority<1>) HB_AUTO_RETURN ( obj.cache_cost () )
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600967 template <typename T>
968 auto cache_cost (const T &obj, hb_priority<0>) HB_AUTO_RETURN ( 0u )
Behdad Esfahbod39820af2022-06-07 10:18:38 -0600969#endif
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600970
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400971 /* Dispatch interface. */
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400972 template <typename T>
Behdad Esfahbodc14efb82019-05-05 09:54:58 -0700973 return_t dispatch (const T &obj)
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400974 {
Behdad Esfahbod83353f12023-01-31 14:32:14 -0700975 hb_applicable_t *entry = &array[i++];
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600976
Behdad Esfahbodd2279a22023-01-27 12:32:55 -0700977 entry->init (obj,
978 apply_to<T>
Behdad Esfahbod39820af2022-06-07 10:18:38 -0600979#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
Behdad Esfahbodd2279a22023-01-27 12:32:55 -0700980 , apply_cached_to<T>
981 , cache_func_to<T>
Behdad Esfahbod39820af2022-06-07 10:18:38 -0600982#endif
Behdad Esfahbodd2279a22023-01-27 12:32:55 -0700983 );
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600984
Behdad Esfahbod39820af2022-06-07 10:18:38 -0600985#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
Behdad Esfahbodc8fb0482022-06-07 09:20:27 -0600986 /* Cache handling
987 *
988 * We allow one subtable from each lookup to use a cache. The assumption
989 * being that multiple subtables of the same lookup cannot use a cache
990 * because the resources they would use will collide. As such, we ask
991 * each subtable to tell us how much it costs (which a cache would avoid),
992 * and we allocate the cache opportunity to the costliest subtable.
993 */
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600994 unsigned cost = cache_cost (obj, hb_prioritize);
Behdad Esfahbod83353f12023-01-31 14:32:14 -0700995 if (cost > cache_user_cost)
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600996 {
Behdad Esfahbod83353f12023-01-31 14:32:14 -0700997 cache_user_idx = i - 1;
Behdad Esfahbodb96622d2022-06-05 02:45:41 -0600998 cache_user_cost = cost;
999 }
Behdad Esfahbod39820af2022-06-07 10:18:38 -06001000#endif
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06001001
Behdad Esfahbod7df3ecf2019-05-10 20:43:26 -07001002 return hb_empty_t ();
Behdad Esfahbodb3390992018-10-10 12:07:49 -04001003 }
Behdad Esfahbod7df3ecf2019-05-10 20:43:26 -07001004 static return_t default_return_value () { return hb_empty_t (); }
Behdad Esfahbodb3390992018-10-10 12:07:49 -04001005
Behdad Esfahbod83353f12023-01-31 14:32:14 -07001006 hb_accelerate_subtables_context_t (hb_applicable_t *array_) :
Behdad Esfahbodf9b643f2022-06-04 07:29:40 -06001007 array (array_) {}
Behdad Esfahbodb3390992018-10-10 12:07:49 -04001008
Behdad Esfahbod83353f12023-01-31 14:32:14 -07001009 hb_applicable_t *array;
1010 unsigned i = 0;
Behdad Esfahbod39820af2022-06-07 10:18:38 -06001011
1012#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06001013 unsigned cache_user_idx = (unsigned) -1;
1014 unsigned cache_user_cost = 0;
Behdad Esfahbod39820af2022-06-07 10:18:38 -06001015#endif
Behdad Esfahbodb3390992018-10-10 12:07:49 -04001016};
1017
1018
Behdad Esfahbodc044f4a2022-12-03 11:58:04 -07001019typedef bool (*intersects_func_t) (const hb_set_t *glyphs, unsigned value, const void *data, void *cache);
Behdad Esfahbod630b8742022-12-03 12:13:15 -07001020typedef void (*intersected_glyphs_func_t) (const hb_set_t *glyphs, const void *data, unsigned value, hb_set_t *intersected_glyphs, void *cache);
Behdad Esfahbod8b349e12022-07-06 17:22:34 -06001021typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, unsigned value, const void *data);
1022typedef bool (*match_func_t) (hb_glyph_info_t &info, unsigned value, const void *data);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001023
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001024struct ContextClosureFuncs
1025{
1026 intersects_func_t intersects;
Qunxin Liub8a58a02021-01-10 15:50:04 -08001027 intersected_glyphs_func_t intersected_glyphs;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001028};
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001029struct ContextCollectGlyphsFuncs
1030{
1031 collect_glyphs_func_t collect;
1032};
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001033struct ContextApplyFuncs
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001034{
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001035 match_func_t match;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001036};
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06001037struct ChainContextApplyFuncs
1038{
1039 match_func_t match[3];
1040};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001041
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001042
Behdad Esfahbodc044f4a2022-12-03 11:58:04 -07001043static inline bool intersects_glyph (const hb_set_t *glyphs, unsigned value, const void *data HB_UNUSED, void *cache HB_UNUSED)
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001044{
1045 return glyphs->has (value);
1046}
Behdad Esfahbodc044f4a2022-12-03 11:58:04 -07001047static inline bool intersects_class (const hb_set_t *glyphs, unsigned value, const void *data, void *cache)
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001048{
1049 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
Behdad Esfahbodac8b2322022-11-30 16:42:15 -07001050 hb_map_t *map = (hb_map_t *) cache;
1051
1052 hb_codepoint_t *cached_v;
1053 if (map->has (value, &cached_v))
1054 return *cached_v;
1055
1056 bool v = class_def.intersects_class (glyphs, value);
1057 map->set (value, v);
1058
1059 return v;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001060}
Behdad Esfahbodc044f4a2022-12-03 11:58:04 -07001061static inline bool intersects_coverage (const hb_set_t *glyphs, unsigned value, const void *data, void *cache HB_UNUSED)
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001062{
Behdad Esfahbod8b349e12022-07-06 17:22:34 -06001063 Offset16To<Coverage> coverage;
1064 coverage = value;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001065 return (data+coverage).intersects (glyphs);
1066}
1067
Qunxin Liub8a58a02021-01-10 15:50:04 -08001068
Behdad Esfahbod630b8742022-12-03 12:13:15 -07001069static inline void intersected_glyph (const hb_set_t *glyphs HB_UNUSED, const void *data, unsigned value, hb_set_t *intersected_glyphs, HB_UNUSED void *cache)
Qunxin Liub8a58a02021-01-10 15:50:04 -08001070{
1071 unsigned g = reinterpret_cast<const HBUINT16 *>(data)[value];
1072 intersected_glyphs->add (g);
1073}
Behdad Esfahbod630b8742022-12-03 12:13:15 -07001074
1075using intersected_class_cache_t = hb_hashmap_t<unsigned, hb_set_t>;
1076
1077static inline void intersected_class_glyphs (const hb_set_t *glyphs, const void *data, unsigned value, hb_set_t *intersected_glyphs, void *cache)
Qunxin Liub8a58a02021-01-10 15:50:04 -08001078{
1079 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
Behdad Esfahbod630b8742022-12-03 12:13:15 -07001080
1081 intersected_class_cache_t *map = (intersected_class_cache_t *) cache;
1082
1083 hb_set_t *cached_v;
1084 if (map->has (value, &cached_v))
1085 {
1086 intersected_glyphs->union_ (*cached_v);
1087 return;
1088 }
1089
1090 hb_set_t v;
1091 class_def.intersected_class_glyphs (glyphs, value, &v);
1092
1093 intersected_glyphs->union_ (v);
1094
1095 map->set (value, std::move (v));
Qunxin Liub8a58a02021-01-10 15:50:04 -08001096}
Behdad Esfahbod630b8742022-12-03 12:13:15 -07001097
1098static inline void intersected_coverage_glyphs (const hb_set_t *glyphs, const void *data, unsigned value, hb_set_t *intersected_glyphs, HB_UNUSED void *cache)
Qunxin Liub8a58a02021-01-10 15:50:04 -08001099{
Behdad Esfahbodad28f972021-03-31 12:49:14 -06001100 Offset16To<Coverage> coverage;
Qunxin Liub8a58a02021-01-10 15:50:04 -08001101 coverage = value;
Behdad Esfahbod00dfbbc2022-07-21 11:39:32 -06001102 (data+coverage).intersect_set (*glyphs, *intersected_glyphs);
Qunxin Liub8a58a02021-01-10 15:50:04 -08001103}
1104
1105
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06001106template <typename HBUINT>
Qunxin Liu44d88cf2020-05-08 15:33:34 -07001107static inline bool array_is_subset_of (const hb_set_t *glyphs,
1108 unsigned int count,
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06001109 const HBUINT values[],
Qunxin Liu44d88cf2020-05-08 15:33:34 -07001110 intersects_func_t intersects_func,
Behdad Esfahbodac8b2322022-11-30 16:42:15 -07001111 const void *intersects_data,
Behdad Esfahbodc044f4a2022-12-03 11:58:04 -07001112 void *cache)
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001113{
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06001114 for (const auto &_ : + hb_iter (values, count))
Behdad Esfahbodac8b2322022-11-30 16:42:15 -07001115 if (!intersects_func (glyphs, _, intersects_data, cache)) return false;
Qunxin Liu44d88cf2020-05-08 15:33:34 -07001116 return true;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001117}
1118
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001119
Behdad Esfahbod8b349e12022-07-06 17:22:34 -06001120static inline void collect_glyph (hb_set_t *glyphs, unsigned value, const void *data HB_UNUSED)
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001121{
1122 glyphs->add (value);
1123}
Behdad Esfahbod8b349e12022-07-06 17:22:34 -06001124static inline void collect_class (hb_set_t *glyphs, unsigned value, const void *data)
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001125{
1126 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
Behdad Esfahbod89ad3c62020-04-23 10:57:30 -07001127 class_def.collect_class (glyphs, value);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001128}
Behdad Esfahbod8b349e12022-07-06 17:22:34 -06001129static inline void collect_coverage (hb_set_t *glyphs, unsigned value, const void *data)
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001130{
Behdad Esfahbod8b349e12022-07-06 17:22:34 -06001131 Offset16To<Coverage> coverage;
1132 coverage = value;
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07001133 (data+coverage).collect_coverage (glyphs);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001134}
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06001135template <typename HBUINT>
Behdad Esfahbod0beb66e2012-12-05 18:46:04 -05001136static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001137 hb_set_t *glyphs,
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001138 unsigned int count,
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06001139 const HBUINT values[],
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001140 collect_glyphs_func_t collect_func,
1141 const void *collect_data)
1142{
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001143 return
1144 + hb_iter (values, count)
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06001145 | hb_apply ([&] (const HBUINT &_) { collect_func (glyphs, _, collect_data); })
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001146 ;
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001147}
1148
1149
Behdad Esfahbod8b349e12022-07-06 17:22:34 -06001150static inline bool match_glyph (hb_glyph_info_t &info, unsigned value, const void *data HB_UNUSED)
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001151{
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06001152 return info.codepoint == value;
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001153}
Behdad Esfahbod8b349e12022-07-06 17:22:34 -06001154static inline bool match_class (hb_glyph_info_t &info, unsigned value, const void *data)
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001155{
Behdad Esfahbod2b5a59c2009-08-04 11:38:50 -04001156 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06001157 return class_def.get_class (info.codepoint) == value;
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001158}
Behdad Esfahbod8b349e12022-07-06 17:22:34 -06001159static inline bool match_class_cached (hb_glyph_info_t &info, unsigned value, const void *data)
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06001160{
1161 unsigned klass = info.syllable();
1162 if (klass < 255)
1163 return klass == value;
1164 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
1165 klass = class_def.get_class (info.codepoint);
1166 if (likely (klass < 255))
1167 info.syllable() = klass;
1168 return klass == value;
1169}
Behdad Esfahbod8b349e12022-07-06 17:22:34 -06001170static inline bool match_coverage (hb_glyph_info_t &info, unsigned value, const void *data)
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001171{
Behdad Esfahbod8b349e12022-07-06 17:22:34 -06001172 Offset16To<Coverage> coverage;
1173 coverage = value;
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06001174 return (data+coverage).get_coverage (info.codepoint) != NOT_COVERED;
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001175}
1176
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06001177template <typename HBUINT>
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001178static inline bool would_match_input (hb_would_apply_context_t *c,
1179 unsigned int count, /* Including the first glyph (not matched) */
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06001180 const HBUINT input[], /* Array of input values--start with second glyph */
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001181 match_func_t match_func,
1182 const void *match_data)
1183{
1184 if (count != c->len)
1185 return false;
1186
1187 for (unsigned int i = 1; i < count; i++)
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06001188 {
1189 hb_glyph_info_t info;
1190 info.codepoint = c->glyphs[i];
1191 if (likely (!match_func (info, input[i - 1], match_data)))
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001192 return false;
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06001193 }
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001194
1195 return true;
1196}
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06001197template <typename HBUINT>
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001198static inline bool match_input (hb_ot_apply_context_t *c,
Behdad Esfahbode072c242009-05-18 03:47:31 -04001199 unsigned int count, /* Including the first glyph (not matched) */
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06001200 const HBUINT input[], /* Array of input values--start with second glyph */
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001201 match_func_t match_func,
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04001202 const void *match_data,
Behdad Esfahbod78481b32021-11-21 16:50:34 -07001203 unsigned int *end_position,
Behdad Esfahbod5ba45042015-11-02 15:43:08 -08001204 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001205 unsigned int *p_total_component_count = nullptr)
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001206{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001207 TRACE_APPLY (nullptr);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -04001208
Behdad Esfahbod5ba45042015-11-02 15:43:08 -08001209 if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return_trace (false);
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001210
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +02001211 hb_buffer_t *buffer = c->buffer;
1212
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001213 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
Behdad Esfahbodb051be52015-01-29 13:40:39 +01001214 skippy_iter.reset (buffer->idx, count - 1);
Behdad Esfahbodf114b182022-07-06 17:31:46 -06001215 skippy_iter.set_match_func (match_func, match_data);
1216 skippy_iter.set_glyph_data (input);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -04001217
Behdad Esfahbod191fa882012-08-28 22:58:55 -04001218 /*
1219 * This is perhaps the trickiest part of OpenType... Remarks:
1220 *
1221 * - If all components of the ligature were marks, we call this a mark ligature.
1222 *
1223 * - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize
1224 * it as a ligature glyph.
1225 *
1226 * - Ligatures cannot be formed across glyphs attached to different components
1227 * of previous ligatures. Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and
1228 * LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother.
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +02001229 * However, it would be wrong to ligate that SHADDA,FATHA sequence.
1230 * There are a couple of exceptions to this:
1231 *
1232 * o If a ligature tries ligating with marks that belong to it itself, go ahead,
1233 * assuming that the font designer knows what they are doing (otherwise it can
1234 * break Indic stuff when a matra wants to ligate with a conjunct,
1235 *
1236 * o If two marks want to ligate and they belong to different components of the
1237 * same ligature glyph, and said ligature glyph is to be ignored according to
1238 * mark-filtering rules, then allow.
ebraminio7c6937e2017-11-20 14:49:22 -05001239 * https://github.com/harfbuzz/harfbuzz/issues/545
Behdad Esfahbod191fa882012-08-28 22:58:55 -04001240 */
1241
Behdad Esfahbod93814ca2012-08-28 22:24:51 -04001242 unsigned int total_component_count = 0;
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +02001243 total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur());
Behdad Esfahbod93814ca2012-08-28 22:24:51 -04001244
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +02001245 unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
1246 unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001247
Behdad Esfahbod621c49c2017-10-04 15:06:48 +02001248 enum {
1249 LIGBASE_NOT_CHECKED,
1250 LIGBASE_MAY_NOT_SKIP,
1251 LIGBASE_MAY_SKIP
1252 } ligbase = LIGBASE_NOT_CHECKED;
1253
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +02001254 match_positions[0] = buffer->idx;
Behdad Esfahbod370f03e2012-01-16 17:03:55 -05001255 for (unsigned int i = 1; i < count; i++)
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001256 {
Behdad Esfahbod3122c2c2021-12-04 19:50:33 -08001257 unsigned unsafe_to;
1258 if (!skippy_iter.next (&unsafe_to))
1259 {
Behdad Esfahbod78481b32021-11-21 16:50:34 -07001260 *end_position = unsafe_to;
Behdad Esfahbod3122c2c2021-12-04 19:50:33 -08001261 return_trace (false);
1262 }
Behdad Esfahbod6cc136f2013-10-17 13:55:48 +02001263
1264 match_positions[i] = skippy_iter.idx;
Behdad Esfahbod93814ca2012-08-28 22:24:51 -04001265
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +02001266 unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]);
1267 unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -04001268
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +02001269 if (first_lig_id && first_lig_comp)
1270 {
Behdad Esfahbod93814ca2012-08-28 22:24:51 -04001271 /* If first component was attached to a previous ligature component,
1272 * all subsequent components should be attached to the same ligature
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +02001273 * component, otherwise we shouldn't ligate them... */
Behdad Esfahbod93814ca2012-08-28 22:24:51 -04001274 if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +02001275 {
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03301276 /* ...unless, we are attached to a base ligature and that base
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +02001277 * ligature is ignorable. */
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03301278 if (ligbase == LIGBASE_NOT_CHECKED)
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +02001279 {
Behdad Esfahbod621c49c2017-10-04 15:06:48 +02001280 bool found = false;
Behdad Esfahbod4d677432019-05-10 16:35:31 -07001281 const auto *out = buffer->out_info;
Behdad Esfahbod621c49c2017-10-04 15:06:48 +02001282 unsigned int j = buffer->out_len;
1283 while (j && _hb_glyph_info_get_lig_id (&out[j - 1]) == first_lig_id)
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +02001284 {
Behdad Esfahbod621c49c2017-10-04 15:06:48 +02001285 if (_hb_glyph_info_get_lig_comp (&out[j - 1]) == 0)
1286 {
1287 j--;
1288 found = true;
1289 break;
1290 }
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +02001291 j--;
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +02001292 }
Behdad Esfahbod621c49c2017-10-04 15:06:48 +02001293
Behdad Esfahbod12757b62018-01-26 18:14:05 -08001294 if (found && skippy_iter.may_skip (out[j]) == hb_ot_apply_context_t::matcher_t::SKIP_YES)
Behdad Esfahbod621c49c2017-10-04 15:06:48 +02001295 ligbase = LIGBASE_MAY_SKIP;
1296 else
1297 ligbase = LIGBASE_MAY_NOT_SKIP;
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +02001298 }
1299
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03301300 if (ligbase == LIGBASE_MAY_NOT_SKIP)
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +02001301 return_trace (false);
1302 }
1303 }
1304 else
Behdad Esfahbod621c49c2017-10-04 15:06:48 +02001305 {
Behdad Esfahbod93814ca2012-08-28 22:24:51 -04001306 /* If first component was NOT attached to a previous ligature component,
1307 * all subsequent components should also NOT be attached to any ligature
1308 * component, unless they are attached to the first component itself! */
1309 if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id))
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001310 return_trace (false);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -04001311 }
1312
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +02001313 total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001314 }
1315
Behdad Esfahbod78481b32021-11-21 16:50:34 -07001316 *end_position = skippy_iter.idx + 1;
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001317
Behdad Esfahbod191fa882012-08-28 22:58:55 -04001318 if (p_total_component_count)
1319 *p_total_component_count = total_component_count;
1320
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001321 return_trace (true);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001322}
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001323static inline bool ligate_input (hb_ot_apply_context_t *c,
Behdad Esfahbode714fe62013-10-17 13:49:51 +02001324 unsigned int count, /* Including the first glyph */
Bruce Mitchener5a24ea12018-10-20 08:09:52 +07001325 const unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
Behdad Esfahbod78481b32021-11-21 16:50:34 -07001326 unsigned int match_end,
Behdad Esfahboda177d022012-08-28 23:18:22 -04001327 hb_codepoint_t lig_glyph,
Behdad Esfahboda177d022012-08-28 23:18:22 -04001328 unsigned int total_component_count)
1329{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001330 TRACE_APPLY (nullptr);
Behdad Esfahbode714fe62013-10-17 13:49:51 +02001331
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +02001332 hb_buffer_t *buffer = c->buffer;
1333
Behdad Esfahbod78481b32021-11-21 16:50:34 -07001334 buffer->merge_clusters (buffer->idx, match_end);
Behdad Esfahbod607feb72013-02-14 07:43:13 -05001335
Behdad Esfahbod9efddb92018-10-02 16:05:26 +02001336 /* - If a base and one or more marks ligate, consider that as a base, NOT
1337 * ligature, such that all following marks can still attach to it.
1338 * https://github.com/harfbuzz/harfbuzz/issues/1109
1339 *
1340 * - If all components of the ligature were marks, we call this a mark ligature.
Behdad Esfahbod3cca9782018-10-02 15:02:16 +02001341 * If it *is* a mark ligature, we don't allocate a new ligature id, and leave
Behdad Esfahboda177d022012-08-28 23:18:22 -04001342 * the ligature to keep its old ligature id. This will allow it to attach to
1343 * a base ligature in GPOS. Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH,
Behdad Esfahbod3cca9782018-10-02 15:02:16 +02001344 * and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA with a
Behdad Esfahboda177d022012-08-28 23:18:22 -04001345 * ligature id and component value of 2. Then if SHADDA,FATHA form a ligature
1346 * later, we don't want them to lose their ligature id/component, otherwise
1347 * GPOS will fail to correctly position the mark ligature on top of the
1348 * LAM,LAM,HEH ligature. See:
1349 * https://bugzilla.gnome.org/show_bug.cgi?id=676343
1350 *
1351 * - If a ligature is formed of components that some of which are also ligatures
1352 * themselves, and those ligature components had marks attached to *their*
1353 * components, we have to attach the marks to the new ligature component
1354 * positions! Now *that*'s tricky! And these marks may be following the
1355 * last component of the whole sequence, so we should loop forward looking
1356 * for them and update them.
1357 *
1358 * Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a
1359 * 'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature
1360 * id and component == 1. Now, during 'liga', the LAM and the LAM-HEH ligature
1361 * form a LAM-LAM-HEH ligature. We need to reassign the SHADDA and FATHA to
1362 * the new ligature with a component value of 2.
1363 *
1364 * This in fact happened to a font... See:
1365 * https://bugzilla.gnome.org/show_bug.cgi?id=437633
1366 */
1367
Behdad Esfahbod9efddb92018-10-02 16:05:26 +02001368 bool is_base_ligature = _hb_glyph_info_is_base_glyph (&buffer->info[match_positions[0]]);
1369 bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->info[match_positions[0]]);
1370 for (unsigned int i = 1; i < count; i++)
Behdad Esfahbod3cca9782018-10-02 15:02:16 +02001371 if (!_hb_glyph_info_is_mark (&buffer->info[match_positions[i]]))
1372 {
Behdad Esfahbod9efddb92018-10-02 16:05:26 +02001373 is_base_ligature = false;
Behdad Esfahbod3cca9782018-10-02 15:02:16 +02001374 is_mark_ligature = false;
1375 break;
1376 }
Behdad Esfahbod9efddb92018-10-02 16:05:26 +02001377 bool is_ligature = !is_base_ligature && !is_mark_ligature;
Behdad Esfahbod3cca9782018-10-02 15:02:16 +02001378
Behdad Esfahbod9efddb92018-10-02 16:05:26 +02001379 unsigned int klass = is_ligature ? HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE : 0;
1380 unsigned int lig_id = is_ligature ? _hb_allocate_lig_id (buffer) : 0;
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +02001381 unsigned int last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
1382 unsigned int last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
Behdad Esfahboda177d022012-08-28 23:18:22 -04001383 unsigned int components_so_far = last_num_components;
1384
Behdad Esfahbod9efddb92018-10-02 16:05:26 +02001385 if (is_ligature)
Behdad Esfahbod7e08f122013-05-27 14:48:34 -04001386 {
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +02001387 _hb_glyph_info_set_lig_props_for_ligature (&buffer->cur(), lig_id, total_component_count);
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +02001388 if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
Behdad Esfahbod3d436d32013-10-28 21:00:37 +01001389 {
Behdad Esfahbod82596692015-11-02 17:44:05 -08001390 _hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER);
Behdad Esfahbod3d436d32013-10-28 21:00:37 +01001391 }
Behdad Esfahbod7e08f122013-05-27 14:48:34 -04001392 }
Behdad Esfahboda0161742013-10-18 00:06:30 +02001393 c->replace_glyph_with_ligature (lig_glyph, klass);
Behdad Esfahboda177d022012-08-28 23:18:22 -04001394
1395 for (unsigned int i = 1; i < count; i++)
1396 {
Behdad Esfahbod7185b272018-05-31 20:03:00 -07001397 while (buffer->idx < match_positions[i] && buffer->successful)
Behdad Esfahboda177d022012-08-28 23:18:22 -04001398 {
Behdad Esfahbod9efddb92018-10-02 16:05:26 +02001399 if (is_ligature)
1400 {
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03301401 unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
Behdad Esfahbod2f02fc72015-12-17 15:21:14 +00001402 if (this_comp == 0)
Behdad Esfahbod100fbea2015-12-17 15:23:09 +00001403 this_comp = last_num_components;
Behdad Esfahboda177d022012-08-28 23:18:22 -04001404 unsigned int new_lig_comp = components_so_far - last_num_components +
Behdad Esfahbod41248cc2019-05-07 20:54:31 -07001405 hb_min (this_comp, last_num_components);
Behdad Esfahbod2f02fc72015-12-17 15:21:14 +00001406 _hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
Behdad Esfahboda177d022012-08-28 23:18:22 -04001407 }
Behdad Esfahbod8450f432021-03-15 15:18:06 -06001408 (void) buffer->next_glyph ();
Behdad Esfahboda177d022012-08-28 23:18:22 -04001409 }
1410
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +02001411 last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
1412 last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
Behdad Esfahboda177d022012-08-28 23:18:22 -04001413 components_so_far += last_num_components;
1414
1415 /* Skip the base glyph */
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +02001416 buffer->idx++;
Behdad Esfahboda177d022012-08-28 23:18:22 -04001417 }
1418
Ebrahim Byagowicc977b62020-03-26 11:18:02 +04301419 if (!is_mark_ligature && last_lig_id)
1420 {
Behdad Esfahboda177d022012-08-28 23:18:22 -04001421 /* Re-adjust components for any marks following. */
Ebrahim Byagowicc977b62020-03-26 11:18:02 +04301422 for (unsigned i = buffer->idx; i < buffer->len; ++i)
1423 {
1424 if (last_lig_id != _hb_glyph_info_get_lig_id (&buffer->info[i])) break;
1425
1426 unsigned this_comp = _hb_glyph_info_get_lig_comp (&buffer->info[i]);
1427 if (!this_comp) break;
1428
1429 unsigned new_lig_comp = components_so_far - last_num_components +
1430 hb_min (this_comp, last_num_components);
1431 _hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
Behdad Esfahboda177d022012-08-28 23:18:22 -04001432 }
1433 }
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001434 return_trace (true);
Behdad Esfahboda177d022012-08-28 23:18:22 -04001435}
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001436
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06001437template <typename HBUINT>
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001438static inline bool match_backtrack (hb_ot_apply_context_t *c,
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001439 unsigned int count,
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06001440 const HBUINT backtrack[],
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001441 match_func_t match_func,
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001442 const void *match_data,
1443 unsigned int *match_start)
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001444{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001445 TRACE_APPLY (nullptr);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -04001446
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001447 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
Behdad Esfahbodb051be52015-01-29 13:40:39 +01001448 skippy_iter.reset (c->buffer->backtrack_len (), count);
Behdad Esfahbodf114b182022-07-06 17:31:46 -06001449 skippy_iter.set_match_func (match_func, match_data);
1450 skippy_iter.set_glyph_data (backtrack);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001451
Behdad Esfahbod4d3aeb82012-01-16 16:43:26 -05001452 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod3122c2c2021-12-04 19:50:33 -08001453 {
1454 unsigned unsafe_from;
1455 if (!skippy_iter.prev (&unsafe_from))
1456 {
Behdad Esfahbod78481b32021-11-21 16:50:34 -07001457 *match_start = unsafe_from;
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001458 return_trace (false);
Behdad Esfahbod3122c2c2021-12-04 19:50:33 -08001459 }
1460 }
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001461
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001462 *match_start = skippy_iter.idx;
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001463 return_trace (true);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001464}
1465
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06001466template <typename HBUINT>
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001467static inline bool match_lookahead (hb_ot_apply_context_t *c,
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001468 unsigned int count,
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06001469 const HBUINT lookahead[],
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001470 match_func_t match_func,
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04001471 const void *match_data,
Behdad Esfahbod78481b32021-11-21 16:50:34 -07001472 unsigned int start_index,
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001473 unsigned int *end_index)
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001474{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001475 TRACE_APPLY (nullptr);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -04001476
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001477 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
Behdad Esfahbod78481b32021-11-21 16:50:34 -07001478 skippy_iter.reset (start_index - 1, count);
Behdad Esfahbodf114b182022-07-06 17:31:46 -06001479 skippy_iter.set_match_func (match_func, match_data);
1480 skippy_iter.set_glyph_data (lookahead);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001481
Behdad Esfahbod370f03e2012-01-16 17:03:55 -05001482 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod3122c2c2021-12-04 19:50:33 -08001483 {
1484 unsigned unsafe_to;
1485 if (!skippy_iter.next (&unsafe_to))
1486 {
Behdad Esfahbod78481b32021-11-21 16:50:34 -07001487 *end_index = unsafe_to;
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001488 return_trace (false);
Behdad Esfahbod3122c2c2021-12-04 19:50:33 -08001489 }
1490 }
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001491
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001492 *end_index = skippy_iter.idx + 1;
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001493 return_trace (true);
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001494}
1495
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04001496
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001497
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001498struct LookupRecord
1499{
Qunxin Liu36ed56b2021-09-23 10:51:21 -07001500 bool serialize (hb_serialize_context_t *c,
1501 const hb_map_t *lookup_map) const
Qunxin Liu0b39c482019-10-22 16:00:43 -07001502 {
1503 TRACE_SERIALIZE (this);
1504 auto *out = c->embed (*this);
Qunxin Liu36ed56b2021-09-23 10:51:21 -07001505 if (unlikely (!out)) return_trace (false);
Qunxin Liu0b39c482019-10-22 16:00:43 -07001506
Qunxin Liu36ed56b2021-09-23 10:51:21 -07001507 return_trace (c->check_assign (out->lookupListIndex, lookup_map->get (lookupListIndex), HB_SERIALIZE_ERROR_INT_OVERFLOW));
Qunxin Liu0b39c482019-10-22 16:00:43 -07001508 }
1509
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301510 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001511 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001512 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001513 return_trace (c->check_struct (this));
Behdad Esfahbodcd3827e2009-08-04 02:09:34 -04001514 }
1515
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001516 HBUINT16 sequenceIndex; /* Index into current glyph
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001517 * sequence--first glyph = 0 */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001518 HBUINT16 lookupListIndex; /* Lookup to apply to that
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001519 * position--zero--based */
Behdad Esfahbod569da922010-05-10 16:38:32 -04001520 public:
1521 DEFINE_SIZE_STATIC (4);
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001522};
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001523
Qunxin Liu36ed56b2021-09-23 10:51:21 -07001524static unsigned serialize_lookuprecord_array (hb_serialize_context_t *c,
1525 const hb_array_t<const LookupRecord> lookupRecords,
1526 const hb_map_t *lookup_map)
1527{
1528 unsigned count = 0;
1529 for (const LookupRecord& r : lookupRecords)
1530 {
1531 if (!lookup_map->has (r.lookupListIndex))
1532 continue;
1533
1534 if (!r.serialize (c, lookup_map))
1535 return 0;
1536
1537 count++;
1538 }
1539 return count;
1540}
1541
Qunxin Liub8a58a02021-01-10 15:50:04 -08001542enum ContextFormat { SimpleContext = 1, ClassBasedContext = 2, CoverageBasedContext = 3 };
1543
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06001544template <typename HBUINT>
Qunxin Liub8a58a02021-01-10 15:50:04 -08001545static void context_closure_recurse_lookups (hb_closure_context_t *c,
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06001546 unsigned inputCount, const HBUINT input[],
Qunxin Liub8a58a02021-01-10 15:50:04 -08001547 unsigned lookupCount,
1548 const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */,
1549 unsigned value,
1550 ContextFormat context_format,
1551 const void *data,
Behdad Esfahbod630b8742022-12-03 12:13:15 -07001552 intersected_glyphs_func_t intersected_glyphs_func,
1553 void *cache)
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001554{
Behdad Esfahboda90f1492023-01-05 13:52:11 -07001555 hb_set_t covered_seq_indicies;
Behdad Esfahbod3947ced2023-01-05 14:47:47 -07001556 hb_set_t pos_glyphs;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001557 for (unsigned int i = 0; i < lookupCount; i++)
Qunxin Liub8a58a02021-01-10 15:50:04 -08001558 {
1559 unsigned seqIndex = lookupRecord[i].sequenceIndex;
Garret Riegeradca4ce2021-03-30 13:20:50 -07001560 if (seqIndex >= inputCount) continue;
Qunxin Liub8a58a02021-01-10 15:50:04 -08001561
Garret Riegerf3c1f4f2022-01-28 11:50:22 -08001562 bool has_pos_glyphs = false;
Qunxin Liub8a58a02021-01-10 15:50:04 -08001563
Behdad Esfahboda90f1492023-01-05 13:52:11 -07001564 if (!covered_seq_indicies.has (seqIndex))
Qunxin Liub8a58a02021-01-10 15:50:04 -08001565 {
Garret Riegerf3c1f4f2022-01-28 11:50:22 -08001566 has_pos_glyphs = true;
Behdad Esfahboda90f1492023-01-05 13:52:11 -07001567 pos_glyphs.clear ();
Qunxin Liub8a58a02021-01-10 15:50:04 -08001568 if (seqIndex == 0)
1569 {
1570 switch (context_format) {
1571 case ContextFormat::SimpleContext:
Garret Riegerf3c1f4f2022-01-28 11:50:22 -08001572 pos_glyphs.add (value);
Qunxin Liub8a58a02021-01-10 15:50:04 -08001573 break;
1574 case ContextFormat::ClassBasedContext:
Behdad Esfahbod630b8742022-12-03 12:13:15 -07001575 intersected_glyphs_func (&c->parent_active_glyphs (), data, value, &pos_glyphs, cache);
Qunxin Liub8a58a02021-01-10 15:50:04 -08001576 break;
1577 case ContextFormat::CoverageBasedContext:
Garret Riegerbc899652022-01-28 13:54:10 -08001578 pos_glyphs.set (c->parent_active_glyphs ());
Qunxin Liub8a58a02021-01-10 15:50:04 -08001579 break;
1580 }
1581 }
1582 else
1583 {
1584 const void *input_data = input;
1585 unsigned input_value = seqIndex - 1;
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08001586 if (context_format != ContextFormat::SimpleContext)
Qunxin Liub8a58a02021-01-10 15:50:04 -08001587 {
1588 input_data = data;
1589 input_value = input[seqIndex - 1];
1590 }
Garret Riegerc6adb902021-03-29 16:08:44 -07001591
Behdad Esfahbod630b8742022-12-03 12:13:15 -07001592 intersected_glyphs_func (c->glyphs, input_data, input_value, &pos_glyphs, cache);
Qunxin Liub8a58a02021-01-10 15:50:04 -08001593 }
1594 }
1595
Behdad Esfahboda90f1492023-01-05 13:52:11 -07001596 covered_seq_indicies.add (seqIndex);
Garret Riegerf3c1f4f2022-01-28 11:50:22 -08001597 if (has_pos_glyphs) {
Behdad Esfahbod2764a612023-01-05 15:14:54 -07001598 c->push_cur_active_glyphs () = std::move (pos_glyphs);
Garret Riegerf3c1f4f2022-01-28 11:50:22 -08001599 } else {
1600 c->push_cur_active_glyphs ().set (*c->glyphs);
1601 }
Garret Riegerc6adb902021-03-29 16:08:44 -07001602
Qunxin Liub8a58a02021-01-10 15:50:04 -08001603 unsigned endIndex = inputCount;
1604 if (context_format == ContextFormat::CoverageBasedContext)
1605 endIndex += 1;
1606
Behdad Esfahboda90f1492023-01-05 13:52:11 -07001607 c->recurse (lookupRecord[i].lookupListIndex, &covered_seq_indicies, seqIndex, endIndex);
Garret Riegerc6adb902021-03-29 16:08:44 -07001608
Qunxin Liu706014f2021-12-01 20:20:12 -08001609 c->pop_cur_done_glyphs ();
Qunxin Liub8a58a02021-01-10 15:50:04 -08001610 }
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001611}
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04001612
Qunxin Liub8a58a02021-01-10 15:50:04 -08001613template <typename context_t>
1614static inline void recurse_lookups (context_t *c,
1615 unsigned int lookupCount,
1616 const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
1617{
1618 for (unsigned int i = 0; i < lookupCount; i++)
1619 c->recurse (lookupRecord[i].lookupListIndex);
1620}
1621
Behdad Esfahbod78481b32021-11-21 16:50:34 -07001622static inline void apply_lookup (hb_ot_apply_context_t *c,
Behdad Esfahbode072c242009-05-18 03:47:31 -04001623 unsigned int count, /* Including the first glyph */
Behdad Esfahbod5ba45042015-11-02 15:43:08 -08001624 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
Behdad Esfahbode072c242009-05-18 03:47:31 -04001625 unsigned int lookupCount,
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001626 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
Behdad Esfahbod78481b32021-11-21 16:50:34 -07001627 unsigned int match_end)
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001628{
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001629 hb_buffer_t *buffer = c->buffer;
jfkthame44f7d6e2017-02-17 03:03:24 +00001630 int end;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001631
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001632 /* All positions are distance from beginning of *output* buffer.
1633 * Adjust. */
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001634 {
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001635 unsigned int bl = buffer->backtrack_len ();
Behdad Esfahbod78481b32021-11-21 16:50:34 -07001636 end = bl + match_end - buffer->idx;
Behdad Esfahbod8751de52013-07-18 16:29:50 -04001637
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001638 int delta = bl - buffer->idx;
1639 /* Convert positions to new indexing. */
1640 for (unsigned int j = 0; j < count; j++)
1641 match_positions[j] += delta;
Behdad Esfahbod8820bb22013-02-14 07:41:03 -05001642 }
Behdad Esfahbode73a0c22009-05-18 04:15:25 -04001643
Behdad Esfahbod7185b272018-05-31 20:03:00 -07001644 for (unsigned int i = 0; i < lookupCount && buffer->successful; i++)
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001645 {
1646 unsigned int idx = lookupRecord[i].sequenceIndex;
1647 if (idx >= count)
1648 continue;
1649
Behdad Esfahbodccd91612022-03-24 13:10:48 -06001650 unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
1651
1652 /* This can happen if earlier recursed lookups deleted many entries. */
1653 if (unlikely (match_positions[idx] >= orig_len))
1654 continue;
1655
Behdad Esfahbode5930722017-11-14 15:47:55 -08001656 if (unlikely (!buffer->move_to (match_positions[idx])))
1657 break;
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001658
Behdad Esfahbodbaf77792017-11-14 21:53:48 -08001659 if (unlikely (buffer->max_ops <= 0))
1660 break;
1661
Behdad Esfahbodbc80e4b2022-07-24 18:48:38 -06001662 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
1663 {
1664 if (buffer->have_output)
1665 c->buffer->sync_so_far ();
1666 c->buffer->message (c->font,
Behdad Esfahboded023f62023-01-12 17:04:24 -07001667 "recursing to lookup %u at %u",
Behdad Esfahbodbc80e4b2022-07-24 18:48:38 -06001668 (unsigned) lookupRecord[i].lookupListIndex,
1669 buffer->idx);
1670 }
1671
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001672 if (!c->recurse (lookupRecord[i].lookupListIndex))
1673 continue;
1674
Behdad Esfahbodbc80e4b2022-07-24 18:48:38 -06001675 if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
1676 {
1677 if (buffer->have_output)
1678 c->buffer->sync_so_far ();
1679 c->buffer->message (c->font,
Behdad Esfahbod94de3282022-07-24 18:51:55 -06001680 "recursed to lookup %u",
1681 (unsigned) lookupRecord[i].lookupListIndex);
Behdad Esfahbodbc80e4b2022-07-24 18:48:38 -06001682 }
1683
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001684 unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len ();
1685 int delta = new_len - orig_len;
1686
1687 if (!delta)
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03301688 continue;
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001689
Behdad Esfahbod9ac9af72017-03-05 13:51:01 -08001690 /* Recursed lookup changed buffer len. Adjust.
1691 *
1692 * TODO:
1693 *
1694 * Right now, if buffer length increased by n, we assume n new glyphs
1695 * were added right after the current position, and if buffer length
1696 * was decreased by n, we assume n match positions after the current
1697 * one where removed. The former (buffer length increased) case is
1698 * fine, but the decrease case can be improved in at least two ways,
1699 * both of which are significant:
1700 *
1701 * - If recursed-to lookup is MultipleSubst and buffer length
1702 * decreased, then it's current match position that was deleted,
1703 * NOT the one after it.
1704 *
1705 * - If buffer length was decreased by n, it does not necessarily
Behdad Esfahboda85461b2022-04-20 12:13:16 -06001706 * mean that n match positions where removed, as there recursed-to
1707 * lookup might had a different LookupFlag. Here's a constructed
1708 * case of that:
1709 * https://github.com/harfbuzz/harfbuzz/discussions/3538
Behdad Esfahbod9ac9af72017-03-05 13:51:01 -08001710 *
1711 * It should be possible to construct tests for both of these cases.
1712 */
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001713
jfkthame44f7d6e2017-02-17 03:03:24 +00001714 end += delta;
Behdad Esfahbodccd91612022-03-24 13:10:48 -06001715 if (end < int (match_positions[idx]))
Behdad Esfahbod359dead2016-05-06 16:19:19 +01001716 {
Behdad Esfahbod4b4a1b92016-12-21 23:10:43 -06001717 /* End might end up being smaller than match_positions[idx] if the recursed
Behdad Esfahbodccd91612022-03-24 13:10:48 -06001718 * lookup ended up removing many items.
1719 * Just never rewind end beyond start of current position, since that is
1720 * not possible in the recursed lookup. Also adjust delta as such.
1721 *
1722 * https://bugs.chromium.org/p/chromium/issues/detail?id=659496
1723 * https://github.com/harfbuzz/harfbuzz/issues/1611
1724 */
1725 delta += match_positions[idx] - end;
Behdad Esfahbod4b4a1b92016-12-21 23:10:43 -06001726 end = match_positions[idx];
Behdad Esfahbod359dead2016-05-06 16:19:19 +01001727 }
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001728
1729 unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */
1730
1731 if (delta > 0)
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001732 {
Behdad Esfahbod5ba45042015-11-02 15:43:08 -08001733 if (unlikely (delta + count > HB_MAX_CONTEXT_LENGTH))
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001734 break;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001735 }
1736 else
1737 {
Behdad Esfahbodbf2a8452022-03-24 13:09:53 -06001738 /* NOTE: delta is non-positive. */
Behdad Esfahbod41248cc2019-05-07 20:54:31 -07001739 delta = hb_max (delta, (int) next - (int) count);
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001740 next -= delta;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001741 }
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001742
1743 /* Shift! */
1744 memmove (match_positions + next + delta, match_positions + next,
1745 (count - next) * sizeof (match_positions[0]));
1746 next += delta;
1747 count += delta;
1748
1749 /* Fill in new entries. */
1750 for (unsigned int j = idx + 1; j < next; j++)
1751 match_positions[j] = match_positions[j - 1] + 1;
1752
1753 /* And fixup the rest. */
1754 for (; next < count; next++)
1755 match_positions[next] += delta;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001756 }
1757
Behdad Esfahbodcac6c862021-03-15 13:46:54 -06001758 (void) buffer->move_to (end);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001759}
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001760
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04001761
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001762
1763/* Contextual lookups */
1764
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001765struct ContextClosureLookupContext
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001766{
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001767 ContextClosureFuncs funcs;
Qunxin Liub8a58a02021-01-10 15:50:04 -08001768 ContextFormat context_format;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001769 const void *intersects_data;
Behdad Esfahbod630b8742022-12-03 12:13:15 -07001770 void *intersects_cache;
1771 void *intersected_glyphs_cache;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001772};
1773
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001774struct ContextCollectGlyphsLookupContext
1775{
1776 ContextCollectGlyphsFuncs funcs;
1777 const void *collect_data;
1778};
1779
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001780struct ContextApplyLookupContext
1781{
1782 ContextApplyFuncs funcs;
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04001783 const void *match_data;
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001784};
1785
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06001786template <typename HBUINT>
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001787static inline bool context_intersects (const hb_set_t *glyphs,
1788 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06001789 const HBUINT input[], /* Array of input values--start with second glyph */
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001790 ContextClosureLookupContext &lookup_context)
1791{
Qunxin Liu44d88cf2020-05-08 15:33:34 -07001792 return array_is_subset_of (glyphs,
1793 inputCount ? inputCount - 1 : 0, input,
Behdad Esfahbod630b8742022-12-03 12:13:15 -07001794 lookup_context.funcs.intersects,
1795 lookup_context.intersects_data,
1796 lookup_context.intersects_cache);
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001797}
1798
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06001799template <typename HBUINT>
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001800static inline void context_closure_lookup (hb_closure_context_t *c,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001801 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06001802 const HBUINT input[], /* Array of input values--start with second glyph */
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001803 unsigned int lookupCount,
1804 const LookupRecord lookupRecord[],
Qunxin Liub8a58a02021-01-10 15:50:04 -08001805 unsigned value, /* Index of first glyph in Coverage or Class value in ClassDef table */
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001806 ContextClosureLookupContext &lookup_context)
1807{
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001808 if (context_intersects (c->glyphs,
1809 inputCount, input,
1810 lookup_context))
Qunxin Liub8a58a02021-01-10 15:50:04 -08001811 context_closure_recurse_lookups (c,
1812 inputCount, input,
1813 lookupCount, lookupRecord,
1814 value,
1815 lookup_context.context_format,
1816 lookup_context.intersects_data,
Behdad Esfahbod630b8742022-12-03 12:13:15 -07001817 lookup_context.funcs.intersected_glyphs,
1818 lookup_context.intersected_glyphs_cache);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001819}
1820
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06001821template <typename HBUINT>
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001822static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
1823 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06001824 const HBUINT input[], /* Array of input values--start with second glyph */
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001825 unsigned int lookupCount,
1826 const LookupRecord lookupRecord[],
1827 ContextCollectGlyphsLookupContext &lookup_context)
1828{
Behdad Esfahbod83035932012-12-04 17:08:41 -05001829 collect_array (c, c->input,
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001830 inputCount ? inputCount - 1 : 0, input,
1831 lookup_context.funcs.collect, lookup_context.collect_data);
1832 recurse_lookups (c,
1833 lookupCount, lookupRecord);
1834}
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001835
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06001836template <typename HBUINT>
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001837static inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
1838 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06001839 const HBUINT input[], /* Array of input values--start with second glyph */
Behdad Esfahbod0beb66e2012-12-05 18:46:04 -05001840 unsigned int lookupCount HB_UNUSED,
1841 const LookupRecord lookupRecord[] HB_UNUSED,
Behdad Esfahbod19ec01d2022-11-16 19:14:42 -07001842 const ContextApplyLookupContext &lookup_context)
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001843{
1844 return would_match_input (c,
1845 inputCount, input,
1846 lookup_context.funcs.match, lookup_context.match_data);
1847}
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06001848
1849template <typename HBUINT>
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001850static inline bool context_apply_lookup (hb_ot_apply_context_t *c,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001851 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06001852 const HBUINT input[], /* Array of input values--start with second glyph */
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001853 unsigned int lookupCount,
1854 const LookupRecord lookupRecord[],
Behdad Esfahbod19ec01d2022-11-16 19:14:42 -07001855 const ContextApplyLookupContext &lookup_context)
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001856{
Behdad Esfahbod78481b32021-11-21 16:50:34 -07001857 unsigned match_end = 0;
1858 unsigned match_positions[HB_MAX_CONTEXT_LENGTH];
1859 if (match_input (c,
1860 inputCount, input,
1861 lookup_context.funcs.match, lookup_context.match_data,
1862 &match_end, match_positions))
1863 {
1864 c->buffer->unsafe_to_break (c->buffer->idx, match_end);
1865 apply_lookup (c,
1866 inputCount, match_positions,
1867 lookupCount, lookupRecord,
1868 match_end);
1869 return true;
1870 }
1871 else
1872 {
1873 c->buffer->unsafe_to_concat (c->buffer->idx, match_end);
1874 return false;
1875 }
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001876}
1877
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06001878template <typename Types>
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001879struct Rule
1880{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301881 bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001882 {
1883 return context_intersects (glyphs,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001884 inputCount, inputZ.arrayZ,
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001885 lookup_context);
1886 }
1887
Qunxin Liub8a58a02021-01-10 15:50:04 -08001888 void closure (hb_closure_context_t *c, unsigned value, ContextClosureLookupContext &lookup_context) const
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001889 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04301890 if (unlikely (c->lookup_limit_exceeded ())) return;
Garret Rieger014e0382020-03-31 16:29:29 -07001891
Behdad Esfahbod51922942022-07-08 14:00:24 -06001892 const auto &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
1893 (inputZ.as_array ((inputCount ? inputCount - 1 : 0)));
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001894 context_closure_lookup (c,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001895 inputCount, inputZ.arrayZ,
1896 lookupCount, lookupRecord.arrayZ,
Qunxin Liub8a58a02021-01-10 15:50:04 -08001897 value, lookup_context);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001898 }
1899
Garret Rieger9fad5402020-09-28 13:24:25 -07001900 void closure_lookups (hb_closure_lookups_context_t *c,
1901 ContextClosureLookupContext &lookup_context) const
Qunxin Liu0b39c482019-10-22 16:00:43 -07001902 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04301903 if (unlikely (c->lookup_limit_exceeded ())) return;
Garret Rieger9fad5402020-09-28 13:24:25 -07001904 if (!intersects (c->glyphs, lookup_context)) return;
Garret Rieger014e0382020-03-31 16:29:29 -07001905
Behdad Esfahbod51922942022-07-08 14:00:24 -06001906 const auto &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
1907 (inputZ.as_array (inputCount ? inputCount - 1 : 0));
Qunxin Liu0b39c482019-10-22 16:00:43 -07001908 recurse_lookups (c, lookupCount, lookupRecord.arrayZ);
1909 }
1910
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301911 void collect_glyphs (hb_collect_glyphs_context_t *c,
1912 ContextCollectGlyphsLookupContext &lookup_context) const
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001913 {
Behdad Esfahbod51922942022-07-08 14:00:24 -06001914 const auto &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
1915 (inputZ.as_array (inputCount ? inputCount - 1 : 0));
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001916 context_collect_glyphs_lookup (c,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001917 inputCount, inputZ.arrayZ,
1918 lookupCount, lookupRecord.arrayZ,
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001919 lookup_context);
1920 }
1921
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301922 bool would_apply (hb_would_apply_context_t *c,
Behdad Esfahbod19ec01d2022-11-16 19:14:42 -07001923 const ContextApplyLookupContext &lookup_context) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001924 {
Behdad Esfahbod51922942022-07-08 14:00:24 -06001925 const auto &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
1926 (inputZ.as_array (inputCount ? inputCount - 1 : 0));
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07001927 return context_would_apply_lookup (c,
1928 inputCount, inputZ.arrayZ,
1929 lookupCount, lookupRecord.arrayZ,
1930 lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001931 }
1932
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301933 bool apply (hb_ot_apply_context_t *c,
Behdad Esfahbod19ec01d2022-11-16 19:14:42 -07001934 const ContextApplyLookupContext &lookup_context) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001935 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001936 TRACE_APPLY (this);
Behdad Esfahbod51922942022-07-08 14:00:24 -06001937 const auto &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
1938 (inputZ.as_array (inputCount ? inputCount - 1 : 0));
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001939 return_trace (context_apply_lookup (c, inputCount, inputZ.arrayZ, lookupCount, lookupRecord.arrayZ, lookup_context));
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001940 }
1941
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001942 bool serialize (hb_serialize_context_t *c,
1943 const hb_map_t *input_mapping, /* old->new glyphid or class mapping */
1944 const hb_map_t *lookup_map) const
1945 {
1946 TRACE_SERIALIZE (this);
1947 auto *out = c->start_embed (this);
1948 if (unlikely (!c->extend_min (out))) return_trace (false);
1949
1950 out->inputCount = inputCount;
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06001951 const auto input = inputZ.as_array (inputCount - 1);
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001952 for (const auto org : input)
1953 {
1954 HBUINT16 d;
1955 d = input_mapping->get (org);
1956 c->copy (d);
1957 }
1958
Behdad Esfahbod51922942022-07-08 14:00:24 -06001959 const auto &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
1960 (inputZ.as_array ((inputCount ? inputCount - 1 : 0)));
Garret Riegerf51b48c2021-11-02 16:16:52 -07001961
Qunxin Liu36ed56b2021-09-23 10:51:21 -07001962 unsigned count = serialize_lookuprecord_array (c, lookupRecord.as_array (lookupCount), lookup_map);
1963 return_trace (c->check_assign (out->lookupCount, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001964 }
1965
1966 bool subset (hb_subset_context_t *c,
1967 const hb_map_t *lookup_map,
1968 const hb_map_t *klass_map = nullptr) const
1969 {
1970 TRACE_SUBSET (this);
Qunxin Liue88fc412021-11-18 16:53:36 -08001971 if (unlikely (!inputCount)) return_trace (false);
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06001972 const auto input = inputZ.as_array (inputCount - 1);
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001973
1974 const hb_map_t *mapping = klass_map == nullptr ? c->plan->glyph_map : klass_map;
1975 if (!hb_all (input, mapping)) return_trace (false);
1976 return_trace (serialize (c->serializer, mapping, lookup_map));
1977 }
1978
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001979 public:
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301980 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001981 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001982 TRACE_SANITIZE (this);
Behdad Esfahbod5aad8192017-11-03 17:16:26 -04001983 return_trace (inputCount.sanitize (c) &&
1984 lookupCount.sanitize (c) &&
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001985 c->check_range (inputZ.arrayZ,
Behdad Esfahbod9c6921c2018-11-30 15:16:57 -05001986 inputZ.item_size * (inputCount ? inputCount - 1 : 0) +
Behdad Esfahbod6d7c6e12018-02-07 14:09:56 -06001987 LookupRecord::static_size * lookupCount));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001988 }
1989
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001990 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001991 HBUINT16 inputCount; /* Total number of glyphs in input
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001992 * glyph sequence--includes the first
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001993 * glyph */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001994 HBUINT16 lookupCount; /* Number of LookupRecords */
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06001995 UnsizedArrayOf<typename Types::HBUINT>
Ebrahim Byagowice114d62019-12-31 15:53:02 +03301996 inputZ; /* Array of match inputs--start with
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001997 * second glyph */
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001998/*UnsizedArrayOf<LookupRecord>
1999 lookupRecordX;*/ /* Array of LookupRecords--in
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002000 * design order */
Behdad Esfahbod569da922010-05-10 16:38:32 -04002001 public:
Behdad Esfahbod6d7c6e12018-02-07 14:09:56 -06002002 DEFINE_SIZE_ARRAY (4, inputZ);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002003};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002004
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06002005template <typename Types>
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002006struct RuleSet
2007{
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06002008 using Rule = OT::Rule<Types>;
2009
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302010 bool intersects (const hb_set_t *glyphs,
2011 ContextClosureLookupContext &lookup_context) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002012 {
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07002013 return
2014 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002015 | hb_map (hb_add (this))
2016 | hb_map ([&] (const Rule &_) { return _.intersects (glyphs, lookup_context); })
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07002017 | hb_any
2018 ;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002019 }
2020
Qunxin Liub8a58a02021-01-10 15:50:04 -08002021 void closure (hb_closure_context_t *c, unsigned value,
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302022 ContextClosureLookupContext &lookup_context) const
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002023 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04302024 if (unlikely (c->lookup_limit_exceeded ())) return;
Garret Rieger014e0382020-03-31 16:29:29 -07002025
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07002026 return
2027 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002028 | hb_map (hb_add (this))
Qunxin Liub8a58a02021-01-10 15:50:04 -08002029 | hb_apply ([&] (const Rule &_) { _.closure (c, value, lookup_context); })
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07002030 ;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002031 }
2032
Garret Rieger9fad5402020-09-28 13:24:25 -07002033 void closure_lookups (hb_closure_lookups_context_t *c,
2034 ContextClosureLookupContext &lookup_context) const
Qunxin Liu0b39c482019-10-22 16:00:43 -07002035 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04302036 if (unlikely (c->lookup_limit_exceeded ())) return;
Qunxin Liu0b39c482019-10-22 16:00:43 -07002037 + hb_iter (rule)
2038 | hb_map (hb_add (this))
Garret Riegere31c2692020-09-28 16:51:25 -07002039 | hb_apply ([&] (const Rule &_) { _.closure_lookups (c, lookup_context); })
Qunxin Liu0b39c482019-10-22 16:00:43 -07002040 ;
2041 }
2042
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302043 void collect_glyphs (hb_collect_glyphs_context_t *c,
2044 ContextCollectGlyphsLookupContext &lookup_context) const
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05002045 {
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07002046 return
2047 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002048 | hb_map (hb_add (this))
2049 | hb_apply ([&] (const Rule &_) { _.collect_glyphs (c, lookup_context); })
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07002050 ;
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05002051 }
2052
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302053 bool would_apply (hb_would_apply_context_t *c,
Behdad Esfahbod19ec01d2022-11-16 19:14:42 -07002054 const ContextApplyLookupContext &lookup_context) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002055 {
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07002056 return
2057 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002058 | hb_map (hb_add (this))
2059 | hb_map ([&] (const Rule &_) { return _.would_apply (c, lookup_context); })
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07002060 | hb_any
2061 ;
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002062 }
2063
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302064 bool apply (hb_ot_apply_context_t *c,
Behdad Esfahbod19ec01d2022-11-16 19:14:42 -07002065 const ContextApplyLookupContext &lookup_context) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002066 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002067 TRACE_APPLY (this);
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07002068 return_trace (
2069 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002070 | hb_map (hb_add (this))
2071 | hb_map ([&] (const Rule &_) { return _.apply (c, lookup_context); })
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07002072 | hb_any
2073 )
2074 ;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002075 }
2076
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002077 bool subset (hb_subset_context_t *c,
2078 const hb_map_t *lookup_map,
2079 const hb_map_t *klass_map = nullptr) const
2080 {
2081 TRACE_SUBSET (this);
2082
2083 auto snap = c->serializer->snapshot ();
2084 auto *out = c->serializer->start_embed (*this);
2085 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
2086
Behdad Esfahbodad28f972021-03-31 12:49:14 -06002087 for (const Offset16To<Rule>& _ : rule)
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002088 {
2089 if (!_) continue;
Garret Riegerc2cc5662021-09-22 14:15:55 -07002090 auto o_snap = c->serializer->snapshot ();
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002091 auto *o = out->rule.serialize_append (c->serializer);
2092 if (unlikely (!o)) continue;
2093
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002094 if (!o->serialize_subset (c, _, this, lookup_map, klass_map))
2095 {
Ebrahim Byagowi5a7cc7f2020-07-29 08:33:32 +04302096 out->rule.pop ();
2097 c->serializer->revert (o_snap);
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002098 }
2099 }
2100
2101 bool ret = bool (out->rule);
2102 if (!ret) c->serializer->revert (snap);
2103
2104 return_trace (ret);
2105 }
2106
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302107 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002108 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002109 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002110 return_trace (rule.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002111 }
2112
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002113 protected:
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06002114 Array16OfOffset16To<Rule>
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04002115 rule; /* Array of Rule tables
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002116 * ordered by preference */
Behdad Esfahboded074222010-05-10 18:08:46 -04002117 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04002118 DEFINE_SIZE_ARRAY (2, rule);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002119};
2120
2121
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06002122template <typename Types>
2123struct ContextFormat1_4
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002124{
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06002125 using RuleSet = OT::RuleSet<Types>;
2126
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302127 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002128 {
2129 struct ContextClosureLookupContext lookup_context = {
Qunxin Liub8a58a02021-01-10 15:50:04 -08002130 {intersects_glyph, intersected_glyph},
2131 ContextFormat::SimpleContext,
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002132 nullptr
2133 };
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002134
2135 return
2136 + hb_zip (this+coverage, ruleSet)
2137 | hb_filter (*glyphs, hb_first)
2138 | hb_map (hb_second)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002139 | hb_map (hb_add (this))
2140 | hb_map ([&] (const RuleSet &_) { return _.intersects (glyphs, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002141 | hb_any
2142 ;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002143 }
2144
Qunxin Liub4fc5932020-12-09 10:44:18 -08002145 bool may_have_non_1to1 () const
2146 { return true; }
2147
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302148 void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002149 {
Behdad Esfahbod00dfbbc2022-07-21 11:39:32 -06002150 hb_set_t& cur_active_glyphs = c->push_cur_active_glyphs ();
2151 get_coverage ().intersect_set (c->previous_parent_active_glyphs (), cur_active_glyphs);
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08002152
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002153 struct ContextClosureLookupContext lookup_context = {
Qunxin Liub8a58a02021-01-10 15:50:04 -08002154 {intersects_glyph, intersected_glyph},
2155 ContextFormat::SimpleContext,
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02002156 nullptr
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002157 };
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002158
Qunxin Liub8a58a02021-01-10 15:50:04 -08002159 + hb_zip (this+coverage, hb_range ((unsigned) ruleSet.len))
Garret Rieger4e2f4092022-01-31 12:20:32 -08002160 | hb_filter ([&] (hb_codepoint_t _) {
2161 return c->previous_parent_active_glyphs ().has (_);
2162 }, hb_first)
Qunxin Liub8a58a02021-01-10 15:50:04 -08002163 | hb_map ([&](const hb_pair_t<hb_codepoint_t, unsigned> _) { return hb_pair_t<unsigned, const RuleSet&> (_.first, this+ruleSet[_.second]); })
2164 | hb_apply ([&] (const hb_pair_t<unsigned, const RuleSet&>& _) { _.second.closure (c, _.first, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002165 ;
Garret Riegerbc899652022-01-28 13:54:10 -08002166
2167 c->pop_cur_done_glyphs ();
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002168 }
2169
Qunxin Liu0b39c482019-10-22 16:00:43 -07002170 void closure_lookups (hb_closure_lookups_context_t *c) const
2171 {
Garret Rieger9fad5402020-09-28 13:24:25 -07002172 struct ContextClosureLookupContext lookup_context = {
Behdad Esfahbod2680be12022-12-03 11:53:14 -07002173 {intersects_glyph, nullptr},
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08002174 ContextFormat::SimpleContext,
Garret Rieger9fad5402020-09-28 13:24:25 -07002175 nullptr
2176 };
2177
2178 + hb_zip (this+coverage, ruleSet)
2179 | hb_filter (*c->glyphs, hb_first)
2180 | hb_map (hb_second)
Qunxin Liu0b39c482019-10-22 16:00:43 -07002181 | hb_map (hb_add (this))
Garret Riegere31c2692020-09-28 16:51:25 -07002182 | hb_apply ([&] (const RuleSet &_) { _.closure_lookups (c, lookup_context); })
Qunxin Liu0b39c482019-10-22 16:00:43 -07002183 ;
2184 }
2185
Qunxin Liu8200e482020-02-26 13:11:42 -08002186 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
2187
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302188 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002189 {
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07002190 (this+coverage).collect_coverage (c->input);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05002191
2192 struct ContextCollectGlyphsLookupContext lookup_context = {
2193 {collect_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02002194 nullptr
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05002195 };
2196
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002197 + hb_iter (ruleSet)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002198 | hb_map (hb_add (this))
2199 | hb_apply ([&] (const RuleSet &_) { _.collect_glyphs (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002200 ;
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002201 }
2202
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302203 bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002204 {
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05002205 const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002206 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002207 {match_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02002208 nullptr
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002209 };
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07002210 return rule_set.would_apply (c, lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002211 }
2212
Ebrahim Byagowie4120082018-12-17 21:31:01 +03302213 const Coverage &get_coverage () const { return this+coverage; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002214
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302215 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002216 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002217 TRACE_APPLY (this);
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05002218 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -04002219 if (likely (index == NOT_COVERED))
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002220 return_trace (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002221
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002222 const RuleSet &rule_set = this+ruleSet[index];
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002223 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002224 {match_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02002225 nullptr
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002226 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002227 return_trace (rule_set.apply (c, lookup_context));
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002228 }
2229
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302230 bool subset (hb_subset_context_t *c) const
Behdad Esfahbod339d3602018-09-03 17:33:34 -07002231 {
2232 TRACE_SUBSET (this);
Garret Riegere5835052020-09-29 11:05:08 -07002233 const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002234 const hb_map_t &glyph_map = *c->plan->glyph_map;
2235
2236 auto *out = c->serializer->start_embed (*this);
2237 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
2238 out->format = format;
2239
Behdad Esfahbod1a00ab62023-01-11 10:56:16 -07002240 const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? &c->plan->gsub_lookups : &c->plan->gpos_lookups;
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002241 hb_sorted_vector_t<hb_codepoint_t> new_coverage;
2242 + hb_zip (this+coverage, ruleSet)
2243 | hb_filter (glyphset, hb_first)
2244 | hb_filter (subset_offset_array (c, out->ruleSet, this, lookup_map), hb_second)
2245 | hb_map (hb_first)
2246 | hb_map (glyph_map)
2247 | hb_sink (new_coverage)
2248 ;
2249
Garret Rieger085aa652021-06-14 16:47:45 -07002250 out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002251 return_trace (bool (new_coverage));
Behdad Esfahbod339d3602018-09-03 17:33:34 -07002252 }
2253
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302254 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002255 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002256 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002257 return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002258 }
2259
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002260 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002261 HBUINT16 format; /* Format identifier--format = 1 */
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06002262 typename Types::template OffsetTo<Coverage>
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002263 coverage; /* Offset to Coverage table--from
2264 * beginning of table */
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06002265 Array16Of<typename Types::template OffsetTo<RuleSet>>
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002266 ruleSet; /* Array of RuleSet tables
2267 * ordered by Coverage Index */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04002268 public:
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06002269 DEFINE_SIZE_ARRAY (2 + 2 * Types::size, ruleSet);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002270};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002271
2272
Behdad Esfahboda90c5af2022-07-08 13:11:47 -06002273template <typename Types>
2274struct ContextFormat2_5
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002275{
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06002276 using RuleSet = OT::RuleSet<SmallTypes>;
2277
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302278 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002279 {
2280 if (!(this+coverage).intersects (glyphs))
2281 return false;
2282
2283 const ClassDef &class_def = this+classDef;
2284
Behdad Esfahbodac8b2322022-11-30 16:42:15 -07002285 hb_map_t cache;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002286 struct ContextClosureLookupContext lookup_context = {
Behdad Esfahbod2680be12022-12-03 11:53:14 -07002287 {intersects_class, nullptr},
Qunxin Liub8a58a02021-01-10 15:50:04 -08002288 ContextFormat::ClassBasedContext,
Behdad Esfahbodac8b2322022-11-30 16:42:15 -07002289 &class_def,
2290 &cache
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002291 };
2292
Qunxin Liu540f19b2021-10-29 17:11:53 -07002293 hb_set_t retained_coverage_glyphs;
Behdad Esfahbod00dfbbc2022-07-21 11:39:32 -06002294 (this+coverage).intersect_set (*glyphs, retained_coverage_glyphs);
Qunxin Liu540f19b2021-10-29 17:11:53 -07002295
2296 hb_set_t coverage_glyph_classes;
2297 class_def.intersected_classes (&retained_coverage_glyphs, &coverage_glyph_classes);
2298
2299
Behdad Esfahbod668d2d52019-03-29 22:48:38 -07002300 return
Behdad Esfahbod26111a12020-06-28 02:59:47 -07002301 + hb_iter (ruleSet)
2302 | hb_map (hb_add (this))
2303 | hb_enumerate
2304 | hb_map ([&] (const hb_pair_t<unsigned, const RuleSet &> p)
Behdad Esfahbode5306922019-03-29 23:31:07 -07002305 { return class_def.intersects_class (glyphs, p.first) &&
Qunxin Liu540f19b2021-10-29 17:11:53 -07002306 coverage_glyph_classes.has (p.first) &&
Behdad Esfahbod26111a12020-06-28 02:59:47 -07002307 p.second.intersects (glyphs, lookup_context); })
Behdad Esfahbod668d2d52019-03-29 22:48:38 -07002308 | hb_any
2309 ;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002310 }
2311
Qunxin Liub4fc5932020-12-09 10:44:18 -08002312 bool may_have_non_1to1 () const
2313 { return true; }
2314
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302315 void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002316 {
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002317 if (!(this+coverage).intersects (c->glyphs))
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002318 return;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002319
Behdad Esfahbod00dfbbc2022-07-21 11:39:32 -06002320 hb_set_t& cur_active_glyphs = c->push_cur_active_glyphs ();
2321 get_coverage ().intersect_set (c->previous_parent_active_glyphs (),
Garret Rieger4e2f4092022-01-31 12:20:32 -08002322 cur_active_glyphs);
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08002323
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002324 const ClassDef &class_def = this+classDef;
2325
Behdad Esfahbodac8b2322022-11-30 16:42:15 -07002326 hb_map_t cache;
Behdad Esfahbod630b8742022-12-03 12:13:15 -07002327 intersected_class_cache_t intersected_cache;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002328 struct ContextClosureLookupContext lookup_context = {
Qunxin Liub8a58a02021-01-10 15:50:04 -08002329 {intersects_class, intersected_class_glyphs},
2330 ContextFormat::ClassBasedContext,
Behdad Esfahbodac8b2322022-11-30 16:42:15 -07002331 &class_def,
Behdad Esfahbod630b8742022-12-03 12:13:15 -07002332 &cache,
2333 &intersected_cache
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002334 };
2335
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07002336 + hb_enumerate (ruleSet)
Behdad Esfahbod78d35f02019-05-15 18:15:05 -07002337 | hb_filter ([&] (unsigned _)
Garret Riegerbc899652022-01-28 13:54:10 -08002338 { return class_def.intersects_class (&c->parent_active_glyphs (), _); },
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07002339 hb_first)
Behdad Esfahboda90c5af2022-07-08 13:11:47 -06002340 | hb_apply ([&] (const hb_pair_t<unsigned, const typename Types::template OffsetTo<RuleSet>&> _)
Qunxin Liub8a58a02021-01-10 15:50:04 -08002341 {
2342 const RuleSet& rule_set = this+_.second;
2343 rule_set.closure (c, _.first, lookup_context);
2344 })
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07002345 ;
Garret Riegerbc899652022-01-28 13:54:10 -08002346
2347 c->pop_cur_done_glyphs ();
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002348 }
2349
Qunxin Liu0b39c482019-10-22 16:00:43 -07002350 void closure_lookups (hb_closure_lookups_context_t *c) const
2351 {
Garret Rieger9fad5402020-09-28 13:24:25 -07002352 if (!(this+coverage).intersects (c->glyphs))
2353 return;
2354
2355 const ClassDef &class_def = this+classDef;
2356
Behdad Esfahbodac8b2322022-11-30 16:42:15 -07002357 hb_map_t cache;
Garret Rieger9fad5402020-09-28 13:24:25 -07002358 struct ContextClosureLookupContext lookup_context = {
Behdad Esfahbod2680be12022-12-03 11:53:14 -07002359 {intersects_class, nullptr},
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08002360 ContextFormat::ClassBasedContext,
Behdad Esfahbodac8b2322022-11-30 16:42:15 -07002361 &class_def,
2362 &cache
Garret Rieger9fad5402020-09-28 13:24:25 -07002363 };
2364
Qunxin Liu0b39c482019-10-22 16:00:43 -07002365 + hb_iter (ruleSet)
2366 | hb_map (hb_add (this))
Garret Rieger9fad5402020-09-28 13:24:25 -07002367 | hb_enumerate
2368 | hb_filter ([&] (const hb_pair_t<unsigned, const RuleSet &> p)
2369 { return class_def.intersects_class (c->glyphs, p.first); })
2370 | hb_map (hb_second)
2371 | hb_apply ([&] (const RuleSet & _)
2372 { _.closure_lookups (c, lookup_context); });
Qunxin Liu0b39c482019-10-22 16:00:43 -07002373 }
2374
Qunxin Liu8200e482020-02-26 13:11:42 -08002375 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
2376
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302377 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002378 {
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07002379 (this+coverage).collect_coverage (c->input);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05002380
Behdad Esfahbod11fba792013-01-02 23:36:37 -06002381 const ClassDef &class_def = this+classDef;
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05002382 struct ContextCollectGlyphsLookupContext lookup_context = {
2383 {collect_class},
Behdad Esfahbod11fba792013-01-02 23:36:37 -06002384 &class_def
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05002385 };
2386
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002387 + hb_iter (ruleSet)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002388 | hb_map (hb_add (this))
2389 | hb_apply ([&] (const RuleSet &_) { _.collect_glyphs (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002390 ;
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002391 }
2392
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302393 bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002394 {
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002395 const ClassDef &class_def = this+classDef;
Behdad Esfahbod2dc11412012-11-24 19:16:34 -05002396 unsigned int index = class_def.get_class (c->glyphs[0]);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002397 const RuleSet &rule_set = this+ruleSet[index];
2398 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002399 {match_class},
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002400 &class_def
2401 };
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07002402 return rule_set.would_apply (c, lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002403 }
2404
Ebrahim Byagowie4120082018-12-17 21:31:01 +03302405 const Coverage &get_coverage () const { return this+coverage; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002406
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06002407 unsigned cache_cost () const
2408 {
2409 unsigned c = (this+classDef).cost () * ruleSet.len;
2410 return c >= 4 ? c : 0;
2411 }
Behdad Esfahbod5963cf42022-06-07 09:12:45 -06002412 bool cache_func (hb_ot_apply_context_t *c, bool enter) const
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06002413 {
Behdad Esfahbod5963cf42022-06-07 09:12:45 -06002414 if (enter)
2415 {
2416 if (!HB_BUFFER_TRY_ALLOCATE_VAR (c->buffer, syllable))
2417 return false;
2418 auto &info = c->buffer->info;
2419 unsigned count = c->buffer->len;
2420 for (unsigned i = 0; i < count; i++)
2421 info[i].syllable() = 255;
2422 c->new_syllables = 255;
2423 return true;
2424 }
2425 else
2426 {
2427 c->new_syllables = (unsigned) -1;
2428 HB_BUFFER_DEALLOCATE_VAR (c->buffer, syllable);
2429 return true;
2430 }
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06002431 }
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06002432
2433 bool apply (hb_ot_apply_context_t *c, bool cached = false) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002434 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002435 TRACE_APPLY (this);
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05002436 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002437 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002438
2439 const ClassDef &class_def = this+classDef;
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06002440
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002441 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06002442 {cached ? match_class_cached : match_class},
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04002443 &class_def
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002444 };
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06002445
2446 if (cached && c->buffer->cur().syllable() < 255)
2447 index = c->buffer->cur().syllable ();
2448 else
2449 {
2450 index = class_def.get_class (c->buffer->cur().codepoint);
2451 if (cached && index < 255)
2452 c->buffer->cur().syllable() = index;
2453 }
2454 const RuleSet &rule_set = this+ruleSet[index];
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002455 return_trace (rule_set.apply (c, lookup_context));
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002456 }
2457
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302458 bool subset (hb_subset_context_t *c) const
Behdad Esfahbod339d3602018-09-03 17:33:34 -07002459 {
2460 TRACE_SUBSET (this);
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002461 auto *out = c->serializer->start_embed (*this);
2462 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
2463 out->format = format;
2464 if (unlikely (!out->coverage.serialize_subset (c, coverage, this)))
2465 return_trace (false);
2466
2467 hb_map_t klass_map;
2468 out->classDef.serialize_subset (c, classDef, this, &klass_map);
2469
Qunxin Liu540f19b2021-10-29 17:11:53 -07002470 const hb_set_t* glyphset = c->plan->glyphset_gsub ();
2471 hb_set_t retained_coverage_glyphs;
Behdad Esfahbod00dfbbc2022-07-21 11:39:32 -06002472 (this+coverage).intersect_set (*glyphset, retained_coverage_glyphs);
Garret Riegerf51b48c2021-11-02 16:16:52 -07002473
Qunxin Liu540f19b2021-10-29 17:11:53 -07002474 hb_set_t coverage_glyph_classes;
2475 (this+classDef).intersected_classes (&retained_coverage_glyphs, &coverage_glyph_classes);
2476
Behdad Esfahbod1a00ab62023-01-11 10:56:16 -07002477 const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? &c->plan->gsub_lookups : &c->plan->gpos_lookups;
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002478 bool ret = true;
Qunxin Liu540f19b2021-10-29 17:11:53 -07002479 int non_zero_index = -1, index = 0;
Garret Riegerff3cac02022-11-23 23:50:49 +00002480 auto snapshot = c->serializer->snapshot();
Behdad Esfahbod6d941942021-02-19 17:08:10 -07002481 for (const auto& _ : + hb_enumerate (ruleSet)
2482 | hb_filter (klass_map, hb_first))
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002483 {
2484 auto *o = out->ruleSet.serialize_append (c->serializer);
2485 if (unlikely (!o))
2486 {
Ebrahim Byagowi5a7cc7f2020-07-29 08:33:32 +04302487 ret = false;
2488 break;
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002489 }
2490
Qunxin Liu540f19b2021-10-29 17:11:53 -07002491 if (coverage_glyph_classes.has (_.first) &&
Garret Riegerff3cac02022-11-23 23:50:49 +00002492 o->serialize_subset (c, _.second, this, lookup_map, &klass_map)) {
Ebrahim Byagowi5a7cc7f2020-07-29 08:33:32 +04302493 non_zero_index = index;
Garret Riegerff3cac02022-11-23 23:50:49 +00002494 snapshot = c->serializer->snapshot();
2495 }
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002496
2497 index++;
2498 }
2499
Qunxin Liu540f19b2021-10-29 17:11:53 -07002500 if (!ret || non_zero_index == -1) return_trace (false);
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002501
2502 //prune empty trailing ruleSets
2503 --index;
2504 while (index > non_zero_index)
2505 {
2506 out->ruleSet.pop ();
2507 index--;
2508 }
Garret Riegerff3cac02022-11-23 23:50:49 +00002509 c->serializer->revert (snapshot);
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002510
2511 return_trace (bool (out->ruleSet));
Behdad Esfahbod339d3602018-09-03 17:33:34 -07002512 }
2513
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302514 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002515 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002516 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002517 return_trace (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002518 }
2519
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002520 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002521 HBUINT16 format; /* Format identifier--format = 2 */
Behdad Esfahboda90c5af2022-07-08 13:11:47 -06002522 typename Types::template OffsetTo<Coverage>
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002523 coverage; /* Offset to Coverage table--from
2524 * beginning of table */
Behdad Esfahboda90c5af2022-07-08 13:11:47 -06002525 typename Types::template OffsetTo<ClassDef>
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002526 classDef; /* Offset to glyph ClassDef table--from
2527 * beginning of table */
Behdad Esfahboda90c5af2022-07-08 13:11:47 -06002528 Array16Of<typename Types::template OffsetTo<RuleSet>>
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002529 ruleSet; /* Array of RuleSet tables
2530 * ordered by class */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04002531 public:
Behdad Esfahboda90c5af2022-07-08 13:11:47 -06002532 DEFINE_SIZE_ARRAY (4 + 2 * Types::size, ruleSet);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002533};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002534
2535
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002536struct ContextFormat3
2537{
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06002538 using RuleSet = OT::RuleSet<SmallTypes>;
2539
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302540 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002541 {
Behdad Esfahbodfb059082018-11-30 20:45:40 -05002542 if (!(this+coverageZ[0]).intersects (glyphs))
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002543 return false;
2544
2545 struct ContextClosureLookupContext lookup_context = {
Behdad Esfahbod2680be12022-12-03 11:53:14 -07002546 {intersects_coverage, nullptr},
Qunxin Liub8a58a02021-01-10 15:50:04 -08002547 ContextFormat::CoverageBasedContext,
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002548 this
2549 };
2550 return context_intersects (glyphs,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02002551 glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002552 lookup_context);
2553 }
2554
Qunxin Liub4fc5932020-12-09 10:44:18 -08002555 bool may_have_non_1to1 () const
2556 { return true; }
2557
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302558 void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002559 {
Behdad Esfahbodfb059082018-11-30 20:45:40 -05002560 if (!(this+coverageZ[0]).intersects (c->glyphs))
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002561 return;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002562
Behdad Esfahbod00dfbbc2022-07-21 11:39:32 -06002563 hb_set_t& cur_active_glyphs = c->push_cur_active_glyphs ();
2564 get_coverage ().intersect_set (c->previous_parent_active_glyphs (),
Garret Rieger4e2f4092022-01-31 12:20:32 -08002565 cur_active_glyphs);
2566
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08002567
Behdad Esfahbod0382b712018-11-02 12:23:26 -04002568 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002569 struct ContextClosureLookupContext lookup_context = {
Qunxin Liub8a58a02021-01-10 15:50:04 -08002570 {intersects_coverage, intersected_coverage_glyphs},
2571 ContextFormat::CoverageBasedContext,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002572 this
2573 };
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002574 context_closure_lookup (c,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02002575 glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002576 lookupCount, lookupRecord,
Qunxin Liub8a58a02021-01-10 15:50:04 -08002577 0, lookup_context);
Garret Riegerbc899652022-01-28 13:54:10 -08002578
2579 c->pop_cur_done_glyphs ();
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002580 }
2581
Qunxin Liu0b39c482019-10-22 16:00:43 -07002582 void closure_lookups (hb_closure_lookups_context_t *c) const
2583 {
Garret Riegera5c0ec72020-09-25 14:57:20 -07002584 if (!intersects (c->glyphs))
2585 return;
Qunxin Liu0b39c482019-10-22 16:00:43 -07002586 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
2587 recurse_lookups (c, lookupCount, lookupRecord);
2588 }
2589
Qunxin Liu8200e482020-02-26 13:11:42 -08002590 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
2591
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302592 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002593 {
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07002594 (this+coverageZ[0]).collect_coverage (c->input);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05002595
Behdad Esfahbod0382b712018-11-02 12:23:26 -04002596 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05002597 struct ContextCollectGlyphsLookupContext lookup_context = {
2598 {collect_coverage},
Behdad Esfahbode75943d2012-11-30 08:38:24 +02002599 this
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05002600 };
2601
2602 context_collect_glyphs_lookup (c,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02002603 glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05002604 lookupCount, lookupRecord,
2605 lookup_context);
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002606 }
2607
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302608 bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002609 {
Behdad Esfahbod0382b712018-11-02 12:23:26 -04002610 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002611 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002612 {match_coverage},
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002613 this
2614 };
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07002615 return context_would_apply_lookup (c,
2616 glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
2617 lookupCount, lookupRecord,
2618 lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002619 }
2620
Ebrahim Byagowie4120082018-12-17 21:31:01 +03302621 const Coverage &get_coverage () const { return this+coverageZ[0]; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002622
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302623 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002624 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002625 TRACE_APPLY (this);
Behdad Esfahbodfb059082018-11-30 20:45:40 -05002626 unsigned int index = (this+coverageZ[0]).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002627 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04002628
Behdad Esfahbod0382b712018-11-02 12:23:26 -04002629 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002630 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002631 {match_coverage},
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04002632 this
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002633 };
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02002634 return_trace (context_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, lookup_context));
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002635 }
2636
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302637 bool subset (hb_subset_context_t *c) const
Behdad Esfahbod339d3602018-09-03 17:33:34 -07002638 {
2639 TRACE_SUBSET (this);
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002640 auto *out = c->serializer->start_embed (this);
2641 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
2642
2643 out->format = format;
2644 out->glyphCount = glyphCount;
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002645
Behdad Esfahbod26111a12020-06-28 02:59:47 -07002646 auto coverages = coverageZ.as_array (glyphCount);
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002647
Behdad Esfahbodad28f972021-03-31 12:49:14 -06002648 for (const Offset16To<Coverage>& offset : coverages)
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002649 {
Behdad Esfahbod6d941942021-02-19 17:08:10 -07002650 /* TODO(subset) This looks like should not be necessary to write this way. */
Behdad Esfahbod9b4b5842021-03-31 13:27:21 -06002651 auto *o = c->serializer->allocate_size<Offset16To<Coverage>> (Offset16To<Coverage>::static_size);
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002652 if (unlikely (!o)) return_trace (false);
2653 if (!o->serialize_subset (c, offset, this)) return_trace (false);
2654 }
2655
Behdad Esfahbod51922942022-07-08 14:00:24 -06002656 const auto& lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>> (coverageZ.as_array (glyphCount));
Behdad Esfahbod1a00ab62023-01-11 10:56:16 -07002657 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 -07002658
Ebrahim Byagowia79d0e42020-05-21 07:32:58 +04302659
Qunxin Liu36ed56b2021-09-23 10:51:21 -07002660 unsigned count = serialize_lookuprecord_array (c->serializer, lookupRecord.as_array (lookupCount), lookup_map);
2661 return_trace (c->serializer->check_assign (out->lookupCount, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
Behdad Esfahbod339d3602018-09-03 17:33:34 -07002662 }
2663
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302664 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002665 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002666 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002667 if (!c->check_struct (this)) return_trace (false);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002668 unsigned int count = glyphCount;
Behdad Esfahbodfb059082018-11-30 20:45:40 -05002669 if (!count) return_trace (false); /* We want to access coverageZ[0] freely. */
Behdad Esfahbod9507b052018-09-10 23:18:07 +02002670 if (!c->check_array (coverageZ.arrayZ, count)) return_trace (false);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002671 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002672 if (!coverageZ[i].sanitize (c, this)) return_trace (false);
Behdad Esfahbod0382b712018-11-02 12:23:26 -04002673 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
Behdad Esfahbod9507b052018-09-10 23:18:07 +02002674 return_trace (c->check_array (lookupRecord, lookupCount));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002675 }
2676
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002677 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002678 HBUINT16 format; /* Format identifier--format = 3 */
2679 HBUINT16 glyphCount; /* Number of glyphs in the input glyph
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002680 * sequence */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002681 HBUINT16 lookupCount; /* Number of LookupRecords */
Behdad Esfahbodad28f972021-03-31 12:49:14 -06002682 UnsizedArrayOf<Offset16To<Coverage>>
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02002683 coverageZ; /* Array of offsets to Coverage
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002684 * table in glyph sequence order */
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02002685/*UnsizedArrayOf<LookupRecord>
2686 lookupRecordX;*/ /* Array of LookupRecords--in
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002687 * design order */
Behdad Esfahbod569da922010-05-10 16:38:32 -04002688 public:
Behdad Esfahbod6d7c6e12018-02-07 14:09:56 -06002689 DEFINE_SIZE_ARRAY (6, coverageZ);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002690};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002691
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002692struct Context
2693{
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -07002694 template <typename context_t, typename ...Ts>
Behdad Esfahbod83e3eab2019-05-07 20:58:43 -07002695 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002696 {
Behdad Esfahbodbe8a87c2023-01-21 15:00:41 -07002697 if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
Behdad Esfahbod00f6a8e2014-12-12 20:36:49 -08002698 TRACE_DISPATCH (this, u.format);
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002699 switch (u.format) {
Behdad Esfahbod6d555ce2021-11-02 00:18:22 -06002700 case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
2701 case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
2702 case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
Behdad Esfahbod5a9c7932022-07-22 21:33:15 -06002703#ifndef HB_NO_BEYOND_64K
Behdad Esfahbod1bf8fa22022-07-08 14:22:21 -06002704 case 4: return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...));
Behdad Esfahbodd1f58e52022-07-08 13:25:07 -06002705 case 5: return_trace (c->dispatch (u.format5, std::forward<Ts> (ds)...));
2706#endif
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002707 default:return_trace (c->default_return_value ());
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002708 }
2709 }
2710
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002711 protected:
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002712 union {
Behdad Esfahboda90c5af2022-07-08 13:11:47 -06002713 HBUINT16 format; /* Format identifier */
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06002714 ContextFormat1_4<SmallTypes> format1;
Behdad Esfahboda90c5af2022-07-08 13:11:47 -06002715 ContextFormat2_5<SmallTypes> format2;
2716 ContextFormat3 format3;
Behdad Esfahbod5a9c7932022-07-22 21:33:15 -06002717#ifndef HB_NO_BEYOND_64K
Behdad Esfahbod1bf8fa22022-07-08 14:22:21 -06002718 ContextFormat1_4<MediumTypes> format4;
Behdad Esfahbodd1f58e52022-07-08 13:25:07 -06002719 ContextFormat2_5<MediumTypes> format5;
2720#endif
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002721 } u;
2722};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002723
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002724
2725/* Chaining Contextual lookups */
2726
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002727struct ChainContextClosureLookupContext
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002728{
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002729 ContextClosureFuncs funcs;
Qunxin Liub8a58a02021-01-10 15:50:04 -08002730 ContextFormat context_format;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002731 const void *intersects_data[3];
Behdad Esfahbod630b8742022-12-03 12:13:15 -07002732 void *intersects_cache[3];
2733 void *intersected_glyphs_cache;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002734};
2735
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002736struct ChainContextCollectGlyphsLookupContext
2737{
2738 ContextCollectGlyphsFuncs funcs;
2739 const void *collect_data[3];
2740};
2741
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002742struct ChainContextApplyLookupContext
2743{
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06002744 ChainContextApplyFuncs funcs;
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04002745 const void *match_data[3];
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04002746};
2747
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06002748template <typename HBUINT>
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002749static inline bool chain_context_intersects (const hb_set_t *glyphs,
2750 unsigned int backtrackCount,
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06002751 const HBUINT backtrack[],
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002752 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06002753 const HBUINT input[], /* Array of input values--start with second glyph */
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002754 unsigned int lookaheadCount,
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06002755 const HBUINT lookahead[],
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002756 ChainContextClosureLookupContext &lookup_context)
2757{
Qunxin Liu44d88cf2020-05-08 15:33:34 -07002758 return array_is_subset_of (glyphs,
2759 backtrackCount, backtrack,
Behdad Esfahbod630b8742022-12-03 12:13:15 -07002760 lookup_context.funcs.intersects,
2761 lookup_context.intersects_data[0],
2762 lookup_context.intersects_cache[0])
Qunxin Liu44d88cf2020-05-08 15:33:34 -07002763 && array_is_subset_of (glyphs,
2764 inputCount ? inputCount - 1 : 0, input,
Behdad Esfahbod630b8742022-12-03 12:13:15 -07002765 lookup_context.funcs.intersects,
2766 lookup_context.intersects_data[1],
2767 lookup_context.intersects_cache[1])
Qunxin Liu44d88cf2020-05-08 15:33:34 -07002768 && array_is_subset_of (glyphs,
2769 lookaheadCount, lookahead,
Behdad Esfahbod630b8742022-12-03 12:13:15 -07002770 lookup_context.funcs.intersects,
2771 lookup_context.intersects_data[2],
2772 lookup_context.intersects_cache[2]);
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002773}
2774
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06002775template <typename HBUINT>
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002776static inline void chain_context_closure_lookup (hb_closure_context_t *c,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002777 unsigned int backtrackCount,
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06002778 const HBUINT backtrack[],
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002779 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06002780 const HBUINT input[], /* Array of input values--start with second glyph */
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002781 unsigned int lookaheadCount,
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06002782 const HBUINT lookahead[],
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002783 unsigned int lookupCount,
2784 const LookupRecord lookupRecord[],
Qunxin Liub8a58a02021-01-10 15:50:04 -08002785 unsigned value,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002786 ChainContextClosureLookupContext &lookup_context)
2787{
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002788 if (chain_context_intersects (c->glyphs,
2789 backtrackCount, backtrack,
2790 inputCount, input,
2791 lookaheadCount, lookahead,
2792 lookup_context))
Qunxin Liub8a58a02021-01-10 15:50:04 -08002793 context_closure_recurse_lookups (c,
2794 inputCount, input,
2795 lookupCount, lookupRecord,
2796 value,
2797 lookup_context.context_format,
2798 lookup_context.intersects_data[1],
Behdad Esfahbod630b8742022-12-03 12:13:15 -07002799 lookup_context.funcs.intersected_glyphs,
2800 lookup_context.intersected_glyphs_cache);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002801}
2802
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06002803template <typename HBUINT>
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002804static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03302805 unsigned int backtrackCount,
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06002806 const HBUINT backtrack[],
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03302807 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06002808 const HBUINT input[], /* Array of input values--start with second glyph */
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03302809 unsigned int lookaheadCount,
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06002810 const HBUINT lookahead[],
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03302811 unsigned int lookupCount,
2812 const LookupRecord lookupRecord[],
2813 ChainContextCollectGlyphsLookupContext &lookup_context)
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002814{
Behdad Esfahbod83035932012-12-04 17:08:41 -05002815 collect_array (c, c->before,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002816 backtrackCount, backtrack,
2817 lookup_context.funcs.collect, lookup_context.collect_data[0]);
Behdad Esfahbod83035932012-12-04 17:08:41 -05002818 collect_array (c, c->input,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002819 inputCount ? inputCount - 1 : 0, input,
2820 lookup_context.funcs.collect, lookup_context.collect_data[1]);
Behdad Esfahbod83035932012-12-04 17:08:41 -05002821 collect_array (c, c->after,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002822 lookaheadCount, lookahead,
2823 lookup_context.funcs.collect, lookup_context.collect_data[2]);
2824 recurse_lookups (c,
2825 lookupCount, lookupRecord);
2826}
2827
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06002828template <typename HBUINT>
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002829static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c,
2830 unsigned int backtrackCount,
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06002831 const HBUINT backtrack[] HB_UNUSED,
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002832 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06002833 const HBUINT input[], /* Array of input values--start with second glyph */
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002834 unsigned int lookaheadCount,
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06002835 const HBUINT lookahead[] HB_UNUSED,
Behdad Esfahbod0beb66e2012-12-05 18:46:04 -05002836 unsigned int lookupCount HB_UNUSED,
2837 const LookupRecord lookupRecord[] HB_UNUSED,
Behdad Esfahbod19ec01d2022-11-16 19:14:42 -07002838 const ChainContextApplyLookupContext &lookup_context)
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002839{
Behdad Esfahbodd9b204d2012-08-23 16:22:28 -04002840 return (c->zero_context ? !backtrackCount && !lookaheadCount : true)
Behdad Esfahbod1f2bb172012-08-23 16:10:37 -04002841 && would_match_input (c,
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002842 inputCount, input,
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06002843 lookup_context.funcs.match[1], lookup_context.match_data[1]);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002844}
2845
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06002846template <typename HBUINT>
Behdad Esfahbodfd034492018-01-17 16:46:51 -08002847static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002848 unsigned int backtrackCount,
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06002849 const HBUINT backtrack[],
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002850 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06002851 const HBUINT input[], /* Array of input values--start with second glyph */
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002852 unsigned int lookaheadCount,
Behdad Esfahbod9d0e9fa2022-07-06 17:49:07 -06002853 const HBUINT lookahead[],
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002854 unsigned int lookupCount,
2855 const LookupRecord lookupRecord[],
Behdad Esfahbod19ec01d2022-11-16 19:14:42 -07002856 const ChainContextApplyLookupContext &lookup_context)
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04002857{
Behdad Esfahbod60006d32022-01-20 15:29:28 -07002858 unsigned end_index = c->buffer->idx;
Behdad Esfahbod78481b32021-11-21 16:50:34 -07002859 unsigned match_end = 0;
2860 unsigned match_positions[HB_MAX_CONTEXT_LENGTH];
Behdad Esfahbod60006d32022-01-20 15:29:28 -07002861 if (!(match_input (c,
2862 inputCount, input,
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06002863 lookup_context.funcs.match[1], lookup_context.match_data[1],
Behdad Esfahbod60006d32022-01-20 15:29:28 -07002864 &match_end, match_positions) && (end_index = match_end)
2865 && match_lookahead (c,
2866 lookaheadCount, lookahead,
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06002867 lookup_context.funcs.match[2], lookup_context.match_data[2],
Behdad Esfahbod60006d32022-01-20 15:29:28 -07002868 match_end, &end_index)))
Behdad Esfahbod78481b32021-11-21 16:50:34 -07002869 {
Behdad Esfahbod60006d32022-01-20 15:29:28 -07002870 c->buffer->unsafe_to_concat (c->buffer->idx, end_index);
2871 return false;
Behdad Esfahbod78481b32021-11-21 16:50:34 -07002872 }
Behdad Esfahbod60006d32022-01-20 15:29:28 -07002873
2874 unsigned start_index = c->buffer->out_len;
2875 if (!match_backtrack (c,
2876 backtrackCount, backtrack,
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06002877 lookup_context.funcs.match[0], lookup_context.match_data[0],
Behdad Esfahbod60006d32022-01-20 15:29:28 -07002878 &start_index))
Behdad Esfahbod78481b32021-11-21 16:50:34 -07002879 {
2880 c->buffer->unsafe_to_concat_from_outbuffer (start_index, end_index);
2881 return false;
2882 }
Behdad Esfahbod60006d32022-01-20 15:29:28 -07002883
2884 c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index);
2885 apply_lookup (c,
2886 inputCount, match_positions,
2887 lookupCount, lookupRecord,
2888 match_end);
2889 return true;
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04002890}
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04002891
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06002892template <typename Types>
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002893struct ChainRule
2894{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302895 bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002896 {
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06002897 const auto &input = StructAfter<decltype (inputX)> (backtrack);
2898 const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002899 return chain_context_intersects (glyphs,
2900 backtrack.len, backtrack.arrayZ,
Behdad Esfahbodeffc7ce2018-09-13 20:21:54 +02002901 input.lenP1, input.arrayZ,
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002902 lookahead.len, lookahead.arrayZ,
2903 lookup_context);
2904 }
2905
Qunxin Liub8a58a02021-01-10 15:50:04 -08002906 void closure (hb_closure_context_t *c, unsigned value,
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302907 ChainContextClosureLookupContext &lookup_context) const
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002908 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04302909 if (unlikely (c->lookup_limit_exceeded ())) return;
Garret Rieger4ad686b2020-03-25 23:32:28 -07002910
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06002911 const auto &input = StructAfter<decltype (inputX)> (backtrack);
2912 const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
2913 const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002914 chain_context_closure_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002915 backtrack.len, backtrack.arrayZ,
Behdad Esfahbodeffc7ce2018-09-13 20:21:54 +02002916 input.lenP1, input.arrayZ,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002917 lookahead.len, lookahead.arrayZ,
2918 lookup.len, lookup.arrayZ,
Qunxin Liub8a58a02021-01-10 15:50:04 -08002919 value,
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002920 lookup_context);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002921 }
2922
Garret Riegerad241f92020-09-28 15:26:13 -07002923 void closure_lookups (hb_closure_lookups_context_t *c,
2924 ChainContextClosureLookupContext &lookup_context) const
Qunxin Liu0b39c482019-10-22 16:00:43 -07002925 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04302926 if (unlikely (c->lookup_limit_exceeded ())) return;
Garret Riegerad241f92020-09-28 15:26:13 -07002927 if (!intersects (c->glyphs, lookup_context)) return;
Garret Rieger4ad686b2020-03-25 23:32:28 -07002928
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06002929 const auto &input = StructAfter<decltype (inputX)> (backtrack);
2930 const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
2931 const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
Qunxin Liu0b39c482019-10-22 16:00:43 -07002932 recurse_lookups (c, lookup.len, lookup.arrayZ);
2933 }
2934
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302935 void collect_glyphs (hb_collect_glyphs_context_t *c,
2936 ChainContextCollectGlyphsLookupContext &lookup_context) const
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002937 {
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06002938 const auto &input = StructAfter<decltype (inputX)> (backtrack);
2939 const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
2940 const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002941 chain_context_collect_glyphs_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002942 backtrack.len, backtrack.arrayZ,
Behdad Esfahbodeffc7ce2018-09-13 20:21:54 +02002943 input.lenP1, input.arrayZ,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002944 lookahead.len, lookahead.arrayZ,
2945 lookup.len, lookup.arrayZ,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002946 lookup_context);
2947 }
2948
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302949 bool would_apply (hb_would_apply_context_t *c,
Behdad Esfahbod19ec01d2022-11-16 19:14:42 -07002950 const ChainContextApplyLookupContext &lookup_context) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002951 {
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06002952 const auto &input = StructAfter<decltype (inputX)> (backtrack);
2953 const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
2954 const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07002955 return chain_context_would_apply_lookup (c,
2956 backtrack.len, backtrack.arrayZ,
2957 input.lenP1, input.arrayZ,
2958 lookahead.len, lookahead.arrayZ, lookup.len,
2959 lookup.arrayZ, lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002960 }
2961
Behdad Esfahbod19ec01d2022-11-16 19:14:42 -07002962 bool apply (hb_ot_apply_context_t *c,
2963 const ChainContextApplyLookupContext &lookup_context) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002964 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002965 TRACE_APPLY (this);
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06002966 const auto &input = StructAfter<decltype (inputX)> (backtrack);
2967 const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
2968 const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002969 return_trace (chain_context_apply_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002970 backtrack.len, backtrack.arrayZ,
Behdad Esfahbodeffc7ce2018-09-13 20:21:54 +02002971 input.lenP1, input.arrayZ,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002972 lookahead.len, lookahead.arrayZ, lookup.len,
2973 lookup.arrayZ, lookup_context));
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002974 }
2975
Qunxin Liub66094a2019-09-30 16:19:18 -07002976 template<typename Iterator,
2977 hb_requires (hb_is_iterator (Iterator))>
2978 void serialize_array (hb_serialize_context_t *c,
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04302979 HBUINT16 len,
2980 Iterator it) const
Qunxin Liub66094a2019-09-30 16:19:18 -07002981 {
2982 c->copy (len);
2983 for (const auto g : it)
Behdad Esfahbod83b66bf2021-02-23 13:04:25 -07002984 c->copy ((HBUINT16) g);
Qunxin Liub66094a2019-09-30 16:19:18 -07002985 }
2986
Qunxin Liu36ed56b2021-09-23 10:51:21 -07002987 bool serialize (hb_serialize_context_t *c,
2988 const hb_map_t *lookup_map,
2989 const hb_map_t *backtrack_map,
2990 const hb_map_t *input_map = nullptr,
2991 const hb_map_t *lookahead_map = nullptr) const
Qunxin Liub66094a2019-09-30 16:19:18 -07002992 {
2993 TRACE_SERIALIZE (this);
2994 auto *out = c->start_embed (this);
Qunxin Liu36ed56b2021-09-23 10:51:21 -07002995 if (unlikely (!out)) return_trace (false);
Qunxin Liub66094a2019-09-30 16:19:18 -07002996
2997 const hb_map_t *mapping = backtrack_map;
2998 serialize_array (c, backtrack.len, + backtrack.iter ()
2999 | hb_map (mapping));
3000
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003001 const auto &input = StructAfter<decltype (inputX)> (backtrack);
Qunxin Liub66094a2019-09-30 16:19:18 -07003002 if (input_map) mapping = input_map;
3003 serialize_array (c, input.lenP1, + input.iter ()
3004 | hb_map (mapping));
3005
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003006 const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
Qunxin Liub66094a2019-09-30 16:19:18 -07003007 if (lookahead_map) mapping = lookahead_map;
3008 serialize_array (c, lookahead.len, + lookahead.iter ()
3009 | hb_map (mapping));
3010
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003011 const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
Qunxin Liu593e58c2020-05-20 18:00:25 -07003012
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003013 HBUINT16* lookupCount = c->embed (&(lookup.len));
Qunxin Liu36ed56b2021-09-23 10:51:21 -07003014 if (!lookupCount) return_trace (false);
Garret Rieger8f47dd52020-11-04 11:05:22 -08003015
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003016 unsigned count = serialize_lookuprecord_array (c, lookup.as_array (), lookup_map);
Qunxin Liu36ed56b2021-09-23 10:51:21 -07003017 return_trace (c->check_assign (*lookupCount, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
Qunxin Liub66094a2019-09-30 16:19:18 -07003018 }
3019
3020 bool subset (hb_subset_context_t *c,
Qunxin Liu593e58c2020-05-20 18:00:25 -07003021 const hb_map_t *lookup_map,
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04303022 const hb_map_t *backtrack_map = nullptr,
3023 const hb_map_t *input_map = nullptr,
3024 const hb_map_t *lookahead_map = nullptr) const
Qunxin Liub66094a2019-09-30 16:19:18 -07003025 {
3026 TRACE_SUBSET (this);
3027
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003028 const auto &input = StructAfter<decltype (inputX)> (backtrack);
3029 const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
Qunxin Liub2fcca62019-10-24 15:15:26 -07003030
Qunxin Liub66094a2019-09-30 16:19:18 -07003031 if (!backtrack_map)
3032 {
Garret Riegere5835052020-09-29 11:05:08 -07003033 const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
Qunxin Liub66094a2019-09-30 16:19:18 -07003034 if (!hb_all (backtrack, glyphset) ||
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04303035 !hb_all (input, glyphset) ||
3036 !hb_all (lookahead, glyphset))
3037 return_trace (false);
Qunxin Liub66094a2019-09-30 16:19:18 -07003038
Qunxin Liu36ed56b2021-09-23 10:51:21 -07003039 serialize (c->serializer, lookup_map, c->plan->glyph_map);
Qunxin Liub66094a2019-09-30 16:19:18 -07003040 }
3041 else
3042 {
3043 if (!hb_all (backtrack, backtrack_map) ||
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04303044 !hb_all (input, input_map) ||
3045 !hb_all (lookahead, lookahead_map))
3046 return_trace (false);
Ebrahim Byagowiaca63902019-10-22 00:06:46 +03303047
Qunxin Liu36ed56b2021-09-23 10:51:21 -07003048 serialize (c->serializer, lookup_map, backtrack_map, input_map, lookahead_map);
Qunxin Liub66094a2019-09-30 16:19:18 -07003049 }
3050
3051 return_trace (true);
3052 }
3053
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303054 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03003055 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05003056 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003057 if (!backtrack.sanitize (c)) return_trace (false);
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003058 const auto &input = StructAfter<decltype (inputX)> (backtrack);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003059 if (!input.sanitize (c)) return_trace (false);
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003060 const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003061 if (!lookahead.sanitize (c)) return_trace (false);
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003062 const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003063 return_trace (lookup.sanitize (c));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04003064 }
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003065
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04003066 protected:
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06003067 Array16Of<typename Types::HBUINT>
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04003068 backtrack; /* Array of backtracking values
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003069 * (to be matched before the input
3070 * sequence) */
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06003071 HeadlessArrayOf<typename Types::HBUINT>
Behdad Esfahbode8cbaaf2009-05-18 02:03:58 -04003072 inputX; /* Array of input values (start with
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003073 * second glyph) */
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06003074 Array16Of<typename Types::HBUINT>
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04003075 lookaheadX; /* Array of lookahead values's (to be
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04003076 * matched after the input sequence) */
Behdad Esfahbod5639e252021-03-31 16:04:43 -06003077 Array16Of<LookupRecord>
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04003078 lookupX; /* Array of LookupRecords--in
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003079 * design order) */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04003080 public:
Behdad Esfahbodbea34c72010-05-10 17:28:16 -04003081 DEFINE_SIZE_MIN (8);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003082};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003083
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06003084template <typename Types>
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04003085struct ChainRuleSet
3086{
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06003087 using ChainRule = OT::ChainRule<Types>;
3088
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303089 bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07003090 {
Behdad Esfahbod05f21302019-03-29 22:40:13 -07003091 return
3092 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07003093 | hb_map (hb_add (this))
3094 | hb_map ([&] (const ChainRule &_) { return _.intersects (glyphs, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07003095 | hb_any
3096 ;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07003097 }
Qunxin Liub8a58a02021-01-10 15:50:04 -08003098 void closure (hb_closure_context_t *c, unsigned value, ChainContextClosureLookupContext &lookup_context) const
Behdad Esfahbod31081f72012-04-23 16:54:58 -04003099 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04303100 if (unlikely (c->lookup_limit_exceeded ())) return;
Garret Rieger4ad686b2020-03-25 23:32:28 -07003101
Behdad Esfahbod05f21302019-03-29 22:40:13 -07003102 return
3103 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07003104 | hb_map (hb_add (this))
Qunxin Liub8a58a02021-01-10 15:50:04 -08003105 | hb_apply ([&] (const ChainRule &_) { _.closure (c, value, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07003106 ;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04003107 }
3108
Garret Riegerad241f92020-09-28 15:26:13 -07003109 void closure_lookups (hb_closure_lookups_context_t *c,
3110 ChainContextClosureLookupContext &lookup_context) const
Qunxin Liu0b39c482019-10-22 16:00:43 -07003111 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04303112 if (unlikely (c->lookup_limit_exceeded ())) return;
Garret Rieger4ad686b2020-03-25 23:32:28 -07003113
Qunxin Liu0b39c482019-10-22 16:00:43 -07003114 + hb_iter (rule)
3115 | hb_map (hb_add (this))
Garret Riegere31c2692020-09-28 16:51:25 -07003116 | hb_apply ([&] (const ChainRule &_) { _.closure_lookups (c, lookup_context); })
Qunxin Liu0b39c482019-10-22 16:00:43 -07003117 ;
3118 }
3119
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303120 void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05003121 {
Behdad Esfahbod05f21302019-03-29 22:40:13 -07003122 return
3123 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07003124 | hb_map (hb_add (this))
3125 | hb_apply ([&] (const ChainRule &_) { _.collect_glyphs (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07003126 ;
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05003127 }
3128
Behdad Esfahbod19ec01d2022-11-16 19:14:42 -07003129 bool would_apply (hb_would_apply_context_t *c,
3130 const ChainContextApplyLookupContext &lookup_context) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003131 {
Behdad Esfahbod05f21302019-03-29 22:40:13 -07003132 return
3133 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07003134 | hb_map (hb_add (this))
3135 | hb_map ([&] (const ChainRule &_) { return _.would_apply (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07003136 | hb_any
3137 ;
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003138 }
3139
Behdad Esfahbod19ec01d2022-11-16 19:14:42 -07003140 bool apply (hb_ot_apply_context_t *c,
3141 const ChainContextApplyLookupContext &lookup_context) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04003142 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05003143 TRACE_APPLY (this);
Behdad Esfahbod05f21302019-03-29 22:40:13 -07003144 return_trace (
3145 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07003146 | hb_map (hb_add (this))
3147 | hb_map ([&] (const ChainRule &_) { return _.apply (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07003148 | hb_any
3149 )
3150 ;
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04003151 }
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003152
Qunxin Liub66094a2019-09-30 16:19:18 -07003153 bool subset (hb_subset_context_t *c,
Qunxin Liu593e58c2020-05-20 18:00:25 -07003154 const hb_map_t *lookup_map,
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04303155 const hb_map_t *backtrack_klass_map = nullptr,
3156 const hb_map_t *input_klass_map = nullptr,
3157 const hb_map_t *lookahead_klass_map = nullptr) const
Qunxin Liub66094a2019-09-30 16:19:18 -07003158 {
3159 TRACE_SUBSET (this);
3160
3161 auto snap = c->serializer->snapshot ();
3162 auto *out = c->serializer->start_embed (*this);
3163 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
3164
Behdad Esfahbodad28f972021-03-31 12:49:14 -06003165 for (const Offset16To<ChainRule>& _ : rule)
Qunxin Liub66094a2019-09-30 16:19:18 -07003166 {
3167 if (!_) continue;
Garret Riegerc2cc5662021-09-22 14:15:55 -07003168 auto o_snap = c->serializer->snapshot ();
Qunxin Liub66094a2019-09-30 16:19:18 -07003169 auto *o = out->rule.serialize_append (c->serializer);
3170 if (unlikely (!o)) continue;
Ebrahim Byagowiaca63902019-10-22 00:06:46 +03303171
ariza188a0a42020-03-07 11:02:36 -08003172 if (!o->serialize_subset (c, _, this,
Qunxin Liu593e58c2020-05-20 18:00:25 -07003173 lookup_map,
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04303174 backtrack_klass_map,
3175 input_klass_map,
3176 lookahead_klass_map))
Qunxin Liub66094a2019-09-30 16:19:18 -07003177 {
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04303178 out->rule.pop ();
3179 c->serializer->revert (o_snap);
Qunxin Liub66094a2019-09-30 16:19:18 -07003180 }
3181 }
3182
3183 bool ret = bool (out->rule);
3184 if (!ret) c->serializer->revert (snap);
Ebrahim Byagowiaca63902019-10-22 00:06:46 +03303185
Qunxin Liub66094a2019-09-30 16:19:18 -07003186 return_trace (ret);
3187 }
3188
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303189 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03003190 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05003191 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003192 return_trace (rule.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04003193 }
3194
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04003195 protected:
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06003196 Array16OfOffset16To<ChainRule>
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04003197 rule; /* Array of ChainRule tables
3198 * ordered by preference */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04003199 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04003200 DEFINE_SIZE_ARRAY (2, rule);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003201};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003202
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06003203template <typename Types>
3204struct ChainContextFormat1_4
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04003205{
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06003206 using ChainRuleSet = OT::ChainRuleSet<Types>;
3207
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303208 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07003209 {
3210 struct ChainContextClosureLookupContext lookup_context = {
Qunxin Liub8a58a02021-01-10 15:50:04 -08003211 {intersects_glyph, intersected_glyph},
3212 ContextFormat::SimpleContext,
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07003213 {nullptr, nullptr, nullptr}
3214 };
Behdad Esfahbod05f21302019-03-29 22:40:13 -07003215
3216 return
3217 + hb_zip (this+coverage, ruleSet)
3218 | hb_filter (*glyphs, hb_first)
3219 | hb_map (hb_second)
Behdad Esfahbod23768672019-05-15 21:57:26 -07003220 | hb_map (hb_add (this))
3221 | hb_map ([&] (const ChainRuleSet &_) { return _.intersects (glyphs, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07003222 | hb_any
3223 ;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07003224 }
3225
Qunxin Liub4fc5932020-12-09 10:44:18 -08003226 bool may_have_non_1to1 () const
3227 { return true; }
3228
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303229 void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04003230 {
Behdad Esfahbod00dfbbc2022-07-21 11:39:32 -06003231 hb_set_t& cur_active_glyphs = c->push_cur_active_glyphs ();
3232 get_coverage ().intersect_set (c->previous_parent_active_glyphs (),
Garret Rieger4e2f4092022-01-31 12:20:32 -08003233 cur_active_glyphs);
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08003234
Behdad Esfahbod31081f72012-04-23 16:54:58 -04003235 struct ChainContextClosureLookupContext lookup_context = {
Qunxin Liub8a58a02021-01-10 15:50:04 -08003236 {intersects_glyph, intersected_glyph},
3237 ContextFormat::SimpleContext,
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02003238 {nullptr, nullptr, nullptr}
Behdad Esfahbod31081f72012-04-23 16:54:58 -04003239 };
Behdad Esfahbod05f21302019-03-29 22:40:13 -07003240
Qunxin Liub8a58a02021-01-10 15:50:04 -08003241 + hb_zip (this+coverage, hb_range ((unsigned) ruleSet.len))
Garret Rieger4e2f4092022-01-31 12:20:32 -08003242 | hb_filter ([&] (hb_codepoint_t _) {
3243 return c->previous_parent_active_glyphs ().has (_);
3244 }, hb_first)
Qunxin Liub8a58a02021-01-10 15:50:04 -08003245 | hb_map ([&](const hb_pair_t<hb_codepoint_t, unsigned> _) { return hb_pair_t<unsigned, const ChainRuleSet&> (_.first, this+ruleSet[_.second]); })
3246 | hb_apply ([&] (const hb_pair_t<unsigned, const ChainRuleSet&>& _) { _.second.closure (c, _.first, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07003247 ;
Garret Riegerbc899652022-01-28 13:54:10 -08003248
3249 c->pop_cur_done_glyphs ();
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04003250 }
3251
Qunxin Liu0b39c482019-10-22 16:00:43 -07003252 void closure_lookups (hb_closure_lookups_context_t *c) const
3253 {
Garret Riegerad241f92020-09-28 15:26:13 -07003254 struct ChainContextClosureLookupContext lookup_context = {
Behdad Esfahbod2680be12022-12-03 11:53:14 -07003255 {intersects_glyph, nullptr},
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08003256 ContextFormat::SimpleContext,
Garret Riegerad241f92020-09-28 15:26:13 -07003257 {nullptr, nullptr, nullptr}
3258 };
3259
3260 + hb_zip (this+coverage, ruleSet)
3261 | hb_filter (*c->glyphs, hb_first)
3262 | hb_map (hb_second)
Qunxin Liu0b39c482019-10-22 16:00:43 -07003263 | hb_map (hb_add (this))
Garret Riegere31c2692020-09-28 16:51:25 -07003264 | hb_apply ([&] (const ChainRuleSet &_) { _.closure_lookups (c, lookup_context); })
Qunxin Liu0b39c482019-10-22 16:00:43 -07003265 ;
3266 }
3267
Qunxin Liu8200e482020-02-26 13:11:42 -08003268 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
3269
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303270 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbod26514d52012-11-23 18:13:48 -05003271 {
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07003272 (this+coverage).collect_coverage (c->input);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05003273
3274 struct ChainContextCollectGlyphsLookupContext lookup_context = {
3275 {collect_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02003276 {nullptr, nullptr, nullptr}
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05003277 };
3278
Behdad Esfahbod05f21302019-03-29 22:40:13 -07003279 + hb_iter (ruleSet)
Behdad Esfahbod23768672019-05-15 21:57:26 -07003280 | hb_map (hb_add (this))
3281 | hb_apply ([&] (const ChainRuleSet &_) { _.collect_glyphs (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07003282 ;
Behdad Esfahbod26514d52012-11-23 18:13:48 -05003283 }
3284
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303285 bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003286 {
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05003287 const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003288 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06003289 {{match_glyph, match_glyph, match_glyph}},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02003290 {nullptr, nullptr, nullptr}
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003291 };
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07003292 return rule_set.would_apply (c, lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003293 }
3294
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303295 const Coverage &get_coverage () const { return this+coverage; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05003296
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303297 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04003298 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05003299 TRACE_APPLY (this);
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05003300 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003301 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04003302
3303 const ChainRuleSet &rule_set = this+ruleSet[index];
Behdad Esfahbod31081f72012-04-23 16:54:58 -04003304 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06003305 {{match_glyph, match_glyph, match_glyph}},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02003306 {nullptr, nullptr, nullptr}
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04003307 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003308 return_trace (rule_set.apply (c, lookup_context));
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003309 }
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04003310
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303311 bool subset (hb_subset_context_t *c) const
Behdad Esfahbod339d3602018-09-03 17:33:34 -07003312 {
3313 TRACE_SUBSET (this);
Garret Riegere5835052020-09-29 11:05:08 -07003314 const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
Qunxin Liub66094a2019-09-30 16:19:18 -07003315 const hb_map_t &glyph_map = *c->plan->glyph_map;
3316
3317 auto *out = c->serializer->start_embed (*this);
3318 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
3319 out->format = format;
3320
Behdad Esfahbod1a00ab62023-01-11 10:56:16 -07003321 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 -07003322 hb_sorted_vector_t<hb_codepoint_t> new_coverage;
3323 + hb_zip (this+coverage, ruleSet)
3324 | hb_filter (glyphset, hb_first)
Qunxin Liu593e58c2020-05-20 18:00:25 -07003325 | hb_filter (subset_offset_array (c, out->ruleSet, this, lookup_map), hb_second)
Qunxin Liub66094a2019-09-30 16:19:18 -07003326 | hb_map (hb_first)
3327 | hb_map (glyph_map)
3328 | hb_sink (new_coverage)
3329 ;
3330
Garret Rieger085aa652021-06-14 16:47:45 -07003331 out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
Qunxin Liub66094a2019-09-30 16:19:18 -07003332 return_trace (bool (new_coverage));
Behdad Esfahbod339d3602018-09-03 17:33:34 -07003333 }
3334
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303335 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03003336 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05003337 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003338 return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04003339 }
3340
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04003341 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01003342 HBUINT16 format; /* Format identifier--format = 1 */
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06003343 typename Types::template OffsetTo<Coverage>
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04003344 coverage; /* Offset to Coverage table--from
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003345 * beginning of table */
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06003346 Array16Of<typename Types::template OffsetTo<ChainRuleSet>>
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04003347 ruleSet; /* Array of ChainRuleSet tables
3348 * ordered by Coverage Index */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04003349 public:
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06003350 DEFINE_SIZE_ARRAY (2 + 2 * Types::size, ruleSet);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003351};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003352
Behdad Esfahboda90c5af2022-07-08 13:11:47 -06003353template <typename Types>
3354struct ChainContextFormat2_5
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04003355{
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06003356 using ChainRuleSet = OT::ChainRuleSet<SmallTypes>;
3357
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303358 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07003359 {
3360 if (!(this+coverage).intersects (glyphs))
3361 return false;
3362
3363 const ClassDef &backtrack_class_def = this+backtrackClassDef;
3364 const ClassDef &input_class_def = this+inputClassDef;
3365 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
3366
Behdad Esfahbodac8b2322022-11-30 16:42:15 -07003367 hb_map_t caches[3] = {};
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07003368 struct ChainContextClosureLookupContext lookup_context = {
Behdad Esfahbod2680be12022-12-03 11:53:14 -07003369 {intersects_class, nullptr},
Qunxin Liub8a58a02021-01-10 15:50:04 -08003370 ContextFormat::ClassBasedContext,
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07003371 {&backtrack_class_def,
3372 &input_class_def,
Behdad Esfahbodac8b2322022-11-30 16:42:15 -07003373 &lookahead_class_def},
3374 {&caches[0], &caches[1], &caches[2]}
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07003375 };
3376
Qunxin Liu540f19b2021-10-29 17:11:53 -07003377 hb_set_t retained_coverage_glyphs;
Behdad Esfahbod00dfbbc2022-07-21 11:39:32 -06003378 (this+coverage).intersect_set (*glyphs, retained_coverage_glyphs);
Qunxin Liu540f19b2021-10-29 17:11:53 -07003379
3380 hb_set_t coverage_glyph_classes;
3381 input_class_def.intersected_classes (&retained_coverage_glyphs, &coverage_glyph_classes);
3382
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07003383 return
Behdad Esfahbod26111a12020-06-28 02:59:47 -07003384 + hb_iter (ruleSet)
3385 | hb_map (hb_add (this))
3386 | hb_enumerate
3387 | hb_map ([&] (const hb_pair_t<unsigned, const ChainRuleSet &> p)
Behdad Esfahbod78d35f02019-05-15 18:15:05 -07003388 { return input_class_def.intersects_class (glyphs, p.first) &&
Qunxin Liu540f19b2021-10-29 17:11:53 -07003389 coverage_glyph_classes.has (p.first) &&
Behdad Esfahbod26111a12020-06-28 02:59:47 -07003390 p.second.intersects (glyphs, lookup_context); })
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07003391 | hb_any
3392 ;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07003393 }
Qunxin Liub4fc5932020-12-09 10:44:18 -08003394
3395 bool may_have_non_1to1 () const
3396 { return true; }
3397
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303398 void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04003399 {
Behdad Esfahbod31081f72012-04-23 16:54:58 -04003400 if (!(this+coverage).intersects (c->glyphs))
Behdad Esfahbod5caece62012-04-23 23:03:12 -04003401 return;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04003402
Behdad Esfahbod00dfbbc2022-07-21 11:39:32 -06003403 hb_set_t& cur_active_glyphs = c->push_cur_active_glyphs ();
3404 get_coverage ().intersect_set (c->previous_parent_active_glyphs (),
Garret Rieger4e2f4092022-01-31 12:20:32 -08003405 cur_active_glyphs);
3406
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08003407
Behdad Esfahbod31081f72012-04-23 16:54:58 -04003408 const ClassDef &backtrack_class_def = this+backtrackClassDef;
3409 const ClassDef &input_class_def = this+inputClassDef;
3410 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
3411
Behdad Esfahbodac8b2322022-11-30 16:42:15 -07003412 hb_map_t caches[3] = {};
Behdad Esfahbod630b8742022-12-03 12:13:15 -07003413 intersected_class_cache_t intersected_cache;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04003414 struct ChainContextClosureLookupContext lookup_context = {
Qunxin Liub8a58a02021-01-10 15:50:04 -08003415 {intersects_class, intersected_class_glyphs},
3416 ContextFormat::ClassBasedContext,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04003417 {&backtrack_class_def,
3418 &input_class_def,
Behdad Esfahbodac8b2322022-11-30 16:42:15 -07003419 &lookahead_class_def},
Behdad Esfahbod630b8742022-12-03 12:13:15 -07003420 {&caches[0], &caches[1], &caches[2]},
3421 &intersected_cache
Behdad Esfahbod31081f72012-04-23 16:54:58 -04003422 };
3423
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07003424 + hb_enumerate (ruleSet)
Behdad Esfahbod78d35f02019-05-15 18:15:05 -07003425 | hb_filter ([&] (unsigned _)
Garret Riegerbc899652022-01-28 13:54:10 -08003426 { return input_class_def.intersects_class (&c->parent_active_glyphs (), _); },
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07003427 hb_first)
Behdad Esfahboda90c5af2022-07-08 13:11:47 -06003428 | hb_apply ([&] (const hb_pair_t<unsigned, const typename Types::template OffsetTo<ChainRuleSet>&> _)
Qunxin Liub8a58a02021-01-10 15:50:04 -08003429 {
3430 const ChainRuleSet& chainrule_set = this+_.second;
3431 chainrule_set.closure (c, _.first, lookup_context);
3432 })
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07003433 ;
Garret Riegerbc899652022-01-28 13:54:10 -08003434
3435 c->pop_cur_done_glyphs ();
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04003436 }
3437
Qunxin Liu0b39c482019-10-22 16:00:43 -07003438 void closure_lookups (hb_closure_lookups_context_t *c) const
3439 {
Garret Riegerad241f92020-09-28 15:26:13 -07003440 if (!(this+coverage).intersects (c->glyphs))
3441 return;
3442
3443 const ClassDef &backtrack_class_def = this+backtrackClassDef;
3444 const ClassDef &input_class_def = this+inputClassDef;
3445 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
3446
Behdad Esfahbodac8b2322022-11-30 16:42:15 -07003447 hb_map_t caches[3] = {};
Garret Riegerad241f92020-09-28 15:26:13 -07003448 struct ChainContextClosureLookupContext lookup_context = {
Behdad Esfahbod2680be12022-12-03 11:53:14 -07003449 {intersects_class, nullptr},
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08003450 ContextFormat::ClassBasedContext,
Garret Riegerad241f92020-09-28 15:26:13 -07003451 {&backtrack_class_def,
3452 &input_class_def,
Behdad Esfahbodac8b2322022-11-30 16:42:15 -07003453 &lookahead_class_def},
3454 {&caches[0], &caches[1], &caches[2]}
Garret Riegerad241f92020-09-28 15:26:13 -07003455 };
3456
Qunxin Liu0b39c482019-10-22 16:00:43 -07003457 + hb_iter (ruleSet)
3458 | hb_map (hb_add (this))
Garret Riegerad241f92020-09-28 15:26:13 -07003459 | hb_enumerate
Behdad Esfahbod6e1afac2021-02-09 18:48:46 -07003460 | hb_filter([&] (unsigned klass)
3461 { return input_class_def.intersects_class (c->glyphs, klass); }, hb_first)
Garret Riegerad241f92020-09-28 15:26:13 -07003462 | hb_map (hb_second)
3463 | hb_apply ([&] (const ChainRuleSet &_)
3464 { _.closure_lookups (c, lookup_context); })
Qunxin Liu0b39c482019-10-22 16:00:43 -07003465 ;
3466 }
3467
Qunxin Liu8200e482020-02-26 13:11:42 -08003468 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
3469
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303470 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbod26514d52012-11-23 18:13:48 -05003471 {
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07003472 (this+coverage).collect_coverage (c->input);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05003473
Behdad Esfahbod11fba792013-01-02 23:36:37 -06003474 const ClassDef &backtrack_class_def = this+backtrackClassDef;
3475 const ClassDef &input_class_def = this+inputClassDef;
3476 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
3477
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05003478 struct ChainContextCollectGlyphsLookupContext lookup_context = {
3479 {collect_class},
Behdad Esfahbod11fba792013-01-02 23:36:37 -06003480 {&backtrack_class_def,
3481 &input_class_def,
3482 &lookahead_class_def}
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05003483 };
3484
Behdad Esfahbod05f21302019-03-29 22:40:13 -07003485 + hb_iter (ruleSet)
Behdad Esfahbod23768672019-05-15 21:57:26 -07003486 | hb_map (hb_add (this))
3487 | hb_apply ([&] (const ChainRuleSet &_) { _.collect_glyphs (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07003488 ;
Behdad Esfahbod26514d52012-11-23 18:13:48 -05003489 }
3490
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303491 bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003492 {
Behdad Esfahbod11fba792013-01-02 23:36:37 -06003493 const ClassDef &backtrack_class_def = this+backtrackClassDef;
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003494 const ClassDef &input_class_def = this+inputClassDef;
Behdad Esfahbod11fba792013-01-02 23:36:37 -06003495 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003496
Behdad Esfahbod2dc11412012-11-24 19:16:34 -05003497 unsigned int index = input_class_def.get_class (c->glyphs[0]);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003498 const ChainRuleSet &rule_set = this+ruleSet[index];
3499 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06003500 {{match_class, match_class, match_class}},
Behdad Esfahbod11fba792013-01-02 23:36:37 -06003501 {&backtrack_class_def,
3502 &input_class_def,
3503 &lookahead_class_def}
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003504 };
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07003505 return rule_set.would_apply (c, lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003506 }
3507
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303508 const Coverage &get_coverage () const { return this+coverage; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05003509
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06003510 unsigned cache_cost () const
3511 {
Behdad Esfahbod21346af2022-06-07 14:41:39 -06003512 unsigned c = (this+lookaheadClassDef).cost () * ruleSet.len;
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06003513 return c >= 4 ? c : 0;
3514 }
Behdad Esfahbod5963cf42022-06-07 09:12:45 -06003515 bool cache_func (hb_ot_apply_context_t *c, bool enter) const
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06003516 {
Behdad Esfahbod5963cf42022-06-07 09:12:45 -06003517 if (enter)
3518 {
3519 if (!HB_BUFFER_TRY_ALLOCATE_VAR (c->buffer, syllable))
3520 return false;
3521 auto &info = c->buffer->info;
3522 unsigned count = c->buffer->len;
3523 for (unsigned i = 0; i < count; i++)
3524 info[i].syllable() = 255;
3525 c->new_syllables = 255;
3526 return true;
3527 }
3528 else
3529 {
3530 c->new_syllables = (unsigned) -1;
3531 HB_BUFFER_DEALLOCATE_VAR (c->buffer, syllable);
3532 return true;
3533 }
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06003534 }
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06003535
3536 bool apply (hb_ot_apply_context_t *c, bool cached = false) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04003537 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05003538 TRACE_APPLY (this);
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05003539 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003540 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04003541
3542 const ClassDef &backtrack_class_def = this+backtrackClassDef;
3543 const ClassDef &input_class_def = this+inputClassDef;
3544 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
3545
Behdad Esfahboda90c5af2022-07-08 13:11:47 -06003546 /* For ChainContextFormat2_5 we cache the LookaheadClassDef instead of InputClassDef.
Behdad Esfahbodbfee6832022-06-07 11:41:05 -06003547 * The reason is that most heavy fonts want to identify a glyph in context and apply
3548 * a lookup to it. In this scenario, the length of the input sequence is one, whereas
3549 * the lookahead / backtrack are typically longer. The one glyph in input sequence is
3550 * looked-up below and no input glyph is looked up in individual rules, whereas the
3551 * lookahead and backtrack glyphs are tried. Since we match lookahead before backtrack,
3552 * we should cache lookahead. This decisions showed a 20% improvement in shaping of
3553 * the Gulzar font.
3554 */
3555
Behdad Esfahbod31081f72012-04-23 16:54:58 -04003556 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbod49d75ef2023-01-27 15:37:11 -07003557 {{cached && &backtrack_class_def == &lookahead_class_def ? match_class_cached : match_class,
Behdad Esfahbodbfee6832022-06-07 11:41:05 -06003558 cached && &input_class_def == &lookahead_class_def ? match_class_cached : match_class,
3559 cached ? match_class_cached : match_class}},
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04003560 {&backtrack_class_def,
3561 &input_class_def,
3562 &lookahead_class_def}
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04003563 };
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06003564
Behdad Esfahbodbfee6832022-06-07 11:41:05 -06003565 index = input_class_def.get_class (c->buffer->cur().codepoint);
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06003566 const ChainRuleSet &rule_set = this+ruleSet[index];
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003567 return_trace (rule_set.apply (c, lookup_context));
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003568 }
3569
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303570 bool subset (hb_subset_context_t *c) const
Behdad Esfahbod339d3602018-09-03 17:33:34 -07003571 {
3572 TRACE_SUBSET (this);
Qunxin Liub66094a2019-09-30 16:19:18 -07003573 auto *out = c->serializer->start_embed (*this);
3574 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
3575 out->format = format;
ariza188a0a42020-03-07 11:02:36 -08003576 out->coverage.serialize_subset (c, coverage, this);
Qunxin Liub66094a2019-09-30 16:19:18 -07003577
3578 hb_map_t backtrack_klass_map;
Qunxin Liub66094a2019-09-30 16:19:18 -07003579 hb_map_t input_klass_map;
Qunxin Liub66094a2019-09-30 16:19:18 -07003580 hb_map_t lookahead_klass_map;
Behdad Esfahboddfa9d7a2021-02-11 11:08:52 -07003581
3582 out->backtrackClassDef.serialize_subset (c, backtrackClassDef, this, &backtrack_klass_map);
3583 // TODO: subset inputClassDef based on glyphs survived in Coverage subsetting
3584 out->inputClassDef.serialize_subset (c, inputClassDef, this, &input_klass_map);
ariza188a0a42020-03-07 11:02:36 -08003585 out->lookaheadClassDef.serialize_subset (c, lookaheadClassDef, this, &lookahead_klass_map);
Behdad Esfahboddfa9d7a2021-02-11 11:08:52 -07003586
3587 if (unlikely (!c->serializer->propagate_error (backtrack_klass_map,
3588 input_klass_map,
3589 lookahead_klass_map)))
Garret Rieger06dbb6a2020-07-31 15:56:14 -07003590 return_trace (false);
Qunxin Liub66094a2019-09-30 16:19:18 -07003591
Qunxin Liu540f19b2021-10-29 17:11:53 -07003592 const hb_set_t* glyphset = c->plan->glyphset_gsub ();
3593 hb_set_t retained_coverage_glyphs;
Behdad Esfahbod00dfbbc2022-07-21 11:39:32 -06003594 (this+coverage).intersect_set (*glyphset, retained_coverage_glyphs);
Qunxin Liu540f19b2021-10-29 17:11:53 -07003595
3596 hb_set_t coverage_glyph_classes;
3597 (this+inputClassDef).intersected_classes (&retained_coverage_glyphs, &coverage_glyph_classes);
3598
Garret Riegerdc375552020-09-25 13:08:46 -07003599 int non_zero_index = -1, index = 0;
Qunxin Liub66094a2019-09-30 16:19:18 -07003600 bool ret = true;
Behdad Esfahbod1a00ab62023-01-11 10:56:16 -07003601 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 -07003602 auto last_non_zero = c->serializer->snapshot ();
Qunxin Liu540f19b2021-10-29 17:11:53 -07003603 for (const auto& _ : + hb_enumerate (ruleSet)
3604 | hb_filter (input_klass_map, hb_first))
Qunxin Liub66094a2019-09-30 16:19:18 -07003605 {
3606 auto *o = out->ruleSet.serialize_append (c->serializer);
3607 if (unlikely (!o))
3608 {
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04303609 ret = false;
3610 break;
Qunxin Liub66094a2019-09-30 16:19:18 -07003611 }
Qunxin Liu540f19b2021-10-29 17:11:53 -07003612 if (coverage_glyph_classes.has (_.first) &&
3613 o->serialize_subset (c, _.second, this,
Qunxin Liu593e58c2020-05-20 18:00:25 -07003614 lookup_map,
3615 &backtrack_klass_map,
3616 &input_klass_map,
3617 &lookahead_klass_map))
Garret Riegerdc375552020-09-25 13:08:46 -07003618 {
3619 last_non_zero = c->serializer->snapshot ();
Ebrahim Byagowi5a7cc7f2020-07-29 08:33:32 +04303620 non_zero_index = index;
Garret Riegerdc375552020-09-25 13:08:46 -07003621 }
Qunxin Liu593e58c2020-05-20 18:00:25 -07003622
3623 index++;
Qunxin Liub66094a2019-09-30 16:19:18 -07003624 }
3625
Qunxin Liu540f19b2021-10-29 17:11:53 -07003626 if (!ret || non_zero_index == -1) return_trace (false);
Qunxin Liub66094a2019-09-30 16:19:18 -07003627
Garret Riegerdc375552020-09-25 13:08:46 -07003628 // prune empty trailing ruleSets
3629 if (index > non_zero_index) {
3630 c->serializer->revert (last_non_zero);
3631 out->ruleSet.len = non_zero_index + 1;
Qunxin Liub66094a2019-09-30 16:19:18 -07003632 }
3633
3634 return_trace (bool (out->ruleSet));
Behdad Esfahbod339d3602018-09-03 17:33:34 -07003635 }
3636
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303637 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03003638 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05003639 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003640 return_trace (coverage.sanitize (c, this) &&
3641 backtrackClassDef.sanitize (c, this) &&
3642 inputClassDef.sanitize (c, this) &&
3643 lookaheadClassDef.sanitize (c, this) &&
3644 ruleSet.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04003645 }
3646
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04003647 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01003648 HBUINT16 format; /* Format identifier--format = 2 */
Behdad Esfahboda90c5af2022-07-08 13:11:47 -06003649 typename Types::template OffsetTo<Coverage>
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04003650 coverage; /* Offset to Coverage table--from
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003651 * beginning of table */
Behdad Esfahboda90c5af2022-07-08 13:11:47 -06003652 typename Types::template OffsetTo<ClassDef>
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04003653 backtrackClassDef; /* Offset to glyph ClassDef table
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003654 * containing backtrack sequence
3655 * data--from beginning of table */
Behdad Esfahboda90c5af2022-07-08 13:11:47 -06003656 typename Types::template OffsetTo<ClassDef>
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04003657 inputClassDef; /* Offset to glyph ClassDef
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003658 * table containing input sequence
3659 * data--from beginning of table */
Behdad Esfahboda90c5af2022-07-08 13:11:47 -06003660 typename Types::template OffsetTo<ClassDef>
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04003661 lookaheadClassDef; /* Offset to glyph ClassDef table
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003662 * containing lookahead sequence
3663 * data--from beginning of table */
Behdad Esfahboda90c5af2022-07-08 13:11:47 -06003664 Array16Of<typename Types::template OffsetTo<ChainRuleSet>>
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04003665 ruleSet; /* Array of ChainRuleSet tables
3666 * ordered by class */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04003667 public:
Behdad Esfahboda90c5af2022-07-08 13:11:47 -06003668 DEFINE_SIZE_ARRAY (4 + 4 * Types::size, ruleSet);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003669};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003670
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04003671struct ChainContextFormat3
3672{
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06003673 using RuleSet = OT::RuleSet<SmallTypes>;
3674
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303675 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07003676 {
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003677 const auto &input = StructAfter<decltype (inputX)> (backtrack);
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07003678
3679 if (!(this+input[0]).intersects (glyphs))
3680 return false;
3681
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003682 const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07003683 struct ChainContextClosureLookupContext lookup_context = {
Behdad Esfahbod2680be12022-12-03 11:53:14 -07003684 {intersects_coverage, nullptr},
Qunxin Liub8a58a02021-01-10 15:50:04 -08003685 ContextFormat::CoverageBasedContext,
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07003686 {this, this, this}
3687 };
3688 return chain_context_intersects (glyphs,
3689 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
3690 input.len, (const HBUINT16 *) input.arrayZ + 1,
3691 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
3692 lookup_context);
3693 }
3694
Qunxin Liub4fc5932020-12-09 10:44:18 -08003695 bool may_have_non_1to1 () const
3696 { return true; }
3697
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303698 void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04003699 {
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003700 const auto &input = StructAfter<decltype (inputX)> (backtrack);
Behdad Esfahbod5caece62012-04-23 23:03:12 -04003701
3702 if (!(this+input[0]).intersects (c->glyphs))
3703 return;
3704
Behdad Esfahbod00dfbbc2022-07-21 11:39:32 -06003705 hb_set_t& cur_active_glyphs = c->push_cur_active_glyphs ();
3706 get_coverage ().intersect_set (c->previous_parent_active_glyphs (),
Garret Rieger4e2f4092022-01-31 12:20:32 -08003707 cur_active_glyphs);
3708
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08003709
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003710 const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
3711 const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
Behdad Esfahbod5caece62012-04-23 23:03:12 -04003712 struct ChainContextClosureLookupContext lookup_context = {
Qunxin Liub8a58a02021-01-10 15:50:04 -08003713 {intersects_coverage, intersected_coverage_glyphs},
3714 ContextFormat::CoverageBasedContext,
Behdad Esfahbod5caece62012-04-23 23:03:12 -04003715 {this, this, this}
3716 };
3717 chain_context_closure_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07003718 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
3719 input.len, (const HBUINT16 *) input.arrayZ + 1,
3720 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
3721 lookup.len, lookup.arrayZ,
Qunxin Liub8a58a02021-01-10 15:50:04 -08003722 0, lookup_context);
Garret Riegerbc899652022-01-28 13:54:10 -08003723
3724 c->pop_cur_done_glyphs ();
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04003725 }
3726
Qunxin Liu0b39c482019-10-22 16:00:43 -07003727 void closure_lookups (hb_closure_lookups_context_t *c) const
3728 {
Garret Riegera5c0ec72020-09-25 14:57:20 -07003729 if (!intersects (c->glyphs))
3730 return;
3731
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003732 const auto &input = StructAfter<decltype (inputX)> (backtrack);
3733 const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
3734 const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
Qunxin Liu0b39c482019-10-22 16:00:43 -07003735 recurse_lookups (c, lookup.len, lookup.arrayZ);
3736 }
3737
Qunxin Liu8200e482020-02-26 13:11:42 -08003738 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
3739
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303740 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbod26514d52012-11-23 18:13:48 -05003741 {
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003742 const auto &input = StructAfter<decltype (inputX)> (backtrack);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05003743
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07003744 (this+input[0]).collect_coverage (c->input);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05003745
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003746 const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
3747 const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
3748
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05003749 struct ChainContextCollectGlyphsLookupContext lookup_context = {
3750 {collect_coverage},
3751 {this, this, this}
3752 };
3753 chain_context_collect_glyphs_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07003754 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
3755 input.len, (const HBUINT16 *) input.arrayZ + 1,
3756 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
3757 lookup.len, lookup.arrayZ,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05003758 lookup_context);
Behdad Esfahbod26514d52012-11-23 18:13:48 -05003759 }
3760
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303761 bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003762 {
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003763 const auto &input = StructAfter<decltype (inputX)> (backtrack);
3764 const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
3765 const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003766 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06003767 {{match_coverage, match_coverage, match_coverage}},
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003768 {this, this, this}
3769 };
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07003770 return chain_context_would_apply_lookup (c,
3771 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
3772 input.len, (const HBUINT16 *) input.arrayZ + 1,
3773 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
3774 lookup.len, lookup.arrayZ, lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003775 }
3776
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303777 const Coverage &get_coverage () const
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05003778 {
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003779 const auto &input = StructAfter<decltype (inputX)> (backtrack);
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05003780 return this+input[0];
3781 }
3782
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303783 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04003784 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05003785 TRACE_APPLY (this);
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003786 const auto &input = StructAfter<decltype (inputX)> (backtrack);
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04003787
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05003788 unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003789 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003790
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003791 const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
3792 const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04003793 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06003794 {{match_coverage, match_coverage, match_coverage}},
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04003795 {this, this, this}
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04003796 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003797 return_trace (chain_context_apply_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07003798 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
3799 input.len, (const HBUINT16 *) input.arrayZ + 1,
3800 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
3801 lookup.len, lookup.arrayZ, lookup_context));
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003802 }
3803
Qunxin Liub66094a2019-09-30 16:19:18 -07003804 template<typename Iterator,
3805 hb_requires (hb_is_iterator (Iterator))>
Ebrahim Byagowi07acd1a2020-03-08 23:39:24 +03303806 bool serialize_coverage_offsets (hb_subset_context_t *c, Iterator it, const void* base) const
Qunxin Liub66094a2019-09-30 16:19:18 -07003807 {
3808 TRACE_SERIALIZE (this);
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06003809 auto *out = c->serializer->start_embed<Array16OfOffset16To<Coverage>> ();
Qunxin Liub66094a2019-09-30 16:19:18 -07003810
Garret Rieger90eb1a42020-09-25 12:36:32 -07003811 if (unlikely (!c->serializer->allocate_size<HBUINT16> (HBUINT16::static_size)))
Garret Rieger940e1c62020-09-28 17:22:01 -07003812 return_trace (false);
Qunxin Liub66094a2019-09-30 16:19:18 -07003813
Garret Rieger940e1c62020-09-28 17:22:01 -07003814 for (auto& offset : it) {
3815 auto *o = out->serialize_append (c->serializer);
3816 if (unlikely (!o) || !o->serialize_subset (c, offset, base))
3817 return_trace (false);
3818 }
Qunxin Liub66094a2019-09-30 16:19:18 -07003819
Garret Rieger940e1c62020-09-28 17:22:01 -07003820 return_trace (true);
Qunxin Liub66094a2019-09-30 16:19:18 -07003821 }
3822
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303823 bool subset (hb_subset_context_t *c) const
Behdad Esfahbod339d3602018-09-03 17:33:34 -07003824 {
3825 TRACE_SUBSET (this);
Qunxin Liub66094a2019-09-30 16:19:18 -07003826
3827 auto *out = c->serializer->start_embed (this);
3828 if (unlikely (!out)) return_trace (false);
3829 if (unlikely (!c->serializer->embed (this->format))) return_trace (false);
3830
ariza188a0a42020-03-07 11:02:36 -08003831 if (!serialize_coverage_offsets (c, backtrack.iter (), this))
Qunxin Liub66094a2019-09-30 16:19:18 -07003832 return_trace (false);
Ebrahim Byagowiaca63902019-10-22 00:06:46 +03303833
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003834 const auto &input = StructAfter<decltype (inputX)> (backtrack);
ariza188a0a42020-03-07 11:02:36 -08003835 if (!serialize_coverage_offsets (c, input.iter (), this))
Qunxin Liub66094a2019-09-30 16:19:18 -07003836 return_trace (false);
3837
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003838 const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
ariza188a0a42020-03-07 11:02:36 -08003839 if (!serialize_coverage_offsets (c, lookahead.iter (), this))
Qunxin Liub66094a2019-09-30 16:19:18 -07003840 return_trace (false);
Ebrahim Byagowiaca63902019-10-22 00:06:46 +03303841
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003842 const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
Behdad Esfahbod1a00ab62023-01-11 10:56:16 -07003843 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 -07003844
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003845 HBUINT16 *lookupCount = c->serializer->copy<HBUINT16> (lookup.len);
Qunxin Liu36ed56b2021-09-23 10:51:21 -07003846 if (!lookupCount) return_trace (false);
Qunxin Liu37379f82021-09-02 11:54:37 -07003847
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003848 unsigned count = serialize_lookuprecord_array (c->serializer, lookup.as_array (), lookup_map);
Qunxin Liu36ed56b2021-09-23 10:51:21 -07003849 return_trace (c->serializer->check_assign (*lookupCount, count, HB_SERIALIZE_ERROR_INT_OVERFLOW));
Behdad Esfahbod339d3602018-09-03 17:33:34 -07003850 }
3851
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303852 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03003853 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05003854 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003855 if (!backtrack.sanitize (c, this)) return_trace (false);
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003856 const auto &input = StructAfter<decltype (inputX)> (backtrack);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003857 if (!input.sanitize (c, this)) return_trace (false);
3858 if (!input.len) return_trace (false); /* To be consistent with Context. */
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003859 const auto &lookahead = StructAfter<decltype (lookaheadX)> (input);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003860 if (!lookahead.sanitize (c, this)) return_trace (false);
Behdad Esfahbod6d051f42022-07-08 14:08:51 -06003861 const auto &lookup = StructAfter<decltype (lookupX)> (lookahead);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003862 return_trace (lookup.sanitize (c));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04003863 }
3864
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04003865 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01003866 HBUINT16 format; /* Format identifier--format = 3 */
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06003867 Array16OfOffset16To<Coverage>
Behdad Esfahbod13ed4402009-05-18 02:14:37 -04003868 backtrack; /* Array of coverage tables
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003869 * in backtracking sequence, in glyph
3870 * sequence order */
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06003871 Array16OfOffset16To<Coverage>
Behdad Esfahbod13ed4402009-05-18 02:14:37 -04003872 inputX ; /* Array of coverage
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003873 * tables in input sequence, in glyph
3874 * sequence order */
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06003875 Array16OfOffset16To<Coverage>
Behdad Esfahbod13ed4402009-05-18 02:14:37 -04003876 lookaheadX; /* Array of coverage tables
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003877 * in lookahead sequence, in glyph
3878 * sequence order */
Behdad Esfahbod5639e252021-03-31 16:04:43 -06003879 Array16Of<LookupRecord>
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04003880 lookupX; /* Array of LookupRecords--in
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04003881 * design order) */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04003882 public:
Behdad Esfahbodbea34c72010-05-10 17:28:16 -04003883 DEFINE_SIZE_MIN (10);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003884};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003885
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04003886struct ChainContext
3887{
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -07003888 template <typename context_t, typename ...Ts>
Behdad Esfahbod83e3eab2019-05-07 20:58:43 -07003889 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04003890 {
Behdad Esfahbodbe8a87c2023-01-21 15:00:41 -07003891 if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
Behdad Esfahbod00f6a8e2014-12-12 20:36:49 -08003892 TRACE_DISPATCH (this, u.format);
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04003893 switch (u.format) {
Behdad Esfahbod6d555ce2021-11-02 00:18:22 -06003894 case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
3895 case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
3896 case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
Behdad Esfahbod5a9c7932022-07-22 21:33:15 -06003897#ifndef HB_NO_BEYOND_64K
Behdad Esfahbod1bf8fa22022-07-08 14:22:21 -06003898 case 4: return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...));
Behdad Esfahbodd1f58e52022-07-08 13:25:07 -06003899 case 5: return_trace (c->dispatch (u.format5, std::forward<Ts> (ds)...));
3900#endif
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003901 default:return_trace (c->default_return_value ());
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003902 }
3903 }
3904
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04003905 protected:
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003906 union {
Behdad Esfahboda90c5af2022-07-08 13:11:47 -06003907 HBUINT16 format; /* Format identifier */
Behdad Esfahbod0f13eb12022-07-08 13:43:33 -06003908 ChainContextFormat1_4<SmallTypes> format1;
Behdad Esfahboda90c5af2022-07-08 13:11:47 -06003909 ChainContextFormat2_5<SmallTypes> format2;
3910 ChainContextFormat3 format3;
Behdad Esfahbod5a9c7932022-07-22 21:33:15 -06003911#ifndef HB_NO_BEYOND_64K
Behdad Esfahbod1bf8fa22022-07-08 14:22:21 -06003912 ChainContextFormat1_4<MediumTypes> format4;
Behdad Esfahbodd1f58e52022-07-08 13:25:07 -06003913 ChainContextFormat2_5<MediumTypes> format5;
3914#endif
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003915 } u;
3916};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003917
3918
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003919template <typename T>
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003920struct ExtensionFormat1
3921{
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303922 unsigned int get_type () const { return extensionLookupType; }
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003923
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003924 template <typename X>
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303925 const X& get_subtable () const
Behdad Esfahbodad28f972021-03-31 12:49:14 -06003926 { return this + reinterpret_cast<const Offset32To<typename T::SubTable> &> (extensionOffset); }
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003927
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -07003928 template <typename context_t, typename ...Ts>
Behdad Esfahbod83e3eab2019-05-07 20:58:43 -07003929 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003930 {
Behdad Esfahbodbe8a87c2023-01-21 15:00:41 -07003931 if (unlikely (!c->may_dispatch (this, this))) return c->no_dispatch_return_value ();
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003932 TRACE_DISPATCH (this, format);
Behdad Esfahbod6d555ce2021-11-02 00:18:22 -06003933 return_trace (get_subtable<typename T::SubTable> ().dispatch (c, get_type (), std::forward<Ts> (ds)...));
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003934 }
3935
Qunxin Liu8200e482020-02-26 13:11:42 -08003936 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
3937 { dispatch (c); }
3938
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003939 /* This is called from may_dispatch() above with hb_sanitize_context_t. */
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303940 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03003941 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05003942 TRACE_SANITIZE (this);
Behdad Esfahbod949f6af2018-01-15 20:44:10 -05003943 return_trace (c->check_struct (this) &&
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07003944 extensionLookupType != T::SubTable::Extension);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04003945 }
3946
Garret Rieger08a49972020-10-06 13:02:12 -07003947 bool subset (hb_subset_context_t *c) const
3948 {
3949 TRACE_SUBSET (this);
3950
3951 auto *out = c->serializer->start_embed (this);
3952 if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
3953
3954 out->format = format;
3955 out->extensionLookupType = extensionLookupType;
3956
3957 const auto& src_offset =
Behdad Esfahbodad28f972021-03-31 12:49:14 -06003958 reinterpret_cast<const Offset32To<typename T::SubTable> &> (extensionOffset);
Garret Rieger08a49972020-10-06 13:02:12 -07003959 auto& dest_offset =
Behdad Esfahbodad28f972021-03-31 12:49:14 -06003960 reinterpret_cast<Offset32To<typename T::SubTable> &> (out->extensionOffset);
Garret Rieger08a49972020-10-06 13:02:12 -07003961
3962 return_trace (dest_offset.serialize_subset (c, src_offset, this, get_type ()));
3963 }
3964
Garret Rieger8d611a72022-07-22 22:49:40 +00003965 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01003966 HBUINT16 format; /* Format identifier. Set to 1. */
3967 HBUINT16 extensionLookupType; /* Lookup type of subtable referenced
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003968 * by ExtensionOffset (i.e. the
3969 * extension subtable). */
Behdad Esfahbodcd9bc732019-05-10 13:17:41 -07003970 Offset32 extensionOffset; /* Offset to the extension subtable,
Behdad Esfahbod81f2af42010-04-22 00:58:49 -04003971 * of lookup type subtable. */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04003972 public:
3973 DEFINE_SIZE_STATIC (8);
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003974};
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003975
Behdad Esfahbod653eeb22012-11-23 16:57:36 -05003976template <typename T>
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003977struct Extension
3978{
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303979 unsigned int get_type () const
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003980 {
3981 switch (u.format) {
Behdad Esfahboddacebca2010-05-10 19:45:41 -04003982 case 1: return u.format1.get_type ();
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003983 default:return 0;
3984 }
3985 }
Behdad Esfahbod7dddd4e2012-11-23 17:04:55 -05003986 template <typename X>
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303987 const X& get_subtable () const
Behdad Esfahbod7dddd4e2012-11-23 17:04:55 -05003988 {
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003989 switch (u.format) {
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07003990 case 1: return u.format1.template get_subtable<typename T::SubTable> ();
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04303991 default:return Null (typename T::SubTable);
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003992 }
Behdad Esfahbod7dddd4e2012-11-23 17:04:55 -05003993 }
3994
Garret Rieger08a49972020-10-06 13:02:12 -07003995 // Specialization of dispatch for subset. dispatch() normally just
3996 // dispatches to the sub table this points too, but for subset
3997 // we need to run subset on this subtable too.
3998 template <typename ...Ts>
3999 typename hb_subset_context_t::return_t dispatch (hb_subset_context_t *c, Ts&&... ds) const
4000 {
4001 switch (u.format) {
4002 case 1: return u.format1.subset (c);
4003 default: return c->default_return_value ();
4004 }
4005 }
4006
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -07004007 template <typename context_t, typename ...Ts>
Behdad Esfahbod83e3eab2019-05-07 20:58:43 -07004008 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
Behdad Esfahbod653eeb22012-11-23 16:57:36 -05004009 {
Behdad Esfahbodbe8a87c2023-01-21 15:00:41 -07004010 if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
Behdad Esfahbod095a1252015-02-19 10:29:41 +03004011 TRACE_DISPATCH (this, u.format);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04004012 switch (u.format) {
Behdad Esfahbod6d555ce2021-11-02 00:18:22 -06004013 case 1: return_trace (u.format1.dispatch (c, std::forward<Ts> (ds)...));
Behdad Esfahbodb4715902015-09-29 14:57:02 +01004014 default:return_trace (c->default_return_value ());
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04004015 }
4016 }
4017
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04004018 protected:
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04004019 union {
Behdad Esfahbod6b191782018-01-10 03:07:30 +01004020 HBUINT16 format; /* Format identifier */
Behdad Esfahbod095a1252015-02-19 10:29:41 +03004021 ExtensionFormat1<T> format1;
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04004022 } u;
4023};
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04004024
4025
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04004026/*
4027 * GSUB/GPOS Common
4028 */
4029
Behdad Esfahbod97e59132018-10-10 11:41:05 -04004030struct hb_ot_layout_lookup_accelerator_t
4031{
4032 template <typename TLookup>
Behdad Esfahbod7a4bd972023-01-31 14:59:39 -07004033 static hb_ot_layout_lookup_accelerator_t *create (const TLookup &lookup)
Behdad Esfahbod97e59132018-10-10 11:41:05 -04004034 {
Behdad Esfahbod83353f12023-01-31 14:32:14 -07004035 unsigned count = lookup.get_subtable_count ();
Behdad Esfahbod83353f12023-01-31 14:32:14 -07004036
Behdad Esfahbod7a4bd972023-01-31 14:59:39 -07004037 unsigned size = sizeof (hb_ot_layout_lookup_accelerator_t) -
4038 HB_VAR_ARRAY * sizeof (hb_accelerate_subtables_context_t::hb_applicable_t) +
4039 count * sizeof (hb_accelerate_subtables_context_t::hb_applicable_t);
4040
Behdad Esfahbodd18fd3f2023-01-31 16:28:49 -07004041 /* The following is a calloc because when we are collecting subtables,
4042 * some of them might be invalid and hence not collect; as a result,
4043 * we might not fill in all the count entries of the subtables array.
4044 * Zeroing it allows the set digest to gatekeep it without having to
4045 * initialize it further. */
Behdad Esfahbod7a4bd972023-01-31 14:59:39 -07004046 auto *thiz = (hb_ot_layout_lookup_accelerator_t *) hb_calloc (1, size);
4047 if (unlikely (!thiz))
4048 return nullptr;
4049
4050 hb_accelerate_subtables_context_t c_accelerate_subtables (thiz->subtables);
Behdad Esfahbodf9b643f2022-06-04 07:29:40 -06004051 lookup.dispatch (&c_accelerate_subtables);
Behdad Esfahbod39820af2022-06-07 10:18:38 -06004052
Behdad Esfahbod7a4bd972023-01-31 14:59:39 -07004053 thiz->digest.init ();
4054 for (auto& subtable : hb_iter (thiz->subtables, count))
4055 thiz->digest.add (subtable.digest);
Behdad Esfahboda053b842022-11-16 14:39:25 -07004056
Behdad Esfahbod39820af2022-06-07 10:18:38 -06004057#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
Behdad Esfahbod7a4bd972023-01-31 14:59:39 -07004058 thiz->cache_user_idx = c_accelerate_subtables.cache_user_idx;
Behdad Esfahbod83353f12023-01-31 14:32:14 -07004059 for (unsigned i = 0; i < count; i++)
Behdad Esfahbod7a4bd972023-01-31 14:59:39 -07004060 if (i != thiz->cache_user_idx)
4061 thiz->subtables[i].apply_cached_func = thiz->subtables[i].apply_func;
Behdad Esfahbod39820af2022-06-07 10:18:38 -06004062#endif
Behdad Esfahbod7a4bd972023-01-31 14:59:39 -07004063
4064 return thiz;
Behdad Esfahbod97e59132018-10-10 11:41:05 -04004065 }
Behdad Esfahbod97e59132018-10-10 11:41:05 -04004066
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03304067 bool may_have (hb_codepoint_t g) const
Behdad Esfahbod97e59132018-10-10 11:41:05 -04004068 { return digest.may_have (g); }
4069
Behdad Esfahbod83353f12023-01-31 14:32:14 -07004070 bool apply (hb_ot_apply_context_t *c, unsigned subtables_count, bool use_cache) const
Behdad Esfahbode78549e2018-10-10 11:54:48 -04004071 {
Behdad Esfahbod39820af2022-06-07 10:18:38 -06004072#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06004073 if (use_cache)
4074 {
Behdad Esfahbodb4d0d162022-11-18 14:47:33 -07004075 return
Behdad Esfahbod83353f12023-01-31 14:32:14 -07004076 + hb_iter (hb_iter (subtables, subtables_count))
Behdad Esfahbodb4d0d162022-11-18 14:47:33 -07004077 | hb_map ([&c] (const hb_accelerate_subtables_context_t::hb_applicable_t &_) { return _.apply_cached (c); })
4078 | hb_any
4079 ;
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06004080 }
4081 else
Behdad Esfahbod39820af2022-06-07 10:18:38 -06004082#endif
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06004083 {
Behdad Esfahbodb4d0d162022-11-18 14:47:33 -07004084 return
Behdad Esfahbod83353f12023-01-31 14:32:14 -07004085 + hb_iter (hb_iter (subtables, subtables_count))
Behdad Esfahbodb4d0d162022-11-18 14:47:33 -07004086 | hb_map ([&c] (const hb_accelerate_subtables_context_t::hb_applicable_t &_) { return _.apply (c); })
4087 | hb_any
4088 ;
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06004089 }
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03304090 return false;
Behdad Esfahbode78549e2018-10-10 11:54:48 -04004091 }
4092
Behdad Esfahbodbba57652022-11-18 14:52:17 -07004093 bool cache_enter (hb_ot_apply_context_t *c) const
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06004094 {
Behdad Esfahbod39820af2022-06-07 10:18:38 -06004095#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06004096 return cache_user_idx != (unsigned) -1 &&
4097 subtables[cache_user_idx].cache_enter (c);
Behdad Esfahbod39820af2022-06-07 10:18:38 -06004098#else
4099 return false;
4100#endif
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06004101 }
Behdad Esfahbodbba57652022-11-18 14:52:17 -07004102 void cache_leave (hb_ot_apply_context_t *c) const
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06004103 {
Behdad Esfahbod39820af2022-06-07 10:18:38 -06004104#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06004105 subtables[cache_user_idx].cache_leave (c);
Behdad Esfahbod39820af2022-06-07 10:18:38 -06004106#endif
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06004107 }
4108
4109
Behdad Esfahbod97e59132018-10-10 11:41:05 -04004110 hb_set_digest_t digest;
Behdad Esfahbod15b6c322022-11-16 15:59:13 -07004111 private:
Behdad Esfahbod39820af2022-06-07 10:18:38 -06004112#ifndef HB_NO_OT_LAYOUT_LOOKUP_CACHE
Behdad Esfahbodb96622d2022-06-05 02:45:41 -06004113 unsigned cache_user_idx = (unsigned) -1;
Behdad Esfahbod39820af2022-06-07 10:18:38 -06004114#endif
Behdad Esfahbod7a4bd972023-01-31 14:59:39 -07004115 hb_accelerate_subtables_context_t::hb_applicable_t subtables[HB_VAR_ARRAY];
Behdad Esfahbod97e59132018-10-10 11:41:05 -04004116};
4117
Behdad Esfahbod5fd0a3f2022-07-11 13:10:04 -06004118template <typename Types>
4119struct GSUBGPOSVersion1_2
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04004120{
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004121 friend struct GSUBGPOS;
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04004122
Garret Rieger8d611a72022-07-22 22:49:40 +00004123 protected:
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004124 FixedVersion<>version; /* Version of the GSUB/GPOS table--initially set
4125 * to 0x00010000u */
Behdad Esfahbod5fd0a3f2022-07-11 13:10:04 -06004126 typename Types:: template OffsetTo<ScriptList>
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004127 scriptList; /* ScriptList table */
Behdad Esfahbod5fd0a3f2022-07-11 13:10:04 -06004128 typename Types::template OffsetTo<FeatureList>
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004129 featureList; /* FeatureList table */
Behdad Esfahbod5fd0a3f2022-07-11 13:10:04 -06004130 typename Types::template OffsetTo<LookupList<Types>>
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004131 lookupList; /* LookupList table */
4132 Offset32To<FeatureVariations>
4133 featureVars; /* Offset to Feature Variations
4134 table--from beginning of table
4135 * (may be NULL). Introduced
4136 * in version 0x00010001. */
4137 public:
Behdad Esfahbod5fd0a3f2022-07-11 13:10:04 -06004138 DEFINE_SIZE_MIN (4 + 3 * Types::size);
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04004139
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004140 unsigned int get_size () const
Behdad Esfahboda8498732019-06-19 19:26:22 -07004141 {
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004142 return min_size +
4143 (version.to_int () >= 0x00010001u ? featureVars.static_size : 0);
Qunxin Liu0b39c482019-10-22 16:00:43 -07004144 }
4145
Garret Rieger8d611a72022-07-22 22:49:40 +00004146 const typename Types::template OffsetTo<LookupList<Types>>* get_lookup_list_offset () const
4147 {
4148 return &lookupList;
4149 }
4150
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07004151 template <typename TLookup>
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004152 bool sanitize (hb_sanitize_context_t *c) const
Qunxin Liu973c47f2020-06-11 11:27:57 -07004153 {
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004154 TRACE_SANITIZE (this);
Behdad Esfahbod99f017f2022-07-11 13:13:19 -06004155 typedef List16OfOffsetTo<TLookup, typename Types::HBUINT> TLookupList;
4156 if (unlikely (!(scriptList.sanitize (c, this) &&
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004157 featureList.sanitize (c, this) &&
Behdad Esfahbod9ef9fc02022-07-11 13:29:23 -06004158 reinterpret_cast<const typename Types::template OffsetTo<TLookupList> &> (lookupList).sanitize (c, this))))
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004159 return_trace (false);
Qunxin Liu973c47f2020-06-11 11:27:57 -07004160
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004161#ifndef HB_NO_VAR
4162 if (unlikely (!(version.to_int () < 0x00010001u || featureVars.sanitize (c, this))))
4163 return_trace (false);
4164#endif
Behdad Esfahbod4119f732022-06-08 06:34:48 -06004165
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004166 return_trace (true);
Qunxin Liu56ca4352021-01-28 15:21:26 -08004167 }
4168
Qunxin Liu973c47f2020-06-11 11:27:57 -07004169 template <typename TLookup>
Qunxin Liue565d1f2019-11-01 10:21:36 -07004170 bool subset (hb_subset_layout_context_t *c) const
Behdad Esfahbodbfa72a92018-09-01 18:34:50 -07004171 {
4172 TRACE_SUBSET (this);
Garret Riegerea1ee0d2023-01-14 00:23:53 +00004173
4174 auto *out = c->subset_context->serializer->start_embed (this);
4175 if (unlikely (!c->subset_context->serializer->extend_min (out))) return_trace (false);
4176
4177 out->version = version;
Behdad Esfahbod1b6d0c42018-12-13 18:10:48 -05004178
Behdad Esfahbod9ef9fc02022-07-11 13:29:23 -06004179 typedef LookupOffsetList<TLookup, typename Types::HBUINT> TLookupList;
4180 reinterpret_cast<typename Types::template OffsetTo<TLookupList> &> (out->lookupList)
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04304181 .serialize_subset (c->subset_context,
Behdad Esfahbod9ef9fc02022-07-11 13:29:23 -06004182 reinterpret_cast<const typename Types::template OffsetTo<TLookupList> &> (lookupList),
Qunxin Liue565d1f2019-11-01 10:21:36 -07004183 this,
Qunxin Liue565d1f2019-11-01 10:21:36 -07004184 c);
4185
Behdad Esfahbod9ef9fc02022-07-11 13:29:23 -06004186 reinterpret_cast<typename Types::template OffsetTo<RecordListOfFeature> &> (out->featureList)
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04304187 .serialize_subset (c->subset_context,
Behdad Esfahbod9ef9fc02022-07-11 13:29:23 -06004188 reinterpret_cast<const typename Types::template OffsetTo<RecordListOfFeature> &> (featureList),
Qunxin Liue565d1f2019-11-01 10:21:36 -07004189 this,
Qunxin Liue565d1f2019-11-01 10:21:36 -07004190 c);
4191
4192 out->scriptList.serialize_subset (c->subset_context,
4193 scriptList,
4194 this,
Qunxin Liue565d1f2019-11-01 10:21:36 -07004195 c);
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07004196
Behdad Esfahboda8498732019-06-19 19:26:22 -07004197#ifndef HB_NO_VAR
Behdad Esfahbodbfa72a92018-09-01 18:34:50 -07004198 if (version.to_int () >= 0x00010001u)
Qunxin Liue565d1f2019-11-01 10:21:36 -07004199 {
Garret Riegerea1ee0d2023-01-14 00:23:53 +00004200 auto snapshot = c->subset_context->serializer->snapshot ();
4201 if (!c->subset_context->serializer->extend_min (&out->featureVars))
4202 return_trace (false);
4203
4204 // TODO(qxliu76): the current implementation doesn't correctly handle feature variations
4205 // that are dropped by instancing when the associated conditions don't trigger.
4206 // Since partial instancing isn't yet supported this isn't an issue yet but will
4207 // need to be fixed for partial instancing.
4208
4209
4210
4211 // if all axes are pinned all feature vars are dropped.
4212 bool ret = !c->subset_context->plan->all_axes_pinned
4213 && out->featureVars.serialize_subset (c->subset_context, featureVars, this, c);
Behdad Esfahbod99f017f2022-07-11 13:13:19 -06004214 if (!ret && version.major == 1)
Qunxin Liue565d1f2019-11-01 10:21:36 -07004215 {
Garret Riegerea1ee0d2023-01-14 00:23:53 +00004216 c->subset_context->serializer->revert (snapshot);
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04304217 out->version.major = 1;
4218 out->version.minor = 0;
Qunxin Liue565d1f2019-11-01 10:21:36 -07004219 }
4220 }
Behdad Esfahboda8498732019-06-19 19:26:22 -07004221#endif
Behdad Esfahbod1b6d0c42018-12-13 18:10:48 -05004222
Behdad Esfahbodbfa72a92018-09-01 18:34:50 -07004223 return_trace (true);
4224 }
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004225};
4226
4227struct GSUBGPOS
4228{
4229 unsigned int get_size () const
4230 {
4231 switch (u.version.major) {
4232 case 1: return u.version1.get_size ();
Behdad Esfahbod5a9c7932022-07-22 21:33:15 -06004233#ifndef HB_NO_BEYOND_64K
Behdad Esfahbod99f017f2022-07-11 13:13:19 -06004234 case 2: return u.version2.get_size ();
4235#endif
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004236 default: return u.version.static_size;
4237 }
4238 }
4239
4240 template <typename TLookup>
4241 bool sanitize (hb_sanitize_context_t *c) const
4242 {
4243 TRACE_SANITIZE (this);
4244 if (unlikely (!u.version.sanitize (c))) return_trace (false);
4245 switch (u.version.major) {
4246 case 1: return_trace (u.version1.sanitize<TLookup> (c));
Behdad Esfahbod5a9c7932022-07-22 21:33:15 -06004247#ifndef HB_NO_BEYOND_64K
Behdad Esfahbod99f017f2022-07-11 13:13:19 -06004248 case 2: return_trace (u.version2.sanitize<TLookup> (c));
4249#endif
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004250 default: return_trace (true);
4251 }
4252 }
4253
4254 template <typename TLookup>
4255 bool subset (hb_subset_layout_context_t *c) const
4256 {
4257 switch (u.version.major) {
4258 case 1: return u.version1.subset<TLookup> (c);
Behdad Esfahbod5a9c7932022-07-22 21:33:15 -06004259#ifndef HB_NO_BEYOND_64K
Behdad Esfahbod99f017f2022-07-11 13:13:19 -06004260 case 2: return u.version2.subset<TLookup> (c);
4261#endif
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004262 default: return false;
4263 }
4264 }
4265
4266 const ScriptList &get_script_list () const
4267 {
4268 switch (u.version.major) {
4269 case 1: return this+u.version1.scriptList;
Behdad Esfahbod5a9c7932022-07-22 21:33:15 -06004270#ifndef HB_NO_BEYOND_64K
Behdad Esfahbod99f017f2022-07-11 13:13:19 -06004271 case 2: return this+u.version2.scriptList;
4272#endif
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004273 default: return Null (ScriptList);
4274 }
4275 }
4276 const FeatureList &get_feature_list () const
4277 {
4278 switch (u.version.major) {
4279 case 1: return this+u.version1.featureList;
Behdad Esfahbod5a9c7932022-07-22 21:33:15 -06004280#ifndef HB_NO_BEYOND_64K
Behdad Esfahbod99f017f2022-07-11 13:13:19 -06004281 case 2: return this+u.version2.featureList;
4282#endif
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004283 default: return Null (FeatureList);
4284 }
4285 }
4286 unsigned int get_lookup_count () const
4287 {
4288 switch (u.version.major) {
4289 case 1: return (this+u.version1.lookupList).len;
Behdad Esfahbod5a9c7932022-07-22 21:33:15 -06004290#ifndef HB_NO_BEYOND_64K
Behdad Esfahbod99f017f2022-07-11 13:13:19 -06004291 case 2: return (this+u.version2.lookupList).len;
4292#endif
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004293 default: return 0;
4294 }
4295 }
4296 const Lookup& get_lookup (unsigned int i) const
4297 {
4298 switch (u.version.major) {
4299 case 1: return (this+u.version1.lookupList)[i];
Behdad Esfahbod5a9c7932022-07-22 21:33:15 -06004300#ifndef HB_NO_BEYOND_64K
Behdad Esfahbod99f017f2022-07-11 13:13:19 -06004301 case 2: return (this+u.version2.lookupList)[i];
4302#endif
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004303 default: return Null (Lookup);
4304 }
4305 }
4306 const FeatureVariations &get_feature_variations () const
4307 {
4308 switch (u.version.major) {
4309 case 1: return (u.version.to_int () >= 0x00010001u ? this+u.version1.featureVars : Null (FeatureVariations));
Behdad Esfahbod5a9c7932022-07-22 21:33:15 -06004310#ifndef HB_NO_BEYOND_64K
Behdad Esfahbod99f017f2022-07-11 13:13:19 -06004311 case 2: return this+u.version2.featureVars;
4312#endif
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004313 default: return Null (FeatureVariations);
4314 }
4315 }
4316
4317 bool has_data () const { return u.version.to_int (); }
4318 unsigned int get_script_count () const
4319 { return get_script_list ().len; }
4320 const Tag& get_script_tag (unsigned int i) const
4321 { return get_script_list ().get_tag (i); }
4322 unsigned int get_script_tags (unsigned int start_offset,
4323 unsigned int *script_count /* IN/OUT */,
4324 hb_tag_t *script_tags /* OUT */) const
4325 { return get_script_list ().get_tags (start_offset, script_count, script_tags); }
4326 const Script& get_script (unsigned int i) const
4327 { return get_script_list ()[i]; }
4328 bool find_script_index (hb_tag_t tag, unsigned int *index) const
4329 { return get_script_list ().find_index (tag, index); }
4330
4331 unsigned int get_feature_count () const
4332 { return get_feature_list ().len; }
4333 hb_tag_t get_feature_tag (unsigned int i) const
4334 { return i == Index::NOT_FOUND_INDEX ? HB_TAG_NONE : get_feature_list ().get_tag (i); }
4335 unsigned int get_feature_tags (unsigned int start_offset,
4336 unsigned int *feature_count /* IN/OUT */,
4337 hb_tag_t *feature_tags /* OUT */) const
4338 { return get_feature_list ().get_tags (start_offset, feature_count, feature_tags); }
4339 const Feature& get_feature (unsigned int i) const
4340 { return get_feature_list ()[i]; }
4341 bool find_feature_index (hb_tag_t tag, unsigned int *index) const
4342 { return get_feature_list ().find_index (tag, index); }
4343
4344 bool find_variations_index (const int *coords, unsigned int num_coords,
4345 unsigned int *index) const
4346 {
4347#ifdef HB_NO_VAR
4348 *index = FeatureVariations::NOT_FOUND_INDEX;
4349 return false;
4350#endif
4351 return get_feature_variations ().find_index (coords, num_coords, index);
4352 }
4353 const Feature& get_feature_variation (unsigned int feature_index,
4354 unsigned int variations_index) const
4355 {
4356#ifndef HB_NO_VAR
4357 if (FeatureVariations::NOT_FOUND_INDEX != variations_index &&
4358 u.version.to_int () >= 0x00010001u)
4359 {
4360 const Feature *feature = get_feature_variations ().find_substitute (variations_index,
4361 feature_index);
4362 if (feature)
4363 return *feature;
4364 }
4365#endif
4366 return get_feature (feature_index);
4367 }
4368
4369 void feature_variation_collect_lookups (const hb_set_t *feature_indexes,
Qunxin Liuf4813e32022-09-09 10:34:09 -07004370 const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004371 hb_set_t *lookup_indexes /* OUT */) const
4372 {
4373#ifndef HB_NO_VAR
Qunxin Liuf4813e32022-09-09 10:34:09 -07004374 get_feature_variations ().collect_lookups (feature_indexes, feature_substitutes_map, lookup_indexes);
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004375#endif
4376 }
4377
Qunxin Liu64e2f2f2022-09-09 09:36:19 -07004378#ifndef HB_NO_VAR
4379 void collect_feature_substitutes_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const
4380 { get_feature_variations ().collect_feature_substitutes_with_variations (c); }
4381#endif
4382
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004383 template <typename TLookup>
4384 void closure_lookups (hb_face_t *face,
4385 const hb_set_t *glyphs,
4386 hb_set_t *lookup_indexes /* IN/OUT */) const
4387 {
4388 hb_set_t visited_lookups, inactive_lookups;
Behdad Esfahbodbba57652022-11-18 14:52:17 -07004389 hb_closure_lookups_context_t c (face, glyphs, &visited_lookups, &inactive_lookups);
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004390
4391 c.set_recurse_func (TLookup::template dispatch_recurse_func<hb_closure_lookups_context_t>);
4392
Behdad Esfahbod16100082022-11-16 20:02:36 -07004393 for (unsigned lookup_index : *lookup_indexes)
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004394 reinterpret_cast<const TLookup &> (get_lookup (lookup_index)).closure_lookups (&c, lookup_index);
4395
4396 hb_set_union (lookup_indexes, &visited_lookups);
4397 hb_set_subtract (lookup_indexes, &inactive_lookups);
4398 }
4399
4400 void prune_langsys (const hb_map_t *duplicate_feature_map,
Qunxin Liua3e6dbb2022-09-02 13:53:10 -07004401 const hb_set_t *layout_scripts,
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004402 hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *script_langsys_map,
4403 hb_set_t *new_feature_indexes /* OUT */) const
4404 {
4405 hb_prune_langsys_context_t c (this, script_langsys_map, duplicate_feature_map, new_feature_indexes);
4406
4407 unsigned count = get_script_count ();
4408 for (unsigned script_index = 0; script_index < count; script_index++)
4409 {
Qunxin Liua3e6dbb2022-09-02 13:53:10 -07004410 const Tag& tag = get_script_tag (script_index);
4411 if (!layout_scripts->has (tag)) continue;
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004412 const Script& s = get_script (script_index);
4413 s.prune_langsys (&c, script_index);
4414 }
4415 }
4416
Garret Rieger718bf5a2020-09-29 13:16:01 -07004417 void prune_features (const hb_map_t *lookup_indices, /* IN */
Qunxin Liuf4813e32022-09-09 10:34:09 -07004418 const hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map, /* IN */
4419 const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map, /* IN */
Qunxin Liu56ca4352021-01-28 15:21:26 -08004420 hb_set_t *feature_indices /* IN/OUT */) const
Qunxin Liu8ffc9ad2019-10-31 15:59:02 -07004421 {
Garret Rieger718bf5a2020-09-29 13:16:01 -07004422#ifndef HB_NO_VAR
4423 // This is the set of feature indices which have alternate versions defined
4424 // if the FeatureVariation's table and the alternate version(s) intersect the
4425 // set of lookup indices.
4426 hb_set_t alternate_feature_indices;
Qunxin Liuf4813e32022-09-09 10:34:09 -07004427 get_feature_variations ().closure_features (lookup_indices, feature_record_cond_idx_map, &alternate_feature_indices);
Behdad Esfahbodfad452b2021-08-16 20:48:24 -06004428 if (unlikely (alternate_feature_indices.in_error()))
4429 {
4430 feature_indices->err ();
Garret Rieger718bf5a2020-09-29 13:16:01 -07004431 return;
4432 }
4433#endif
4434
Behdad Esfahbod01f961a2022-11-18 15:47:17 -07004435 for (unsigned i : hb_iter (feature_indices))
Qunxin Liu8ffc9ad2019-10-31 15:59:02 -07004436 {
Garret Riegerc35d7862021-04-01 14:32:38 -07004437 hb_tag_t tag = get_feature_tag (i);
4438 if (tag == HB_TAG ('p', 'r', 'e', 'f'))
4439 // Note: Never ever drop feature 'pref', even if it's empty.
4440 // HarfBuzz chooses shaper for Khmer based on presence of this
4441 // feature. See thread at:
4442 // http://lists.freedesktop.org/archives/harfbuzz/2012-November/002660.html
4443 continue;
Garret Rieger718bf5a2020-09-29 13:16:01 -07004444
Qunxin Liuca418ca2021-11-17 16:42:08 -08004445
Qunxin Liuf4813e32022-09-09 10:34:09 -07004446 const Feature *f = &(get_feature (i));
4447 const Feature** p = nullptr;
4448 if (feature_substitutes_map->has (i, &p))
4449 f = *p;
4450
4451 if (!f->featureParams.is_null () &&
Qunxin Liuca418ca2021-11-17 16:42:08 -08004452 tag == HB_TAG ('s', 'i', 'z', 'e'))
4453 continue;
4454
Qunxin Liuf4813e32022-09-09 10:34:09 -07004455 if (!f->intersects_lookup_indexes (lookup_indices)
Behdad Esfahbod29025292021-03-02 15:05:22 -07004456#ifndef HB_NO_VAR
4457 && !alternate_feature_indices.has (i)
4458#endif
4459 )
4460 feature_indices->del (i);
Qunxin Liu8ffc9ad2019-10-31 15:59:02 -07004461 }
Qunxin Liu8ffc9ad2019-10-31 15:59:02 -07004462 }
4463
Qunxin Liu125450d2023-03-13 15:43:29 -07004464 void collect_name_ids (const hb_map_t *feature_index_map,
4465 hb_set_t *nameids_to_retain /* OUT */) const
4466 {
4467 unsigned count = get_feature_count ();
4468 for (unsigned i = 0 ; i < count; i++)
4469 {
4470 if (!feature_index_map->has (i)) continue;
4471 hb_tag_t tag = get_feature_tag (i);
4472 get_feature (i).collect_name_ids (tag, nameids_to_retain);
4473 }
4474 }
4475
Behdad Esfahbod963413f2018-08-26 00:47:55 -07004476 template <typename T>
4477 struct accelerator_t
4478 {
Behdad Esfahbodac1bb3e2022-01-20 11:47:17 -07004479 accelerator_t (hb_face_t *face)
Behdad Esfahbod963413f2018-08-26 00:47:55 -07004480 {
Ebrahim Byagowiba22df32020-03-10 10:42:20 +03304481 this->table = hb_sanitize_context_t ().reference_table<T> (face);
Behdad Esfahbod56719472020-06-05 12:57:23 -07004482 if (unlikely (this->table->is_blocklisted (this->table.get_blob (), face)))
Behdad Esfahbod574d8882018-11-25 16:51:22 -05004483 {
4484 hb_blob_destroy (this->table.get_blob ());
4485 this->table = hb_blob_get_empty ();
4486 }
Behdad Esfahbod963413f2018-08-26 00:47:55 -07004487
Behdad Esfahbodb9291002018-08-26 01:15:47 -07004488 this->lookup_count = table->get_lookup_count ();
Behdad Esfahbod963413f2018-08-26 00:47:55 -07004489
Behdad Esfahbod7a4bd972023-01-31 14:59:39 -07004490 this->accels = (hb_atomic_ptr_t<hb_ot_layout_lookup_accelerator_t> *) hb_calloc (this->lookup_count, sizeof (*accels));
Behdad Esfahbod963413f2018-08-26 00:47:55 -07004491 if (unlikely (!this->accels))
Dominik Röttschesa5f6f862020-10-23 14:25:05 +03004492 {
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03304493 this->lookup_count = 0;
Behdad Esfahbod53806e52020-11-25 11:51:37 -07004494 this->table.destroy ();
Dominik Röttschesa5f6f862020-10-23 14:25:05 +03004495 this->table = hb_blob_get_empty ();
4496 }
Behdad Esfahbod963413f2018-08-26 00:47:55 -07004497 }
Behdad Esfahbodac1bb3e2022-01-20 11:47:17 -07004498 ~accelerator_t ()
Behdad Esfahbod963413f2018-08-26 00:47:55 -07004499 {
Behdad Esfahbodb9291002018-08-26 01:15:47 -07004500 for (unsigned int i = 0; i < this->lookup_count; i++)
Behdad Esfahbod7a4bd972023-01-31 14:59:39 -07004501 hb_free (this->accels[i]);
Behdad Esfahbod2337f0d2021-07-08 10:58:50 -06004502 hb_free (this->accels);
Behdad Esfahbodda6aa3b2018-11-11 11:40:57 -05004503 this->table.destroy ();
Behdad Esfahbod963413f2018-08-26 00:47:55 -07004504 }
4505
Behdad Esfahbod7a4bd972023-01-31 14:59:39 -07004506 hb_ot_layout_lookup_accelerator_t *get_accel (unsigned lookup_index) const
4507 {
4508 if (unlikely (lookup_index >= lookup_count)) return nullptr;
4509
4510 retry:
4511 auto *accel = accels[lookup_index].get_acquire ();
4512 if (unlikely (!accel))
4513 {
4514 accel = hb_ot_layout_lookup_accelerator_t::create (table->get_lookup (lookup_index));
4515 if (unlikely (!accel))
4516 return nullptr;
4517
4518 if (unlikely (!accels[lookup_index].cmpexch (nullptr, accel)))
4519 {
4520 hb_free (accel);
4521 goto retry;
4522 }
4523 }
4524
4525 return accel;
4526 }
4527
Behdad Esfahbod5d0078a2018-11-10 23:52:15 -05004528 hb_blob_ptr_t<T> table;
Behdad Esfahbodb9291002018-08-26 01:15:47 -07004529 unsigned int lookup_count;
Behdad Esfahbod7a4bd972023-01-31 14:59:39 -07004530 hb_atomic_ptr_t<hb_ot_layout_lookup_accelerator_t> *accels;
Behdad Esfahbod963413f2018-08-26 00:47:55 -07004531 };
4532
Behdad Esfahbod212aba62009-05-24 00:50:27 -04004533 protected:
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004534 union {
Behdad Esfahbod5fd0a3f2022-07-11 13:10:04 -06004535 FixedVersion<> version; /* Version identifier */
4536 GSUBGPOSVersion1_2<SmallTypes> version1;
Behdad Esfahbod5a9c7932022-07-22 21:33:15 -06004537#ifndef HB_NO_BEYOND_64K
Behdad Esfahbod99f017f2022-07-11 13:13:19 -06004538 GSUBGPOSVersion1_2<MediumTypes> version2;
4539#endif
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004540 } u;
Behdad Esfahbodb3651232010-05-10 16:57:29 -04004541 public:
Behdad Esfahbod6d0e3e62022-07-11 12:28:53 -06004542 DEFINE_SIZE_MIN (4);
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04004543};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04004544
Behdad Esfahbod6f20f722009-05-17 20:28:01 -04004545
Behdad Esfahbod7d52e662012-11-16 18:49:54 -08004546} /* namespace OT */
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -04004547
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04004548
Behdad Esfahbodc77ae402018-08-25 22:36:36 -07004549#endif /* HB_OT_LAYOUT_GSUBGPOS_HH */