blob: 389d7af8fdd390d6957cb3bcce47857caa660384 [file] [log] [blame]
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001/*
Behdad Esfahbod2409d5f2011-04-21 17:14:28 -04002 * Copyright © 2007,2008,2009,2010 Red Hat, Inc.
Behdad Esfahbod5b93e8d2012-04-23 22:26:13 -04003 * Copyright © 2010,2012 Google, Inc.
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04004 *
Behdad Esfahbodc755cb32010-04-22 00:11:43 -04005 * This is part of HarfBuzz, a text shaping library.
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04006 *
7 * Permission is hereby granted, without written agreement and without
8 * license or royalty fees, to use, copy, modify, and distribute this
9 * software and its documentation for any purpose, provided that the
10 * above copyright notice and the following two paragraphs appear in
11 * all copies of this software.
12 *
13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
17 * DAMAGE.
18 *
19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24 *
25 * Red Hat Author(s): Behdad Esfahbod
Behdad Esfahbod98370e82010-10-27 17:39:01 -040026 * Google Author(s): Behdad Esfahbod
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -040027 */
28
Behdad Esfahbodc77ae402018-08-25 22:36:36 -070029#ifndef HB_OT_LAYOUT_GSUBGPOS_HH
30#define HB_OT_LAYOUT_GSUBGPOS_HH
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -040031
Behdad Esfahbodc77ae402018-08-25 22:36:36 -070032#include "hb.hh"
33#include "hb-buffer.hh"
34#include "hb-map.hh"
Behdad Esfahbodc77ae402018-08-25 22:36:36 -070035#include "hb-set.hh"
Behdad Esfahbod71c9f842018-09-10 22:37:19 +020036#include "hb-ot-map.hh"
Behdad Esfahbodb9291002018-08-26 01:15:47 -070037#include "hb-ot-layout-common.hh"
38#include "hb-ot-layout-gdef-table.hh"
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -040039
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -040040
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -040041namespace OT {
42
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -040043
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -070044struct hb_intersects_context_t :
Behdad Esfahbod8d0a90a2020-06-18 16:53:54 -070045 hb_dispatch_context_t<hb_intersects_context_t, bool>
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -070046{
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -070047 template <typename T>
Behdad Esfahbodc14efb82019-05-05 09:54:58 -070048 return_t dispatch (const T &obj) { return obj.intersects (this->glyphs); }
Ebrahim Byagowie4120082018-12-17 21:31:01 +033049 static return_t default_return_value () { return false; }
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -070050 bool stop_sublookup_iteration (return_t r) const { return r; }
51
52 const hb_set_t *glyphs;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -070053
54 hb_intersects_context_t (const hb_set_t *glyphs_) :
Behdad Esfahbod70d66962020-06-18 17:09:39 -070055 glyphs (glyphs_) {}
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -070056};
57
Behdad Esfahbod77a1a2b2015-10-09 12:20:58 -040058struct hb_closure_context_t :
Behdad Esfahbod25aec022020-06-18 16:58:01 -070059 hb_dispatch_context_t<hb_closure_context_t>
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -040060{
Behdad Esfahbod44fc2372012-11-21 23:33:13 -050061 typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
62 template <typename T>
Behdad Esfahbod7df3ecf2019-05-10 20:43:26 -070063 return_t dispatch (const T &obj) { obj.closure (this); return hb_empty_t (); }
64 static return_t default_return_value () { return hb_empty_t (); }
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -070065 void recurse (unsigned int lookup_index)
Behdad Esfahbod44fc2372012-11-21 23:33:13 -050066 {
Behdad Esfahbod9b346772012-11-23 17:55:40 -050067 if (unlikely (nesting_level_left == 0 || !recurse_func))
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -070068 return;
Behdad Esfahbod44fc2372012-11-21 23:33:13 -050069
70 nesting_level_left--;
71 recurse_func (this, lookup_index);
72 nesting_level_left++;
Behdad Esfahbod44fc2372012-11-21 23:33:13 -050073 }
74
Garret Rieger4ad686b2020-03-25 23:32:28 -070075 bool lookup_limit_exceeded ()
Ebrahim Byagowi1a482782020-03-26 11:15:09 +043076 { return lookup_count > HB_MAX_LOOKUP_INDICES; }
Garret Rieger4ad686b2020-03-25 23:32:28 -070077
Behdad Esfahbodba0ea562018-06-11 23:24:41 -040078 bool should_visit_lookup (unsigned int lookup_index)
Garret Rieger45186b92018-06-05 17:14:42 -070079 {
Garret Rieger834a2242020-03-12 03:02:36 -070080 if (lookup_count++ > HB_MAX_LOOKUP_INDICES)
81 return false;
82
Garret Rieger45186b92018-06-05 17:14:42 -070083 if (is_lookup_done (lookup_index))
84 return false;
Garret Rieger834a2242020-03-12 03:02:36 -070085
Garret Rieger45186b92018-06-05 17:14:42 -070086 done_lookups->set (lookup_index, glyphs->get_population ());
87 return true;
88 }
89
90 bool is_lookup_done (unsigned int lookup_index)
91 {
Garret Rieger1e4fe102020-08-12 13:06:37 -070092 if (done_lookups->in_error ())
93 return true;
94
Behdad Esfahbodc38bd402018-07-24 09:43:27 -070095 /* Have we visited this lookup with the current set of glyphs? */
Garret Rieger45186b92018-06-05 17:14:42 -070096 return done_lookups->get (lookup_index) == glyphs->get_population ();
97 }
98
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -040099 hb_face_t *face;
Behdad Esfahbod6a9be5b2012-04-23 22:23:17 -0400100 hb_set_t *glyphs;
Behdad Esfahbodede1a712019-01-09 10:45:53 -0800101 hb_set_t output[1];
Behdad Esfahbod44fc2372012-11-21 23:33:13 -0500102 recurse_func_t recurse_func;
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400103 unsigned int nesting_level_left;
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400104
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400105 hb_closure_context_t (hb_face_t *face_,
Behdad Esfahbod6a9be5b2012-04-23 22:23:17 -0400106 hb_set_t *glyphs_,
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330107 hb_map_t *done_lookups_,
108 unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400109 face (face_),
110 glyphs (glyphs_),
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200111 recurse_func (nullptr),
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400112 nesting_level_left (nesting_level_left_),
Garret Rieger834a2242020-03-12 03:02:36 -0700113 done_lookups (done_lookups_),
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +0430114 lookup_count (0)
Garret Rieger834a2242020-03-12 03:02:36 -0700115 {}
Behdad Esfahbod9b346772012-11-23 17:55:40 -0500116
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330117 ~hb_closure_context_t () { flush (); }
Behdad Esfahbodc38bd402018-07-24 09:43:27 -0700118
Behdad Esfahbod9b346772012-11-23 17:55:40 -0500119 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
Garret Rieger45186b92018-06-05 17:14:42 -0700120
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330121 void flush ()
Behdad Esfahbodc38bd402018-07-24 09:43:27 -0700122 {
Michiharu Arizaff5223b2020-02-23 15:53:21 -0800123 hb_set_del_range (output, face->get_num_glyphs (), hb_set_get_max (output)); /* Remove invalid glyphs. */
Behdad Esfahbodede1a712019-01-09 10:45:53 -0800124 hb_set_union (glyphs, output);
125 hb_set_clear (output);
Behdad Esfahbodc38bd402018-07-24 09:43:27 -0700126 }
127
Garret Rieger45186b92018-06-05 17:14:42 -0700128 private:
129 hb_map_t *done_lookups;
Garret Rieger834a2242020-03-12 03:02:36 -0700130 unsigned int lookup_count;
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400131};
132
Qunxin Liu0b39c482019-10-22 16:00:43 -0700133struct hb_closure_lookups_context_t :
Behdad Esfahbod25aec022020-06-18 16:58:01 -0700134 hb_dispatch_context_t<hb_closure_lookups_context_t>
Qunxin Liu0b39c482019-10-22 16:00:43 -0700135{
Qunxin Liu0b39c482019-10-22 16:00:43 -0700136 typedef return_t (*recurse_func_t) (hb_closure_lookups_context_t *c, unsigned lookup_index);
137 template <typename T>
138 return_t dispatch (const T &obj) { obj.closure_lookups (this); return hb_empty_t (); }
139 static return_t default_return_value () { return hb_empty_t (); }
140 void recurse (unsigned lookup_index)
141 {
142 if (unlikely (nesting_level_left == 0 || !recurse_func))
143 return;
144
145 /* Return if new lookup was recursed to before. */
146 if (is_lookup_visited (lookup_index))
147 return;
148
Qunxin Liu0b39c482019-10-22 16:00:43 -0700149 nesting_level_left--;
150 recurse_func (this, lookup_index);
151 nesting_level_left++;
152 }
153
154 void set_lookup_visited (unsigned lookup_index)
155 { visited_lookups->add (lookup_index); }
156
157 void set_lookup_inactive (unsigned lookup_index)
158 { inactive_lookups->add (lookup_index); }
159
Garret Rieger4ad686b2020-03-25 23:32:28 -0700160 bool lookup_limit_exceeded ()
Ebrahim Byagowi1a482782020-03-26 11:15:09 +0430161 { return lookup_count > HB_MAX_LOOKUP_INDICES; }
Garret Rieger4ad686b2020-03-25 23:32:28 -0700162
Qunxin Liu0b39c482019-10-22 16:00:43 -0700163 bool is_lookup_visited (unsigned lookup_index)
Garret Rieger834a2242020-03-12 03:02:36 -0700164 {
165 if (lookup_count++ > HB_MAX_LOOKUP_INDICES)
166 return true;
167
Garret Rieger95622392020-08-12 13:01:22 -0700168 if (visited_lookups->in_error ())
169 return true;
170
Garret Rieger834a2242020-03-12 03:02:36 -0700171 return visited_lookups->has (lookup_index);
172 }
Qunxin Liu0b39c482019-10-22 16:00:43 -0700173
174 hb_face_t *face;
175 const hb_set_t *glyphs;
176 recurse_func_t recurse_func;
177 unsigned int nesting_level_left;
Qunxin Liu0b39c482019-10-22 16:00:43 -0700178
179 hb_closure_lookups_context_t (hb_face_t *face_,
180 const hb_set_t *glyphs_,
181 hb_set_t *visited_lookups_,
182 hb_set_t *inactive_lookups_,
183 unsigned nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
184 face (face_),
185 glyphs (glyphs_),
186 recurse_func (nullptr),
187 nesting_level_left (nesting_level_left_),
Qunxin Liu0b39c482019-10-22 16:00:43 -0700188 visited_lookups (visited_lookups_),
Garret Rieger834a2242020-03-12 03:02:36 -0700189 inactive_lookups (inactive_lookups_),
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +0430190 lookup_count (0) {}
Qunxin Liu0b39c482019-10-22 16:00:43 -0700191
192 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
193
194 private:
195 hb_set_t *visited_lookups;
196 hb_set_t *inactive_lookups;
Garret Rieger834a2242020-03-12 03:02:36 -0700197 unsigned int lookup_count;
Qunxin Liu0b39c482019-10-22 16:00:43 -0700198};
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400199
Behdad Esfahbod77a1a2b2015-10-09 12:20:58 -0400200struct hb_would_apply_context_t :
Behdad Esfahbod8d0a90a2020-06-18 16:53:54 -0700201 hb_dispatch_context_t<hb_would_apply_context_t, bool>
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400202{
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500203 template <typename T>
Behdad Esfahbodc14efb82019-05-05 09:54:58 -0700204 return_t dispatch (const T &obj) { return obj.would_apply (this); }
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330205 static return_t default_return_value () { return false; }
Behdad Esfahbod7b912c12013-01-04 01:25:27 -0600206 bool stop_sublookup_iteration (return_t r) const { return r; }
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500207
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400208 hb_face_t *face;
Behdad Esfahbod472f2292012-08-07 22:25:24 -0400209 const hb_codepoint_t *glyphs;
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400210 unsigned int len;
Behdad Esfahbodd9b204d2012-08-23 16:22:28 -0400211 bool zero_context;
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400212
213 hb_would_apply_context_t (hb_face_t *face_,
Behdad Esfahbod472f2292012-08-07 22:25:24 -0400214 const hb_codepoint_t *glyphs_,
215 unsigned int len_,
Behdad Esfahbod2bd9fe32012-09-04 15:15:19 -0400216 bool zero_context_) :
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400217 face (face_),
Behdad Esfahbod472f2292012-08-07 22:25:24 -0400218 glyphs (glyphs_),
219 len (len_),
Behdad Esfahbod70d66962020-06-18 17:09:39 -0700220 zero_context (zero_context_) {}
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400221};
222
Behdad Esfahbod77a1a2b2015-10-09 12:20:58 -0400223struct hb_collect_glyphs_context_t :
Behdad Esfahbod25aec022020-06-18 16:58:01 -0700224 hb_dispatch_context_t<hb_collect_glyphs_context_t>
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800225{
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500226 typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index);
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500227 template <typename T>
Behdad Esfahbod7df3ecf2019-05-10 20:43:26 -0700228 return_t dispatch (const T &obj) { obj.collect_glyphs (this); return hb_empty_t (); }
229 static return_t default_return_value () { return hb_empty_t (); }
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700230 void recurse (unsigned int lookup_index)
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500231 {
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500232 if (unlikely (nesting_level_left == 0 || !recurse_func))
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700233 return;
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500234
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200235 /* Note that GPOS sets recurse_func to nullptr already, so it doesn't get
Behdad Esfahbod1bcfa062012-12-04 16:58:09 -0500236 * past the previous check. For GSUB, we only want to collect the output
Behdad Esfahbod76ea5632013-05-04 16:01:20 -0400237 * glyphs in the recursion. If output is not requested, we can go home now.
238 *
239 * Note further, that the above is not exactly correct. A recursed lookup
240 * is allowed to match input that is not matched in the context, but that's
241 * not how most fonts are built. It's possible to relax that and recurse
242 * with all sets here if it proves to be an issue.
243 */
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500244
245 if (output == hb_set_get_empty ())
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700246 return;
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500247
Behdad Esfahbodfde3e4a2014-10-29 11:23:08 -0700248 /* Return if new lookup was recursed to before. */
Behdad Esfahbod8b9d9b72017-10-22 17:48:06 -0400249 if (recursed_lookups->has (lookup_index))
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700250 return;
Behdad Esfahbodfde3e4a2014-10-29 11:23:08 -0700251
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500252 hb_set_t *old_before = before;
253 hb_set_t *old_input = input;
254 hb_set_t *old_after = after;
255 before = input = after = hb_set_get_empty ();
Behdad Esfahbod1bcfa062012-12-04 16:58:09 -0500256
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500257 nesting_level_left--;
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500258 recurse_func (this, lookup_index);
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500259 nesting_level_left++;
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500260
261 before = old_before;
262 input = old_input;
263 after = old_after;
264
Behdad Esfahbod8b9d9b72017-10-22 17:48:06 -0400265 recursed_lookups->add (lookup_index);
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500266 }
267
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800268 hb_face_t *face;
Behdad Esfahbod83035932012-12-04 17:08:41 -0500269 hb_set_t *before;
270 hb_set_t *input;
271 hb_set_t *after;
272 hb_set_t *output;
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500273 recurse_func_t recurse_func;
Behdad Esfahbod8b9d9b72017-10-22 17:48:06 -0400274 hb_set_t *recursed_lookups;
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500275 unsigned int nesting_level_left;
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800276
277 hb_collect_glyphs_context_t (hb_face_t *face_,
Ebrahim Byagowi63109432018-10-13 14:00:05 +0330278 hb_set_t *glyphs_before, /* OUT. May be NULL */
279 hb_set_t *glyphs_input, /* OUT. May be NULL */
280 hb_set_t *glyphs_after, /* OUT. May be NULL */
281 hb_set_t *glyphs_output, /* OUT. May be NULL */
Behdad Esfahbod5ba45042015-11-02 15:43:08 -0800282 unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800283 face (face_),
Behdad Esfahbod83035932012-12-04 17:08:41 -0500284 before (glyphs_before ? glyphs_before : hb_set_get_empty ()),
285 input (glyphs_input ? glyphs_input : hb_set_get_empty ()),
286 after (glyphs_after ? glyphs_after : hb_set_get_empty ()),
287 output (glyphs_output ? glyphs_output : hb_set_get_empty ()),
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200288 recurse_func (nullptr),
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700289 recursed_lookups (hb_set_create ()),
Behdad Esfahbod70d66962020-06-18 17:09:39 -0700290 nesting_level_left (nesting_level_left_) {}
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330291 ~hb_collect_glyphs_context_t () { hb_set_destroy (recursed_lookups); }
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500292
293 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800294};
295
296
297
Behdad Esfahbod8e36ccf2015-02-17 19:15:34 +0300298template <typename set_t>
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -0700299struct hb_collect_coverage_context_t :
Behdad Esfahbod8d0a90a2020-06-18 16:53:54 -0700300 hb_dispatch_context_t<hb_collect_coverage_context_t<set_t>, const Coverage &>
Behdad Esfahbod2005fa52012-11-22 14:38:10 -0500301{
Behdad Esfahboddc492d72020-06-18 17:03:05 -0700302 typedef const Coverage &return_t; // Stoopid that we have to dupe this here.
Behdad Esfahbod2005fa52012-11-22 14:38:10 -0500303 template <typename T>
Behdad Esfahbodc14efb82019-05-05 09:54:58 -0700304 return_t dispatch (const T &obj) { return obj.get_coverage (); }
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +0430305 static return_t default_return_value () { return Null (Coverage); }
Behdad Esfahbod8e36ccf2015-02-17 19:15:34 +0300306 bool stop_sublookup_iteration (return_t r) const
307 {
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -0700308 r.collect_coverage (set);
Behdad Esfahbod8e36ccf2015-02-17 19:15:34 +0300309 return false;
310 }
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500311
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -0700312 hb_collect_coverage_context_t (set_t *set_) :
Behdad Esfahbod70d66962020-06-18 17:09:39 -0700313 set (set_) {}
Behdad Esfahboda1733db2012-11-23 16:40:04 -0500314
Behdad Esfahbod8e36ccf2015-02-17 19:15:34 +0300315 set_t *set;
Behdad Esfahbod2005fa52012-11-22 14:38:10 -0500316};
317
318
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800319struct hb_ot_apply_context_t :
320 hb_dispatch_context_t<hb_ot_apply_context_t, bool, HB_DEBUG_APPLY>
Behdad Esfahbod1376fb72010-04-29 02:19:21 -0400321{
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500322 struct matcher_t
323 {
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330324 matcher_t () :
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500325 lookup_props (0),
Behdad Esfahbodcfc507c2013-02-14 10:40:12 -0500326 ignore_zwnj (false),
327 ignore_zwj (false),
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500328 mask (-1),
329#define arg1(arg) (arg) /* Remove the macro to see why it's needed! */
330 syllable arg1(0),
331#undef arg1
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200332 match_func (nullptr),
Ebrahim Byagowif7a08cd2018-10-30 11:29:09 +0330333 match_data (nullptr) {}
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500334
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100335 typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500336
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330337 void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; }
338 void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
339 void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
340 void set_mask (hb_mask_t mask_) { mask = mask_; }
341 void set_syllable (uint8_t syllable_) { syllable = syllable_; }
342 void set_match_func (match_func_t match_func_,
Ebrahim Byagowid0e2add2020-07-18 22:14:52 +0430343 const void *match_data_)
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500344 { match_func = match_func_; match_data = match_data_; }
345
Behdad Esfahbod2b2a6e82013-02-21 15:07:03 -0500346 enum may_match_t {
347 MATCH_NO,
348 MATCH_YES,
349 MATCH_MAYBE
350 };
351
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330352 may_match_t may_match (const hb_glyph_info_t &info,
Behdad Esfahbod085793d2019-04-24 10:15:59 -0400353 const HBUINT16 *glyph_data) const
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500354 {
Behdad Esfahbod2b2a6e82013-02-21 15:07:03 -0500355 if (!(info.mask & mask) ||
356 (syllable && syllable != info.syllable ()))
357 return MATCH_NO;
358
359 if (match_func)
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330360 return match_func (info.codepoint, *glyph_data, match_data) ? MATCH_YES : MATCH_NO;
Behdad Esfahbod2b2a6e82013-02-21 15:07:03 -0500361
362 return MATCH_MAYBE;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500363 }
364
365 enum may_skip_t {
366 SKIP_NO,
367 SKIP_YES,
368 SKIP_MAYBE
369 };
370
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330371 may_skip_t may_skip (const hb_ot_apply_context_t *c,
372 const hb_glyph_info_t &info) const
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500373 {
Behdad Esfahbodb98c5db2014-07-16 13:44:01 -0400374 if (!c->check_glyph_property (&info, lookup_props))
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500375 return SKIP_YES;
376
Khaled Hosny06cfe3f2017-05-17 21:32:47 +0300377 if (unlikely (_hb_glyph_info_is_default_ignorable_and_not_hidden (&info) &&
Behdad Esfahbod0b454792013-02-14 10:46:52 -0500378 (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) &&
Behdad Esfahbod4ba796b2015-07-22 17:41:31 +0100379 (ignore_zwj || !_hb_glyph_info_is_zwj (&info))))
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500380 return SKIP_MAYBE;
381
382 return SKIP_NO;
383 }
384
385 protected:
386 unsigned int lookup_props;
387 bool ignore_zwnj;
Behdad Esfahbod0b454792013-02-14 10:46:52 -0500388 bool ignore_zwj;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500389 hb_mask_t mask;
390 uint8_t syllable;
391 match_func_t match_func;
392 const void *match_data;
393 };
394
Behdad Esfahbod69626692015-01-29 13:08:41 +0100395 struct skipping_iterator_t
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500396 {
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330397 void init (hb_ot_apply_context_t *c_, bool context_match = false)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500398 {
Behdad Esfahbod514564f2015-01-29 13:48:48 +0100399 c = c_;
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200400 match_glyph_data = nullptr;
401 matcher.set_match_func (nullptr, nullptr);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500402 matcher.set_lookup_props (c->lookup_props);
Behdad Esfahbod3583fb02018-09-23 22:33:38 -0400403 /* Ignore ZWNJ if we are matching GPOS, or matching GSUB context and asked to. */
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100404 matcher.set_ignore_zwnj (c->table_index == 1 || (context_match && c->auto_zwnj));
Behdad Esfahbod3583fb02018-09-23 22:33:38 -0400405 /* Ignore ZWJ if we are matching context, or asked to. */
406 matcher.set_ignore_zwj (context_match || c->auto_zwj);
Behdad Esfahbod514564f2015-01-29 13:48:48 +0100407 matcher.set_mask (context_match ? -1 : c->lookup_mask);
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500408 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330409 void set_lookup_props (unsigned int lookup_props)
Behdad Esfahbod514564f2015-01-29 13:48:48 +0100410 {
411 matcher.set_lookup_props (lookup_props);
412 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330413 void set_match_func (matcher_t::match_func_t match_func_,
414 const void *match_data_,
415 const HBUINT16 glyph_data[])
Behdad Esfahbodc074ebc2013-02-13 11:22:42 -0500416 {
Behdad Esfahbod4a6b1ee2015-10-21 11:20:55 -0200417 matcher.set_match_func (match_func_, match_data_);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500418 match_glyph_data = glyph_data;
Behdad Esfahbodc074ebc2013-02-13 11:22:42 -0500419 }
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500420
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330421 void reset (unsigned int start_index_,
Ebrahim Byagowi08428a12020-04-24 23:45:17 +0430422 unsigned int num_items_)
Behdad Esfahbodb051be52015-01-29 13:40:39 +0100423 {
424 idx = start_index_;
425 num_items = num_items_;
426 end = c->buffer->len;
427 matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
428 }
429
Ebrahim Byagowi64a45be2019-11-09 12:25:33 +0330430 void reject ()
431 {
432 num_items++;
433 if (match_glyph_data) match_glyph_data--;
434 }
Behdad Esfahbod69626692015-01-29 13:08:41 +0100435
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330436 matcher_t::may_skip_t
437 may_skip (const hb_glyph_info_t &info) const
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330438 { return matcher.may_skip (c, info); }
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200439
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330440 bool next ()
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500441 {
Behdad Esfahbod506ffeb2012-01-18 16:07:53 -0500442 assert (num_items > 0);
Behdad Esfahbod37d13ac2015-01-29 11:38:01 +0100443 while (idx + num_items < end)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500444 {
Behdad Esfahboda4a48fe2012-01-17 18:08:41 -0500445 idx++;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500446 const hb_glyph_info_t &info = c->buffer->info[idx];
447
Behdad Esfahbodff93ac82013-02-21 14:51:40 -0500448 matcher_t::may_skip_t skip = matcher.may_skip (c, info);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500449 if (unlikely (skip == matcher_t::SKIP_YES))
450 continue;
451
Behdad Esfahbod2b2a6e82013-02-21 15:07:03 -0500452 matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
Behdad Esfahbod722e8b82013-02-21 15:37:51 -0500453 if (match == matcher_t::MATCH_YES ||
454 (match == matcher_t::MATCH_MAYBE &&
455 skip == matcher_t::SKIP_NO))
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500456 {
457 num_items--;
Ebrahim Byagowiaca63902019-10-22 00:06:46 +0330458 if (match_glyph_data) match_glyph_data++;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500459 return true;
460 }
461
462 if (skip == matcher_t::SKIP_NO)
Behdad Esfahbod722e8b82013-02-21 15:37:51 -0500463 return false;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500464 }
465 return false;
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500466 }
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330467 bool prev ()
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500468 {
Behdad Esfahbod506ffeb2012-01-18 16:07:53 -0500469 assert (num_items > 0);
Behdad Esfahbod18a06f82018-07-05 14:03:48 +0430470 while (idx > num_items - 1)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500471 {
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500472 idx--;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500473 const hb_glyph_info_t &info = c->buffer->out_info[idx];
474
Behdad Esfahbodff93ac82013-02-21 14:51:40 -0500475 matcher_t::may_skip_t skip = matcher.may_skip (c, info);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500476 if (unlikely (skip == matcher_t::SKIP_YES))
477 continue;
478
Behdad Esfahbod2b2a6e82013-02-21 15:07:03 -0500479 matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
Behdad Esfahbod722e8b82013-02-21 15:37:51 -0500480 if (match == matcher_t::MATCH_YES ||
481 (match == matcher_t::MATCH_MAYBE &&
482 skip == matcher_t::SKIP_NO))
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500483 {
484 num_items--;
Ebrahim Byagowiaca63902019-10-22 00:06:46 +0330485 if (match_glyph_data) match_glyph_data++;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500486 return true;
487 }
488
489 if (skip == matcher_t::SKIP_NO)
Behdad Esfahbod722e8b82013-02-21 15:37:51 -0500490 return false;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500491 }
492 return false;
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500493 }
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500494
495 unsigned int idx;
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400496 protected:
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800497 hb_ot_apply_context_t *c;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500498 matcher_t matcher;
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100499 const HBUINT16 *match_glyph_data;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500500
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500501 unsigned int num_items;
Behdad Esfahbod69626692015-01-29 13:08:41 +0100502 unsigned int end;
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500503 };
504
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100505
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330506 const char *get_name () { return "APPLY"; }
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800507 typedef return_t (*recurse_func_t) (hb_ot_apply_context_t *c, unsigned int lookup_index);
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100508 template <typename T>
Behdad Esfahbodc14efb82019-05-05 09:54:58 -0700509 return_t dispatch (const T &obj) { return obj.apply (this); }
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330510 static return_t default_return_value () { return false; }
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100511 bool stop_sublookup_iteration (return_t r) const { return r; }
Behdad Esfahbod12757b62018-01-26 18:14:05 -0800512 return_t recurse (unsigned int sub_lookup_index)
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100513 {
Behdad Esfahbodbaf77792017-11-14 21:53:48 -0800514 if (unlikely (nesting_level_left == 0 || !recurse_func || buffer->max_ops-- <= 0))
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100515 return default_return_value ();
516
517 nesting_level_left--;
Behdad Esfahbod12757b62018-01-26 18:14:05 -0800518 bool ret = recurse_func (this, sub_lookup_index);
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100519 nesting_level_left++;
520 return ret;
521 }
522
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100523 skipping_iterator_t iter_input, iter_context;
524
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100525 hb_font_t *font;
526 hb_face_t *face;
527 hb_buffer_t *buffer;
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100528 recurse_func_t recurse_func;
529 const GDEF &gdef;
530 const VariationStore &var_store;
531
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100532 hb_direction_t direction;
533 hb_mask_t lookup_mask;
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100534 unsigned int table_index; /* GSUB/GPOS */
Behdad Esfahbod2c8b3b22015-08-18 14:36:43 +0100535 unsigned int lookup_index;
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100536 unsigned int lookup_props;
537 unsigned int nesting_level_left;
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100538
Behdad Esfahbod80de4bc2018-09-10 16:24:52 +0200539 bool has_glyph_classes;
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100540 bool auto_zwnj;
541 bool auto_zwj;
David Corbettc2a75e02018-01-25 14:22:03 -0500542 bool random;
Behdad Esfahbod80de4bc2018-09-10 16:24:52 +0200543
Behdad Esfahbodcfdea882018-09-11 10:57:48 +0200544 uint32_t random_state;
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100545
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100546
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800547 hb_ot_apply_context_t (unsigned int table_index_,
Ebrahim Byagowid0e2add2020-07-18 22:14:52 +0430548 hb_font_t *font_,
549 hb_buffer_t *buffer_) :
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100550 iter_input (), iter_context (),
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100551 font (font_), face (font->face), buffer (buffer_),
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200552 recurse_func (nullptr),
Behdad Esfahbod7dcf8e12019-06-26 13:44:10 -0700553 gdef (
554#ifndef HB_NO_OT_LAYOUT
555 *face->table.GDEF->table
556#else
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +0430557 Null (GDEF)
Behdad Esfahbod7dcf8e12019-06-26 13:44:10 -0700558#endif
559 ),
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100560 var_store (gdef.get_var_store ()),
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100561 direction (buffer_->props.direction),
562 lookup_mask (1),
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100563 table_index (table_index_),
Behdad Esfahbod2c8b3b22015-08-18 14:36:43 +0100564 lookup_index ((unsigned int) -1),
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100565 lookup_props (0),
566 nesting_level_left (HB_MAX_NESTING_LEVEL),
Behdad Esfahbod80de4bc2018-09-10 16:24:52 +0200567 has_glyph_classes (gdef.has_glyph_classes ()),
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100568 auto_zwnj (true),
569 auto_zwj (true),
David Corbettc2a75e02018-01-25 14:22:03 -0500570 random (false),
Behdad Esfahbodd748dc72018-09-24 18:30:50 -0400571 random_state (1) { init_iters (); }
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100572
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330573 void init_iters ()
Behdad Esfahbod365576d2015-01-29 13:59:42 +0100574 {
Behdad Esfahbod365576d2015-01-29 13:59:42 +0100575 iter_input.init (this, false);
576 iter_context.init (this, true);
577 }
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100578
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330579 void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; init_iters (); }
580 void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; init_iters (); }
581 void set_auto_zwnj (bool auto_zwnj_) { auto_zwnj = auto_zwnj_; init_iters (); }
582 void set_random (bool random_) { random = random_; }
583 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
584 void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; }
585 void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; init_iters (); }
Behdad Esfahbod9516cbd2018-09-23 22:00:34 -0400586
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330587 uint32_t random_number ()
Behdad Esfahbod08260c72018-09-11 10:51:19 +0200588 {
Behdad Esfahbodcfdea882018-09-11 10:57:48 +0200589 /* http://www.cplusplus.com/reference/random/minstd_rand/ */
590 random_state = random_state * 48271 % 2147483647;
591 return random_state;
Behdad Esfahbod08260c72018-09-11 10:51:19 +0200592 }
593
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330594 bool match_properties_mark (hb_codepoint_t glyph,
595 unsigned int glyph_props,
596 unsigned int match_props) const
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400597 {
598 /* If using mark filtering sets, the high short of
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700599 * match_props has the set index.
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400600 */
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700601 if (match_props & LookupFlag::UseMarkFilteringSet)
602 return gdef.mark_set_covers (match_props >> 16, glyph);
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400603
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700604 /* The second byte of match_props has the meaning
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400605 * "ignore marks of attachment type different than
606 * the attachment type specified."
607 */
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700608 if (match_props & LookupFlag::MarkAttachmentType)
609 return (match_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400610
611 return true;
612 }
613
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330614 bool check_glyph_property (const hb_glyph_info_t *info,
615 unsigned int match_props) const
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400616 {
Behdad Esfahbodb98c5db2014-07-16 13:44:01 -0400617 hb_codepoint_t glyph = info->codepoint;
618 unsigned int glyph_props = _hb_glyph_info_get_glyph_props (info);
619
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400620 /* Not covered, if, for example, glyph class is ligature and
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700621 * match_props includes LookupFlags::IgnoreLigatures
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400622 */
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700623 if (glyph_props & match_props & LookupFlag::IgnoreFlags)
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400624 return false;
625
Behdad Esfahbod5a08ecf2012-11-16 13:34:29 -0800626 if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK))
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700627 return match_properties_mark (glyph, glyph_props, match_props);
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400628
629 return true;
630 }
631
Ebrahim Byagowi9748ae72020-08-11 17:52:48 +0430632 void _set_glyph_props (hb_codepoint_t glyph_index,
633 unsigned int class_guess = 0,
634 bool ligature = false,
635 bool component = false) const
Behdad Esfahbod60da7632012-07-16 16:13:32 -0400636 {
Ebrahim Byagowi9748ae72020-08-11 17:52:48 +0430637 unsigned int add_in = _hb_glyph_info_get_glyph_props (&buffer->cur()) &
638 HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE;
639 add_in |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED;
Behdad Esfahbod09675a82013-10-18 01:05:58 +0200640 if (ligature)
Behdad Esfahbod832a6f92014-06-04 16:57:42 -0400641 {
Ebrahim Byagowi9748ae72020-08-11 17:52:48 +0430642 add_in |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED;
Behdad Esfahbod832a6f92014-06-04 16:57:42 -0400643 /* In the only place that the MULTIPLIED bit is used, Uniscribe
644 * seems to only care about the "last" transformation between
Bruce Mitchener257d0e52018-10-19 22:49:21 +0700645 * Ligature and Multiple substitutions. Ie. if you ligate, expand,
Behdad Esfahbod832a6f92014-06-04 16:57:42 -0400646 * and ligate again, it forgives the multiplication and acts as
647 * if only ligation happened. As such, clear MULTIPLIED bit.
648 */
Ebrahim Byagowi9748ae72020-08-11 17:52:48 +0430649 add_in &= ~HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
Behdad Esfahbod832a6f92014-06-04 16:57:42 -0400650 }
651 if (component)
Ebrahim Byagowi9748ae72020-08-11 17:52:48 +0430652 add_in |= HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
Behdad Esfahbod2fca1422012-07-30 18:46:41 -0400653 if (likely (has_glyph_classes))
Ebrahim Byagowi9748ae72020-08-11 17:52:48 +0430654 _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | gdef.get_glyph_props (glyph_index));
Behdad Esfahbod05bd1b62012-07-30 19:30:01 -0400655 else if (class_guess)
Ebrahim Byagowi9748ae72020-08-11 17:52:48 +0430656 _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | class_guess);
Behdad Esfahbod60da7632012-07-16 16:13:32 -0400657 }
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500658
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330659 void replace_glyph (hb_codepoint_t glyph_index) const
Behdad Esfahbod3ec77d62012-06-08 21:44:06 -0400660 {
Ebrahim Byagowi9748ae72020-08-11 17:52:48 +0430661 _set_glyph_props (glyph_index);
Behdad Esfahbod98370e82010-10-27 17:39:01 -0400662 buffer->replace_glyph (glyph_index);
663 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330664 void replace_glyph_inplace (hb_codepoint_t glyph_index) const
Behdad Esfahbod7fbbf862012-07-30 18:36:42 -0400665 {
Ebrahim Byagowi9748ae72020-08-11 17:52:48 +0430666 _set_glyph_props (glyph_index);
Behdad Esfahbod7fbbf862012-07-30 18:36:42 -0400667 buffer->cur().codepoint = glyph_index;
668 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330669 void replace_glyph_with_ligature (hb_codepoint_t glyph_index,
Behdad Esfahbodf4cd99f2020-04-22 14:45:57 -0700670 unsigned int class_guess) const
Behdad Esfahboda0161742013-10-18 00:06:30 +0200671 {
Ebrahim Byagowi9748ae72020-08-11 17:52:48 +0430672 _set_glyph_props (glyph_index, class_guess, true);
Behdad Esfahboda0161742013-10-18 00:06:30 +0200673 buffer->replace_glyph (glyph_index);
674 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330675 void output_glyph_for_component (hb_codepoint_t glyph_index,
Behdad Esfahbodf4cd99f2020-04-22 14:45:57 -0700676 unsigned int class_guess) const
Behdad Esfahboda0161742013-10-18 00:06:30 +0200677 {
Ebrahim Byagowi9748ae72020-08-11 17:52:48 +0430678 _set_glyph_props (glyph_index, class_guess, false, true);
Behdad Esfahboda0161742013-10-18 00:06:30 +0200679 buffer->output_glyph (glyph_index);
680 }
Behdad Esfahbod1376fb72010-04-29 02:19:21 -0400681};
682
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -0400683
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400684struct hb_get_subtables_context_t :
Behdad Esfahbod25aec022020-06-18 16:58:01 -0700685 hb_dispatch_context_t<hb_get_subtables_context_t>
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400686{
687 template <typename Type>
Behdad Esfahboda061e472019-12-10 13:31:50 -0600688 static inline bool apply_to (const void *obj, OT::hb_ot_apply_context_t *c)
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400689 {
690 const Type *typed_obj = (const Type *) obj;
691 return typed_obj->apply (c);
692 }
693
694 typedef bool (*hb_apply_func_t) (const void *obj, OT::hb_ot_apply_context_t *c);
695
696 struct hb_applicable_t
697 {
698 template <typename T>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330699 void init (const T &obj_, hb_apply_func_t apply_func_)
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400700 {
701 obj = &obj_;
702 apply_func = apply_func_;
703 digest.init ();
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -0700704 obj_.get_coverage ().collect_coverage (&digest);
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400705 }
706
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330707 bool apply (OT::hb_ot_apply_context_t *c) const
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400708 {
709 return digest.may_have (c->buffer->cur().codepoint) && apply_func (obj, c);
710 }
711
712 private:
713 const void *obj;
714 hb_apply_func_t apply_func;
715 hb_set_digest_t digest;
716 };
717
Behdad Esfahbodfa333e32018-12-27 17:56:22 -0500718 typedef hb_vector_t<hb_applicable_t> array_t;
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400719
720 /* Dispatch interface. */
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400721 template <typename T>
Behdad Esfahbodc14efb82019-05-05 09:54:58 -0700722 return_t dispatch (const T &obj)
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400723 {
724 hb_applicable_t *entry = array.push();
725 entry->init (obj, apply_to<T>);
Behdad Esfahbod7df3ecf2019-05-10 20:43:26 -0700726 return hb_empty_t ();
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400727 }
Behdad Esfahbod7df3ecf2019-05-10 20:43:26 -0700728 static return_t default_return_value () { return hb_empty_t (); }
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400729
730 hb_get_subtables_context_t (array_t &array_) :
Behdad Esfahbod15354402020-06-19 08:30:59 -0700731 array (array_) {}
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400732
733 array_t &array;
Behdad Esfahbodb3390992018-10-10 12:07:49 -0400734};
735
736
737
Behdad Esfahbod94a23aa2010-05-05 01:13:09 -0400738
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700739typedef bool (*intersects_func_t) (const hb_set_t *glyphs, const HBUINT16 &value, const void *data);
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100740typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const HBUINT16 &value, const void *data);
741typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -0400742
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400743struct ContextClosureFuncs
744{
745 intersects_func_t intersects;
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400746};
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500747struct ContextCollectGlyphsFuncs
748{
749 collect_glyphs_func_t collect;
750};
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400751struct ContextApplyFuncs
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400752{
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -0400753 match_func_t match;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -0400754};
755
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500756
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700757static inline bool intersects_glyph (const hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400758{
759 return glyphs->has (value);
760}
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700761static inline bool intersects_class (const hb_set_t *glyphs, const HBUINT16 &value, const void *data)
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400762{
763 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
764 return class_def.intersects_class (glyphs, value);
765}
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700766static inline bool intersects_coverage (const hb_set_t *glyphs, const HBUINT16 &value, const void *data)
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400767{
768 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
769 return (data+coverage).intersects (glyphs);
770}
771
Qunxin Liu44d88cf2020-05-08 15:33:34 -0700772static inline bool array_is_subset_of (const hb_set_t *glyphs,
773 unsigned int count,
774 const HBUINT16 values[],
775 intersects_func_t intersects_func,
776 const void *intersects_data)
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400777{
Garret Rieger95ab1102019-10-21 13:15:46 -0700778 for (const HBUINT16 &_ : + hb_iter (values, count))
Qunxin Liu44d88cf2020-05-08 15:33:34 -0700779 if (!intersects_func (glyphs, _, intersects_data)) return false;
780 return true;
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400781}
782
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -0400783
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100784static inline void collect_glyph (hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500785{
786 glyphs->add (value);
787}
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100788static inline void collect_class (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500789{
790 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
Behdad Esfahbod89ad3c62020-04-23 10:57:30 -0700791 class_def.collect_class (glyphs, value);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500792}
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100793static inline void collect_coverage (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500794{
795 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -0700796 (data+coverage).collect_coverage (glyphs);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500797}
Behdad Esfahbod0beb66e2012-12-05 18:46:04 -0500798static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -0500799 hb_set_t *glyphs,
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500800 unsigned int count,
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100801 const HBUINT16 values[],
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500802 collect_glyphs_func_t collect_func,
803 const void *collect_data)
804{
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -0700805 return
806 + hb_iter (values, count)
807 | hb_apply ([&] (const HBUINT16 &_) { collect_func (glyphs, _, collect_data); })
808 ;
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500809}
810
811
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100812static inline bool match_glyph (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data HB_UNUSED)
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400813{
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -0400814 return glyph_id == value;
815}
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100816static inline bool match_class (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data)
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400817{
Behdad Esfahbod2b5a59c2009-08-04 11:38:50 -0400818 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -0400819 return class_def.get_class (glyph_id) == value;
820}
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100821static inline bool match_coverage (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data)
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400822{
Behdad Esfahbod6b54c5d2009-05-18 18:30:25 -0400823 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400824 return (data+coverage).get_coverage (glyph_id) != NOT_COVERED;
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -0400825}
826
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400827static inline bool would_match_input (hb_would_apply_context_t *c,
828 unsigned int count, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100829 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400830 match_func_t match_func,
831 const void *match_data)
832{
833 if (count != c->len)
834 return false;
835
836 for (unsigned int i = 1; i < count; i++)
Behdad Esfahbod472f2292012-08-07 22:25:24 -0400837 if (likely (!match_func (c->glyphs[i], input[i - 1], match_data)))
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400838 return false;
839
840 return true;
841}
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800842static inline bool match_input (hb_ot_apply_context_t *c,
Behdad Esfahbode072c242009-05-18 03:47:31 -0400843 unsigned int count, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100844 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -0400845 match_func_t match_func,
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -0400846 const void *match_data,
Behdad Esfahbod6cc136f2013-10-17 13:55:48 +0200847 unsigned int *end_offset,
Behdad Esfahbod5ba45042015-11-02 15:43:08 -0800848 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200849 unsigned int *p_total_component_count = nullptr)
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -0400850{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200851 TRACE_APPLY (nullptr);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400852
Behdad Esfahbod5ba45042015-11-02 15:43:08 -0800853 if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return_trace (false);
Behdad Esfahbod6b65a762013-10-14 18:51:39 +0200854
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200855 hb_buffer_t *buffer = c->buffer;
856
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800857 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
Behdad Esfahbodb051be52015-01-29 13:40:39 +0100858 skippy_iter.reset (buffer->idx, count - 1);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500859 skippy_iter.set_match_func (match_func, match_data, input);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400860
Behdad Esfahbod191fa882012-08-28 22:58:55 -0400861 /*
862 * This is perhaps the trickiest part of OpenType... Remarks:
863 *
864 * - If all components of the ligature were marks, we call this a mark ligature.
865 *
866 * - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize
867 * it as a ligature glyph.
868 *
869 * - Ligatures cannot be formed across glyphs attached to different components
870 * of previous ligatures. Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and
871 * LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother.
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200872 * However, it would be wrong to ligate that SHADDA,FATHA sequence.
873 * There are a couple of exceptions to this:
874 *
875 * o If a ligature tries ligating with marks that belong to it itself, go ahead,
876 * assuming that the font designer knows what they are doing (otherwise it can
877 * break Indic stuff when a matra wants to ligate with a conjunct,
878 *
879 * o If two marks want to ligate and they belong to different components of the
880 * same ligature glyph, and said ligature glyph is to be ignored according to
881 * mark-filtering rules, then allow.
ebraminio7c6937e2017-11-20 14:49:22 -0500882 * https://github.com/harfbuzz/harfbuzz/issues/545
Behdad Esfahbod191fa882012-08-28 22:58:55 -0400883 */
884
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400885 unsigned int total_component_count = 0;
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200886 total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur());
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400887
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200888 unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
889 unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -0400890
Behdad Esfahbod621c49c2017-10-04 15:06:48 +0200891 enum {
892 LIGBASE_NOT_CHECKED,
893 LIGBASE_MAY_NOT_SKIP,
894 LIGBASE_MAY_SKIP
895 } ligbase = LIGBASE_NOT_CHECKED;
896
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200897 match_positions[0] = buffer->idx;
Behdad Esfahbod370f03e2012-01-16 17:03:55 -0500898 for (unsigned int i = 1; i < count; i++)
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400899 {
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100900 if (!skippy_iter.next ()) return_trace (false);
Behdad Esfahbod6cc136f2013-10-17 13:55:48 +0200901
902 match_positions[i] = skippy_iter.idx;
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400903
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200904 unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]);
905 unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400906
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200907 if (first_lig_id && first_lig_comp)
908 {
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400909 /* If first component was attached to a previous ligature component,
910 * all subsequent components should be attached to the same ligature
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200911 * component, otherwise we shouldn't ligate them... */
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400912 if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200913 {
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330914 /* ...unless, we are attached to a base ligature and that base
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200915 * ligature is ignorable. */
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330916 if (ligbase == LIGBASE_NOT_CHECKED)
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200917 {
Behdad Esfahbod621c49c2017-10-04 15:06:48 +0200918 bool found = false;
Behdad Esfahbod4d677432019-05-10 16:35:31 -0700919 const auto *out = buffer->out_info;
Behdad Esfahbod621c49c2017-10-04 15:06:48 +0200920 unsigned int j = buffer->out_len;
921 while (j && _hb_glyph_info_get_lig_id (&out[j - 1]) == first_lig_id)
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200922 {
Behdad Esfahbod621c49c2017-10-04 15:06:48 +0200923 if (_hb_glyph_info_get_lig_comp (&out[j - 1]) == 0)
924 {
925 j--;
926 found = true;
927 break;
928 }
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200929 j--;
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200930 }
Behdad Esfahbod621c49c2017-10-04 15:06:48 +0200931
Behdad Esfahbod12757b62018-01-26 18:14:05 -0800932 if (found && skippy_iter.may_skip (out[j]) == hb_ot_apply_context_t::matcher_t::SKIP_YES)
Behdad Esfahbod621c49c2017-10-04 15:06:48 +0200933 ligbase = LIGBASE_MAY_SKIP;
934 else
935 ligbase = LIGBASE_MAY_NOT_SKIP;
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200936 }
937
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +0330938 if (ligbase == LIGBASE_MAY_NOT_SKIP)
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200939 return_trace (false);
940 }
941 }
942 else
Behdad Esfahbod621c49c2017-10-04 15:06:48 +0200943 {
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400944 /* If first component was NOT attached to a previous ligature component,
945 * all subsequent components should also NOT be attached to any ligature
946 * component, unless they are attached to the first component itself! */
947 if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id))
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100948 return_trace (false);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400949 }
950
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200951 total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -0400952 }
953
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200954 *end_offset = skippy_iter.idx - buffer->idx + 1;
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400955
Behdad Esfahbod191fa882012-08-28 22:58:55 -0400956 if (p_total_component_count)
957 *p_total_component_count = total_component_count;
958
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100959 return_trace (true);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400960}
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800961static inline bool ligate_input (hb_ot_apply_context_t *c,
Behdad Esfahbode714fe62013-10-17 13:49:51 +0200962 unsigned int count, /* Including the first glyph */
Bruce Mitchener5a24ea12018-10-20 08:09:52 +0700963 const unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
Behdad Esfahbode714fe62013-10-17 13:49:51 +0200964 unsigned int match_length,
Behdad Esfahboda177d022012-08-28 23:18:22 -0400965 hb_codepoint_t lig_glyph,
Behdad Esfahboda177d022012-08-28 23:18:22 -0400966 unsigned int total_component_count)
967{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200968 TRACE_APPLY (nullptr);
Behdad Esfahbode714fe62013-10-17 13:49:51 +0200969
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200970 hb_buffer_t *buffer = c->buffer;
971
972 buffer->merge_clusters (buffer->idx, buffer->idx + match_length);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500973
Behdad Esfahbod9efddb92018-10-02 16:05:26 +0200974 /* - If a base and one or more marks ligate, consider that as a base, NOT
975 * ligature, such that all following marks can still attach to it.
976 * https://github.com/harfbuzz/harfbuzz/issues/1109
977 *
978 * - If all components of the ligature were marks, we call this a mark ligature.
Behdad Esfahbod3cca9782018-10-02 15:02:16 +0200979 * If it *is* a mark ligature, we don't allocate a new ligature id, and leave
Behdad Esfahboda177d022012-08-28 23:18:22 -0400980 * the ligature to keep its old ligature id. This will allow it to attach to
981 * a base ligature in GPOS. Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH,
Behdad Esfahbod3cca9782018-10-02 15:02:16 +0200982 * and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA with a
Behdad Esfahboda177d022012-08-28 23:18:22 -0400983 * ligature id and component value of 2. Then if SHADDA,FATHA form a ligature
984 * later, we don't want them to lose their ligature id/component, otherwise
985 * GPOS will fail to correctly position the mark ligature on top of the
986 * LAM,LAM,HEH ligature. See:
987 * https://bugzilla.gnome.org/show_bug.cgi?id=676343
988 *
989 * - If a ligature is formed of components that some of which are also ligatures
990 * themselves, and those ligature components had marks attached to *their*
991 * components, we have to attach the marks to the new ligature component
992 * positions! Now *that*'s tricky! And these marks may be following the
993 * last component of the whole sequence, so we should loop forward looking
994 * for them and update them.
995 *
996 * Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a
997 * 'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature
998 * id and component == 1. Now, during 'liga', the LAM and the LAM-HEH ligature
999 * form a LAM-LAM-HEH ligature. We need to reassign the SHADDA and FATHA to
1000 * the new ligature with a component value of 2.
1001 *
1002 * This in fact happened to a font... See:
1003 * https://bugzilla.gnome.org/show_bug.cgi?id=437633
1004 */
1005
Behdad Esfahbod9efddb92018-10-02 16:05:26 +02001006 bool is_base_ligature = _hb_glyph_info_is_base_glyph (&buffer->info[match_positions[0]]);
1007 bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->info[match_positions[0]]);
1008 for (unsigned int i = 1; i < count; i++)
Behdad Esfahbod3cca9782018-10-02 15:02:16 +02001009 if (!_hb_glyph_info_is_mark (&buffer->info[match_positions[i]]))
1010 {
Behdad Esfahbod9efddb92018-10-02 16:05:26 +02001011 is_base_ligature = false;
Behdad Esfahbod3cca9782018-10-02 15:02:16 +02001012 is_mark_ligature = false;
1013 break;
1014 }
Behdad Esfahbod9efddb92018-10-02 16:05:26 +02001015 bool is_ligature = !is_base_ligature && !is_mark_ligature;
Behdad Esfahbod3cca9782018-10-02 15:02:16 +02001016
Behdad Esfahbod9efddb92018-10-02 16:05:26 +02001017 unsigned int klass = is_ligature ? HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE : 0;
1018 unsigned int lig_id = is_ligature ? _hb_allocate_lig_id (buffer) : 0;
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +02001019 unsigned int last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
1020 unsigned int last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
Behdad Esfahboda177d022012-08-28 23:18:22 -04001021 unsigned int components_so_far = last_num_components;
1022
Behdad Esfahbod9efddb92018-10-02 16:05:26 +02001023 if (is_ligature)
Behdad Esfahbod7e08f122013-05-27 14:48:34 -04001024 {
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +02001025 _hb_glyph_info_set_lig_props_for_ligature (&buffer->cur(), lig_id, total_component_count);
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +02001026 if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
Behdad Esfahbod3d436d32013-10-28 21:00:37 +01001027 {
Behdad Esfahbod82596692015-11-02 17:44:05 -08001028 _hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER);
Behdad Esfahbod3d436d32013-10-28 21:00:37 +01001029 }
Behdad Esfahbod7e08f122013-05-27 14:48:34 -04001030 }
Behdad Esfahboda0161742013-10-18 00:06:30 +02001031 c->replace_glyph_with_ligature (lig_glyph, klass);
Behdad Esfahboda177d022012-08-28 23:18:22 -04001032
1033 for (unsigned int i = 1; i < count; i++)
1034 {
Behdad Esfahbod7185b272018-05-31 20:03:00 -07001035 while (buffer->idx < match_positions[i] && buffer->successful)
Behdad Esfahboda177d022012-08-28 23:18:22 -04001036 {
Behdad Esfahbod9efddb92018-10-02 16:05:26 +02001037 if (is_ligature)
1038 {
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03301039 unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
Behdad Esfahbod2f02fc72015-12-17 15:21:14 +00001040 if (this_comp == 0)
Behdad Esfahbod100fbea2015-12-17 15:23:09 +00001041 this_comp = last_num_components;
Behdad Esfahboda177d022012-08-28 23:18:22 -04001042 unsigned int new_lig_comp = components_so_far - last_num_components +
Behdad Esfahbod41248cc2019-05-07 20:54:31 -07001043 hb_min (this_comp, last_num_components);
Behdad Esfahbod2f02fc72015-12-17 15:21:14 +00001044 _hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
Behdad Esfahboda177d022012-08-28 23:18:22 -04001045 }
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +02001046 buffer->next_glyph ();
Behdad Esfahboda177d022012-08-28 23:18:22 -04001047 }
1048
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +02001049 last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
1050 last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
Behdad Esfahboda177d022012-08-28 23:18:22 -04001051 components_so_far += last_num_components;
1052
1053 /* Skip the base glyph */
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +02001054 buffer->idx++;
Behdad Esfahboda177d022012-08-28 23:18:22 -04001055 }
1056
Ebrahim Byagowicc977b62020-03-26 11:18:02 +04301057 if (!is_mark_ligature && last_lig_id)
1058 {
Behdad Esfahboda177d022012-08-28 23:18:22 -04001059 /* Re-adjust components for any marks following. */
Ebrahim Byagowicc977b62020-03-26 11:18:02 +04301060 for (unsigned i = buffer->idx; i < buffer->len; ++i)
1061 {
1062 if (last_lig_id != _hb_glyph_info_get_lig_id (&buffer->info[i])) break;
1063
1064 unsigned this_comp = _hb_glyph_info_get_lig_comp (&buffer->info[i]);
1065 if (!this_comp) break;
1066
1067 unsigned new_lig_comp = components_so_far - last_num_components +
1068 hb_min (this_comp, last_num_components);
1069 _hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
Behdad Esfahboda177d022012-08-28 23:18:22 -04001070 }
1071 }
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001072 return_trace (true);
Behdad Esfahboda177d022012-08-28 23:18:22 -04001073}
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001074
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001075static inline bool match_backtrack (hb_ot_apply_context_t *c,
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001076 unsigned int count,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001077 const HBUINT16 backtrack[],
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001078 match_func_t match_func,
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001079 const void *match_data,
1080 unsigned int *match_start)
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001081{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001082 TRACE_APPLY (nullptr);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -04001083
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001084 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
Behdad Esfahbodb051be52015-01-29 13:40:39 +01001085 skippy_iter.reset (c->buffer->backtrack_len (), count);
Behdad Esfahbod607feb72013-02-14 07:43:13 -05001086 skippy_iter.set_match_func (match_func, match_data, backtrack);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001087
Behdad Esfahbod4d3aeb82012-01-16 16:43:26 -05001088 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -05001089 if (!skippy_iter.prev ())
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001090 return_trace (false);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001091
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001092 *match_start = skippy_iter.idx;
1093
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001094 return_trace (true);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001095}
1096
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001097static inline bool match_lookahead (hb_ot_apply_context_t *c,
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001098 unsigned int count,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001099 const HBUINT16 lookahead[],
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001100 match_func_t match_func,
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04001101 const void *match_data,
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001102 unsigned int offset,
1103 unsigned int *end_index)
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001104{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001105 TRACE_APPLY (nullptr);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -04001106
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001107 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
Behdad Esfahbodb051be52015-01-29 13:40:39 +01001108 skippy_iter.reset (c->buffer->idx + offset - 1, count);
Behdad Esfahbod607feb72013-02-14 07:43:13 -05001109 skippy_iter.set_match_func (match_func, match_data, lookahead);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001110
Behdad Esfahbod370f03e2012-01-16 17:03:55 -05001111 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -05001112 if (!skippy_iter.next ())
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001113 return_trace (false);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -04001114
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001115 *end_index = skippy_iter.idx + 1;
1116
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001117 return_trace (true);
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001118}
1119
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04001120
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001121
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001122struct LookupRecord
1123{
Qunxin Liu0b39c482019-10-22 16:00:43 -07001124 LookupRecord* copy (hb_serialize_context_t *c,
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001125 const hb_map_t *lookup_map) const
Qunxin Liu0b39c482019-10-22 16:00:43 -07001126 {
1127 TRACE_SERIALIZE (this);
1128 auto *out = c->embed (*this);
1129 if (unlikely (!out)) return_trace (nullptr);
1130
1131 out->lookupListIndex = hb_map_get (lookup_map, lookupListIndex);
1132 return_trace (out);
1133 }
1134
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301135 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001136 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001137 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001138 return_trace (c->check_struct (this));
Behdad Esfahbodcd3827e2009-08-04 02:09:34 -04001139 }
1140
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001141 HBUINT16 sequenceIndex; /* Index into current glyph
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001142 * sequence--first glyph = 0 */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001143 HBUINT16 lookupListIndex; /* Lookup to apply to that
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001144 * position--zero--based */
Behdad Esfahbod569da922010-05-10 16:38:32 -04001145 public:
1146 DEFINE_SIZE_STATIC (4);
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001147};
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001148
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001149template <typename context_t>
1150static inline void recurse_lookups (context_t *c,
1151 unsigned int lookupCount,
1152 const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001153{
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001154 for (unsigned int i = 0; i < lookupCount; i++)
Behdad Esfahbod86522e42013-07-22 19:07:53 -04001155 c->recurse (lookupRecord[i].lookupListIndex);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001156}
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04001157
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001158static inline bool apply_lookup (hb_ot_apply_context_t *c,
Behdad Esfahbode072c242009-05-18 03:47:31 -04001159 unsigned int count, /* Including the first glyph */
Behdad Esfahbod5ba45042015-11-02 15:43:08 -08001160 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
Behdad Esfahbode072c242009-05-18 03:47:31 -04001161 unsigned int lookupCount,
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001162 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
1163 unsigned int match_length)
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001164{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001165 TRACE_APPLY (nullptr);
Behdad Esfahbod902cc8a2012-11-23 15:06:59 -05001166
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001167 hb_buffer_t *buffer = c->buffer;
jfkthame44f7d6e2017-02-17 03:03:24 +00001168 int end;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001169
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001170 /* All positions are distance from beginning of *output* buffer.
1171 * Adjust. */
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001172 {
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001173 unsigned int bl = buffer->backtrack_len ();
1174 end = bl + match_length;
Behdad Esfahbod8751de52013-07-18 16:29:50 -04001175
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001176 int delta = bl - buffer->idx;
1177 /* Convert positions to new indexing. */
1178 for (unsigned int j = 0; j < count; j++)
1179 match_positions[j] += delta;
Behdad Esfahbod8820bb22013-02-14 07:41:03 -05001180 }
Behdad Esfahbode73a0c22009-05-18 04:15:25 -04001181
Behdad Esfahbod7185b272018-05-31 20:03:00 -07001182 for (unsigned int i = 0; i < lookupCount && buffer->successful; i++)
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001183 {
1184 unsigned int idx = lookupRecord[i].sequenceIndex;
1185 if (idx >= count)
1186 continue;
1187
Behdad Esfahbod9cc1ed42015-11-19 12:39:09 -08001188 /* Don't recurse to ourself at same position.
1189 * Note that this test is too naive, it doesn't catch longer loops. */
1190 if (idx == 0 && lookupRecord[i].lookupListIndex == c->lookup_index)
1191 continue;
1192
Behdad Esfahbode5930722017-11-14 15:47:55 -08001193 if (unlikely (!buffer->move_to (match_positions[idx])))
1194 break;
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001195
Behdad Esfahbodbaf77792017-11-14 21:53:48 -08001196 if (unlikely (buffer->max_ops <= 0))
1197 break;
1198
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001199 unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
1200 if (!c->recurse (lookupRecord[i].lookupListIndex))
1201 continue;
1202
1203 unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len ();
1204 int delta = new_len - orig_len;
1205
1206 if (!delta)
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03301207 continue;
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001208
Behdad Esfahbod9ac9af72017-03-05 13:51:01 -08001209 /* Recursed lookup changed buffer len. Adjust.
1210 *
1211 * TODO:
1212 *
1213 * Right now, if buffer length increased by n, we assume n new glyphs
1214 * were added right after the current position, and if buffer length
1215 * was decreased by n, we assume n match positions after the current
1216 * one where removed. The former (buffer length increased) case is
1217 * fine, but the decrease case can be improved in at least two ways,
1218 * both of which are significant:
1219 *
1220 * - If recursed-to lookup is MultipleSubst and buffer length
1221 * decreased, then it's current match position that was deleted,
1222 * NOT the one after it.
1223 *
1224 * - If buffer length was decreased by n, it does not necessarily
1225 * mean that n match positions where removed, as there might
1226 * have been marks and default-ignorables in the sequence. We
1227 * should instead drop match positions between current-position
1228 * and current-position + n instead.
1229 *
1230 * It should be possible to construct tests for both of these cases.
1231 */
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001232
jfkthame44f7d6e2017-02-17 03:03:24 +00001233 end += delta;
Behdad Esfahbod47e7a182017-03-10 13:23:02 -08001234 if (end <= int (match_positions[idx]))
Behdad Esfahbod359dead2016-05-06 16:19:19 +01001235 {
Behdad Esfahbod4b4a1b92016-12-21 23:10:43 -06001236 /* End might end up being smaller than match_positions[idx] if the recursed
Behdad Esfahbod47e7a182017-03-10 13:23:02 -08001237 * lookup ended up removing many items, more than we have had matched.
Behdad Esfahbod4b4a1b92016-12-21 23:10:43 -06001238 * Just never rewind end back and get out of here.
1239 * https://bugs.chromium.org/p/chromium/issues/detail?id=659496 */
1240 end = match_positions[idx];
Behdad Esfahbod47e7a182017-03-10 13:23:02 -08001241 /* There can't be any further changes. */
Behdad Esfahbod359dead2016-05-06 16:19:19 +01001242 break;
1243 }
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001244
1245 unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */
1246
1247 if (delta > 0)
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001248 {
Behdad Esfahbod5ba45042015-11-02 15:43:08 -08001249 if (unlikely (delta + count > HB_MAX_CONTEXT_LENGTH))
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001250 break;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001251 }
1252 else
1253 {
Behdad Esfahbod47e7a182017-03-10 13:23:02 -08001254 /* NOTE: delta is negative. */
Behdad Esfahbod41248cc2019-05-07 20:54:31 -07001255 delta = hb_max (delta, (int) next - (int) count);
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001256 next -= delta;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001257 }
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001258
1259 /* Shift! */
1260 memmove (match_positions + next + delta, match_positions + next,
1261 (count - next) * sizeof (match_positions[0]));
1262 next += delta;
1263 count += delta;
1264
1265 /* Fill in new entries. */
1266 for (unsigned int j = idx + 1; j < next; j++)
1267 match_positions[j] = match_positions[j - 1] + 1;
1268
1269 /* And fixup the rest. */
1270 for (; next < count; next++)
1271 match_positions[next] += delta;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001272 }
1273
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001274 buffer->move_to (end);
1275
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001276 return_trace (true);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001277}
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001278
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04001279
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001280
1281/* Contextual lookups */
1282
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001283struct ContextClosureLookupContext
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001284{
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001285 ContextClosureFuncs funcs;
1286 const void *intersects_data;
1287};
1288
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001289struct ContextCollectGlyphsLookupContext
1290{
1291 ContextCollectGlyphsFuncs funcs;
1292 const void *collect_data;
1293};
1294
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001295struct ContextApplyLookupContext
1296{
1297 ContextApplyFuncs funcs;
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04001298 const void *match_data;
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001299};
1300
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001301static inline bool context_intersects (const hb_set_t *glyphs,
1302 unsigned int inputCount, /* Including the first glyph (not matched) */
1303 const HBUINT16 input[], /* Array of input values--start with second glyph */
1304 ContextClosureLookupContext &lookup_context)
1305{
Qunxin Liu44d88cf2020-05-08 15:33:34 -07001306 return array_is_subset_of (glyphs,
1307 inputCount ? inputCount - 1 : 0, input,
1308 lookup_context.funcs.intersects, lookup_context.intersects_data);
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001309}
1310
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001311static inline void context_closure_lookup (hb_closure_context_t *c,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001312 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001313 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001314 unsigned int lookupCount,
1315 const LookupRecord lookupRecord[],
1316 ContextClosureLookupContext &lookup_context)
1317{
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001318 if (context_intersects (c->glyphs,
1319 inputCount, input,
1320 lookup_context))
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001321 recurse_lookups (c,
1322 lookupCount, lookupRecord);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001323}
1324
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001325static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
1326 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001327 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001328 unsigned int lookupCount,
1329 const LookupRecord lookupRecord[],
1330 ContextCollectGlyphsLookupContext &lookup_context)
1331{
Behdad Esfahbod83035932012-12-04 17:08:41 -05001332 collect_array (c, c->input,
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001333 inputCount ? inputCount - 1 : 0, input,
1334 lookup_context.funcs.collect, lookup_context.collect_data);
1335 recurse_lookups (c,
1336 lookupCount, lookupRecord);
1337}
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001338
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001339static inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
1340 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001341 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbod0beb66e2012-12-05 18:46:04 -05001342 unsigned int lookupCount HB_UNUSED,
1343 const LookupRecord lookupRecord[] HB_UNUSED,
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001344 ContextApplyLookupContext &lookup_context)
1345{
1346 return would_match_input (c,
1347 inputCount, input,
1348 lookup_context.funcs.match, lookup_context.match_data);
1349}
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001350static inline bool context_apply_lookup (hb_ot_apply_context_t *c,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001351 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001352 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001353 unsigned int lookupCount,
1354 const LookupRecord lookupRecord[],
1355 ContextApplyLookupContext &lookup_context)
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001356{
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001357 unsigned int match_length = 0;
Behdad Esfahbod5ba45042015-11-02 15:43:08 -08001358 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001359 return match_input (c,
Behdad Esfahbod41697102010-05-05 01:37:58 -04001360 inputCount, input,
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001361 lookup_context.funcs.match, lookup_context.match_data,
1362 &match_length, match_positions)
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001363 && (c->buffer->unsafe_to_break (c->buffer->idx, c->buffer->idx + match_length),
1364 apply_lookup (c,
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001365 inputCount, match_positions,
1366 lookupCount, lookupRecord,
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001367 match_length));
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001368}
1369
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001370struct Rule
1371{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301372 bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001373 {
1374 return context_intersects (glyphs,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001375 inputCount, inputZ.arrayZ,
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001376 lookup_context);
1377 }
1378
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301379 void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001380 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04301381 if (unlikely (c->lookup_limit_exceeded ())) return;
Garret Rieger014e0382020-03-31 16:29:29 -07001382
Ebrahim Byagowi92588782019-04-30 13:05:10 -07001383 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
Behdad Esfahbod0382b712018-11-02 12:23:26 -04001384 (inputZ.as_array ((inputCount ? inputCount - 1 : 0)));
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001385 context_closure_lookup (c,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001386 inputCount, inputZ.arrayZ,
1387 lookupCount, lookupRecord.arrayZ,
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001388 lookup_context);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001389 }
1390
Qunxin Liu0b39c482019-10-22 16:00:43 -07001391 void closure_lookups (hb_closure_lookups_context_t *c) const
1392 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04301393 if (unlikely (c->lookup_limit_exceeded ())) return;
Garret Rieger014e0382020-03-31 16:29:29 -07001394
Qunxin Liu0b39c482019-10-22 16:00:43 -07001395 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
1396 (inputZ.as_array (inputCount ? inputCount - 1 : 0));
1397 recurse_lookups (c, lookupCount, lookupRecord.arrayZ);
1398 }
1399
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301400 void collect_glyphs (hb_collect_glyphs_context_t *c,
1401 ContextCollectGlyphsLookupContext &lookup_context) const
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001402 {
Ebrahim Byagowi92588782019-04-30 13:05:10 -07001403 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
Behdad Esfahbod0382b712018-11-02 12:23:26 -04001404 (inputZ.as_array (inputCount ? inputCount - 1 : 0));
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001405 context_collect_glyphs_lookup (c,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001406 inputCount, inputZ.arrayZ,
1407 lookupCount, lookupRecord.arrayZ,
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001408 lookup_context);
1409 }
1410
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301411 bool would_apply (hb_would_apply_context_t *c,
1412 ContextApplyLookupContext &lookup_context) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001413 {
Ebrahim Byagowi92588782019-04-30 13:05:10 -07001414 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
Behdad Esfahbod0382b712018-11-02 12:23:26 -04001415 (inputZ.as_array (inputCount ? inputCount - 1 : 0));
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07001416 return context_would_apply_lookup (c,
1417 inputCount, inputZ.arrayZ,
1418 lookupCount, lookupRecord.arrayZ,
1419 lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001420 }
1421
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301422 bool apply (hb_ot_apply_context_t *c,
1423 ContextApplyLookupContext &lookup_context) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001424 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001425 TRACE_APPLY (this);
Ebrahim Byagowi92588782019-04-30 13:05:10 -07001426 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
Behdad Esfahbod0382b712018-11-02 12:23:26 -04001427 (inputZ.as_array (inputCount ? inputCount - 1 : 0));
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001428 return_trace (context_apply_lookup (c, inputCount, inputZ.arrayZ, lookupCount, lookupRecord.arrayZ, lookup_context));
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001429 }
1430
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001431 bool serialize (hb_serialize_context_t *c,
1432 const hb_map_t *input_mapping, /* old->new glyphid or class mapping */
1433 const hb_map_t *lookup_map) const
1434 {
1435 TRACE_SERIALIZE (this);
1436 auto *out = c->start_embed (this);
1437 if (unlikely (!c->extend_min (out))) return_trace (false);
1438
1439 out->inputCount = inputCount;
1440 out->lookupCount = lookupCount;
1441
1442 const hb_array_t<const HBUINT16> input = inputZ.as_array (inputCount - 1);
1443 for (const auto org : input)
1444 {
1445 HBUINT16 d;
1446 d = input_mapping->get (org);
1447 c->copy (d);
1448 }
1449
1450 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
Ebrahim Byagowi5a7cc7f2020-07-29 08:33:32 +04301451 (inputZ.as_array ((inputCount ? inputCount - 1 : 0)));
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001452 for (unsigned i = 0; i < (unsigned) lookupCount; i++)
1453 c->copy (lookupRecord[i], lookup_map);
1454
1455 return_trace (true);
1456 }
1457
1458 bool subset (hb_subset_context_t *c,
1459 const hb_map_t *lookup_map,
1460 const hb_map_t *klass_map = nullptr) const
1461 {
1462 TRACE_SUBSET (this);
1463
1464 const hb_array_t<const HBUINT16> input = inputZ.as_array ((inputCount ? inputCount - 1 : 0));
1465 if (!input.length) return_trace (false);
1466
1467 const hb_map_t *mapping = klass_map == nullptr ? c->plan->glyph_map : klass_map;
1468 if (!hb_all (input, mapping)) return_trace (false);
1469 return_trace (serialize (c->serializer, mapping, lookup_map));
1470 }
1471
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001472 public:
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301473 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001474 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001475 TRACE_SANITIZE (this);
Behdad Esfahbod5aad8192017-11-03 17:16:26 -04001476 return_trace (inputCount.sanitize (c) &&
1477 lookupCount.sanitize (c) &&
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001478 c->check_range (inputZ.arrayZ,
Behdad Esfahbod9c6921c2018-11-30 15:16:57 -05001479 inputZ.item_size * (inputCount ? inputCount - 1 : 0) +
Behdad Esfahbod6d7c6e12018-02-07 14:09:56 -06001480 LookupRecord::static_size * lookupCount));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001481 }
1482
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001483 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001484 HBUINT16 inputCount; /* Total number of glyphs in input
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001485 * glyph sequence--includes the first
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001486 * glyph */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001487 HBUINT16 lookupCount; /* Number of LookupRecords */
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001488 UnsizedArrayOf<HBUINT16>
Ebrahim Byagowice114d62019-12-31 15:53:02 +03301489 inputZ; /* Array of match inputs--start with
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001490 * second glyph */
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001491/*UnsizedArrayOf<LookupRecord>
1492 lookupRecordX;*/ /* Array of LookupRecords--in
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001493 * design order */
Behdad Esfahbod569da922010-05-10 16:38:32 -04001494 public:
Behdad Esfahbod6d7c6e12018-02-07 14:09:56 -06001495 DEFINE_SIZE_ARRAY (4, inputZ);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001496};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001497
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001498struct RuleSet
1499{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301500 bool intersects (const hb_set_t *glyphs,
1501 ContextClosureLookupContext &lookup_context) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001502 {
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001503 return
1504 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07001505 | hb_map (hb_add (this))
1506 | hb_map ([&] (const Rule &_) { return _.intersects (glyphs, lookup_context); })
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001507 | hb_any
1508 ;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001509 }
1510
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301511 void closure (hb_closure_context_t *c,
1512 ContextClosureLookupContext &lookup_context) const
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001513 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04301514 if (unlikely (c->lookup_limit_exceeded ())) return;
Garret Rieger014e0382020-03-31 16:29:29 -07001515
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001516 return
1517 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07001518 | hb_map (hb_add (this))
1519 | hb_apply ([&] (const Rule &_) { _.closure (c, lookup_context); })
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001520 ;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001521 }
1522
Qunxin Liu0b39c482019-10-22 16:00:43 -07001523 void closure_lookups (hb_closure_lookups_context_t *c) const
1524 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04301525 if (unlikely (c->lookup_limit_exceeded ())) return;
Garret Rieger014e0382020-03-31 16:29:29 -07001526
Qunxin Liu0b39c482019-10-22 16:00:43 -07001527 return
1528 + hb_iter (rule)
1529 | hb_map (hb_add (this))
1530 | hb_apply ([&] (const Rule &_) { _.closure_lookups (c); })
1531 ;
1532 }
1533
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301534 void collect_glyphs (hb_collect_glyphs_context_t *c,
1535 ContextCollectGlyphsLookupContext &lookup_context) const
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001536 {
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001537 return
1538 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07001539 | hb_map (hb_add (this))
1540 | hb_apply ([&] (const Rule &_) { _.collect_glyphs (c, lookup_context); })
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001541 ;
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001542 }
1543
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301544 bool would_apply (hb_would_apply_context_t *c,
1545 ContextApplyLookupContext &lookup_context) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001546 {
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001547 return
1548 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07001549 | hb_map (hb_add (this))
1550 | hb_map ([&] (const Rule &_) { return _.would_apply (c, lookup_context); })
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001551 | hb_any
1552 ;
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001553 }
1554
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301555 bool apply (hb_ot_apply_context_t *c,
1556 ContextApplyLookupContext &lookup_context) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001557 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001558 TRACE_APPLY (this);
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001559 return_trace (
1560 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07001561 | hb_map (hb_add (this))
1562 | hb_map ([&] (const Rule &_) { return _.apply (c, lookup_context); })
Behdad Esfahbod22ec4c32019-03-29 22:27:46 -07001563 | hb_any
1564 )
1565 ;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001566 }
1567
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001568 bool subset (hb_subset_context_t *c,
1569 const hb_map_t *lookup_map,
1570 const hb_map_t *klass_map = nullptr) const
1571 {
1572 TRACE_SUBSET (this);
1573
1574 auto snap = c->serializer->snapshot ();
1575 auto *out = c->serializer->start_embed (*this);
1576 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
1577
1578 for (const OffsetTo<Rule>& _ : rule)
1579 {
1580 if (!_) continue;
1581 auto *o = out->rule.serialize_append (c->serializer);
1582 if (unlikely (!o)) continue;
1583
1584 auto o_snap = c->serializer->snapshot ();
1585 if (!o->serialize_subset (c, _, this, lookup_map, klass_map))
1586 {
Ebrahim Byagowi5a7cc7f2020-07-29 08:33:32 +04301587 out->rule.pop ();
1588 c->serializer->revert (o_snap);
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001589 }
1590 }
1591
1592 bool ret = bool (out->rule);
1593 if (!ret) c->serializer->revert (snap);
1594
1595 return_trace (ret);
1596 }
1597
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301598 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001599 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001600 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001601 return_trace (rule.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001602 }
1603
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001604 protected:
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001605 OffsetArrayOf<Rule>
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001606 rule; /* Array of Rule tables
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001607 * ordered by preference */
Behdad Esfahboded074222010-05-10 18:08:46 -04001608 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04001609 DEFINE_SIZE_ARRAY (2, rule);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001610};
1611
1612
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001613struct ContextFormat1
1614{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301615 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001616 {
1617 struct ContextClosureLookupContext lookup_context = {
1618 {intersects_glyph},
1619 nullptr
1620 };
Behdad Esfahbod05f21302019-03-29 22:40:13 -07001621
1622 return
1623 + hb_zip (this+coverage, ruleSet)
1624 | hb_filter (*glyphs, hb_first)
1625 | hb_map (hb_second)
Behdad Esfahbod23768672019-05-15 21:57:26 -07001626 | hb_map (hb_add (this))
1627 | hb_map ([&] (const RuleSet &_) { return _.intersects (glyphs, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07001628 | hb_any
1629 ;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001630 }
1631
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301632 void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001633 {
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001634 struct ContextClosureLookupContext lookup_context = {
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001635 {intersects_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001636 nullptr
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001637 };
Behdad Esfahbod05f21302019-03-29 22:40:13 -07001638
1639 + hb_zip (this+coverage, ruleSet)
1640 | hb_filter (*c->glyphs, hb_first)
1641 | hb_map (hb_second)
Behdad Esfahbod23768672019-05-15 21:57:26 -07001642 | hb_map (hb_add (this))
1643 | hb_apply ([&] (const RuleSet &_) { _.closure (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07001644 ;
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001645 }
1646
Qunxin Liu0b39c482019-10-22 16:00:43 -07001647 void closure_lookups (hb_closure_lookups_context_t *c) const
1648 {
1649 + hb_iter (ruleSet)
1650 | hb_map (hb_add (this))
1651 | hb_apply ([&] (const RuleSet &_) { _.closure_lookups (c); })
1652 ;
1653 }
1654
Qunxin Liu8200e482020-02-26 13:11:42 -08001655 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
1656
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301657 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001658 {
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07001659 (this+coverage).collect_coverage (c->input);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001660
1661 struct ContextCollectGlyphsLookupContext lookup_context = {
1662 {collect_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001663 nullptr
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001664 };
1665
Behdad Esfahbod05f21302019-03-29 22:40:13 -07001666 + hb_iter (ruleSet)
Behdad Esfahbod23768672019-05-15 21:57:26 -07001667 | hb_map (hb_add (this))
1668 | hb_apply ([&] (const RuleSet &_) { _.collect_glyphs (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07001669 ;
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001670 }
1671
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301672 bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001673 {
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05001674 const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001675 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001676 {match_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001677 nullptr
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001678 };
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07001679 return rule_set.would_apply (c, lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001680 }
1681
Ebrahim Byagowie4120082018-12-17 21:31:01 +03301682 const Coverage &get_coverage () const { return this+coverage; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001683
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301684 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001685 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001686 TRACE_APPLY (this);
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05001687 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -04001688 if (likely (index == NOT_COVERED))
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001689 return_trace (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04001690
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001691 const RuleSet &rule_set = this+ruleSet[index];
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001692 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001693 {match_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001694 nullptr
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001695 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001696 return_trace (rule_set.apply (c, lookup_context));
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001697 }
1698
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301699 bool subset (hb_subset_context_t *c) const
Behdad Esfahbod339d3602018-09-03 17:33:34 -07001700 {
1701 TRACE_SUBSET (this);
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001702 const hb_set_t &glyphset = *c->plan->glyphset ();
1703 const hb_map_t &glyph_map = *c->plan->glyph_map;
1704
1705 auto *out = c->serializer->start_embed (*this);
1706 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
1707 out->format = format;
1708
1709 const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
1710 hb_sorted_vector_t<hb_codepoint_t> new_coverage;
1711 + hb_zip (this+coverage, ruleSet)
1712 | hb_filter (glyphset, hb_first)
1713 | hb_filter (subset_offset_array (c, out->ruleSet, this, lookup_map), hb_second)
1714 | hb_map (hb_first)
1715 | hb_map (glyph_map)
1716 | hb_sink (new_coverage)
1717 ;
1718
1719 out->coverage.serialize (c->serializer, out)
Ebrahim Byagowi5a7cc7f2020-07-29 08:33:32 +04301720 .serialize (c->serializer, new_coverage.iter ());
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001721 return_trace (bool (new_coverage));
Behdad Esfahbod339d3602018-09-03 17:33:34 -07001722 }
1723
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301724 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001725 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001726 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001727 return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001728 }
1729
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001730 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001731 HBUINT16 format; /* Format identifier--format = 1 */
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001732 OffsetTo<Coverage>
1733 coverage; /* Offset to Coverage table--from
1734 * beginning of table */
1735 OffsetArrayOf<RuleSet>
1736 ruleSet; /* Array of RuleSet tables
1737 * ordered by Coverage Index */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04001738 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04001739 DEFINE_SIZE_ARRAY (6, ruleSet);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001740};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001741
1742
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001743struct ContextFormat2
1744{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301745 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001746 {
1747 if (!(this+coverage).intersects (glyphs))
1748 return false;
1749
1750 const ClassDef &class_def = this+classDef;
1751
1752 struct ContextClosureLookupContext lookup_context = {
1753 {intersects_class},
1754 &class_def
1755 };
1756
Behdad Esfahbod668d2d52019-03-29 22:48:38 -07001757 return
Behdad Esfahbod26111a12020-06-28 02:59:47 -07001758 + hb_iter (ruleSet)
1759 | hb_map (hb_add (this))
1760 | hb_enumerate
1761 | hb_map ([&] (const hb_pair_t<unsigned, const RuleSet &> p)
Behdad Esfahbode5306922019-03-29 23:31:07 -07001762 { return class_def.intersects_class (glyphs, p.first) &&
Behdad Esfahbod26111a12020-06-28 02:59:47 -07001763 p.second.intersects (glyphs, lookup_context); })
Behdad Esfahbod668d2d52019-03-29 22:48:38 -07001764 | hb_any
1765 ;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001766 }
1767
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301768 void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001769 {
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001770 if (!(this+coverage).intersects (c->glyphs))
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001771 return;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001772
1773 const ClassDef &class_def = this+classDef;
1774
1775 struct ContextClosureLookupContext lookup_context = {
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001776 {intersects_class},
Behdad Esfahbod11fba792013-01-02 23:36:37 -06001777 &class_def
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001778 };
1779
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07001780 return
1781 + hb_enumerate (ruleSet)
Behdad Esfahbod78d35f02019-05-15 18:15:05 -07001782 | hb_filter ([&] (unsigned _)
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07001783 { return class_def.intersects_class (c->glyphs, _); },
1784 hb_first)
1785 | hb_map (hb_second)
Behdad Esfahbod23768672019-05-15 21:57:26 -07001786 | hb_map (hb_add (this))
1787 | hb_apply ([&] (const RuleSet &_) { _.closure (c, lookup_context); })
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07001788 ;
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001789 }
1790
Qunxin Liu0b39c482019-10-22 16:00:43 -07001791 void closure_lookups (hb_closure_lookups_context_t *c) const
1792 {
1793 + hb_iter (ruleSet)
1794 | hb_map (hb_add (this))
1795 | hb_apply ([&] (const RuleSet &_) { _.closure_lookups (c); })
1796 ;
1797 }
1798
Qunxin Liu8200e482020-02-26 13:11:42 -08001799 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
1800
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301801 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001802 {
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07001803 (this+coverage).collect_coverage (c->input);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001804
Behdad Esfahbod11fba792013-01-02 23:36:37 -06001805 const ClassDef &class_def = this+classDef;
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001806 struct ContextCollectGlyphsLookupContext lookup_context = {
1807 {collect_class},
Behdad Esfahbod11fba792013-01-02 23:36:37 -06001808 &class_def
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001809 };
1810
Behdad Esfahbod05f21302019-03-29 22:40:13 -07001811 + hb_iter (ruleSet)
Behdad Esfahbod23768672019-05-15 21:57:26 -07001812 | hb_map (hb_add (this))
1813 | hb_apply ([&] (const RuleSet &_) { _.collect_glyphs (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07001814 ;
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001815 }
1816
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301817 bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001818 {
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001819 const ClassDef &class_def = this+classDef;
Behdad Esfahbod2dc11412012-11-24 19:16:34 -05001820 unsigned int index = class_def.get_class (c->glyphs[0]);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001821 const RuleSet &rule_set = this+ruleSet[index];
1822 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001823 {match_class},
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001824 &class_def
1825 };
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07001826 return rule_set.would_apply (c, lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001827 }
1828
Ebrahim Byagowie4120082018-12-17 21:31:01 +03301829 const Coverage &get_coverage () const { return this+coverage; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001830
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301831 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001832 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001833 TRACE_APPLY (this);
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05001834 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001835 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04001836
1837 const ClassDef &class_def = this+classDef;
Behdad Esfahbod2dc11412012-11-24 19:16:34 -05001838 index = class_def.get_class (c->buffer->cur().codepoint);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001839 const RuleSet &rule_set = this+ruleSet[index];
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001840 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001841 {match_class},
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04001842 &class_def
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001843 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001844 return_trace (rule_set.apply (c, lookup_context));
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001845 }
1846
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301847 bool subset (hb_subset_context_t *c) const
Behdad Esfahbod339d3602018-09-03 17:33:34 -07001848 {
1849 TRACE_SUBSET (this);
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001850 auto *out = c->serializer->start_embed (*this);
1851 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
1852 out->format = format;
1853 if (unlikely (!out->coverage.serialize_subset (c, coverage, this)))
1854 return_trace (false);
1855
1856 hb_map_t klass_map;
1857 out->classDef.serialize_subset (c, classDef, this, &klass_map);
1858
1859 const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
1860 bool ret = true;
Garret Rieger8c3d4de2020-09-09 12:38:34 -07001861 int non_zero_index = 0, index = 0;
Ebrahim Byagowia79d0e42020-05-21 07:32:58 +04301862 for (const hb_pair_t<unsigned, const OffsetTo<RuleSet>&> _ : + hb_enumerate (ruleSet)
1863 | hb_filter (klass_map, hb_first))
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001864 {
1865 auto *o = out->ruleSet.serialize_append (c->serializer);
1866 if (unlikely (!o))
1867 {
Ebrahim Byagowi5a7cc7f2020-07-29 08:33:32 +04301868 ret = false;
1869 break;
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001870 }
1871
1872 if (o->serialize_subset (c, _.second, this, lookup_map, &klass_map))
Ebrahim Byagowi5a7cc7f2020-07-29 08:33:32 +04301873 non_zero_index = index;
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07001874
1875 index++;
1876 }
1877
1878 if (!ret) return_trace (ret);
1879
1880 //prune empty trailing ruleSets
1881 --index;
1882 while (index > non_zero_index)
1883 {
1884 out->ruleSet.pop ();
1885 index--;
1886 }
1887
1888 return_trace (bool (out->ruleSet));
Behdad Esfahbod339d3602018-09-03 17:33:34 -07001889 }
1890
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301891 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001892 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001893 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001894 return_trace (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001895 }
1896
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001897 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001898 HBUINT16 format; /* Format identifier--format = 2 */
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001899 OffsetTo<Coverage>
1900 coverage; /* Offset to Coverage table--from
1901 * beginning of table */
1902 OffsetTo<ClassDef>
1903 classDef; /* Offset to glyph ClassDef table--from
1904 * beginning of table */
1905 OffsetArrayOf<RuleSet>
1906 ruleSet; /* Array of RuleSet tables
1907 * ordered by class */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04001908 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04001909 DEFINE_SIZE_ARRAY (8, ruleSet);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001910};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001911
1912
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001913struct ContextFormat3
1914{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301915 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001916 {
Behdad Esfahbodfb059082018-11-30 20:45:40 -05001917 if (!(this+coverageZ[0]).intersects (glyphs))
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001918 return false;
1919
1920 struct ContextClosureLookupContext lookup_context = {
1921 {intersects_coverage},
1922 this
1923 };
1924 return context_intersects (glyphs,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001925 glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001926 lookup_context);
1927 }
1928
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301929 void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001930 {
Behdad Esfahbodfb059082018-11-30 20:45:40 -05001931 if (!(this+coverageZ[0]).intersects (c->glyphs))
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001932 return;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001933
Behdad Esfahbod0382b712018-11-02 12:23:26 -04001934 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001935 struct ContextClosureLookupContext lookup_context = {
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001936 {intersects_coverage},
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001937 this
1938 };
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001939 context_closure_lookup (c,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001940 glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001941 lookupCount, lookupRecord,
1942 lookup_context);
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001943 }
1944
Qunxin Liu0b39c482019-10-22 16:00:43 -07001945 void closure_lookups (hb_closure_lookups_context_t *c) const
1946 {
1947 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
1948 recurse_lookups (c, lookupCount, lookupRecord);
1949 }
1950
Qunxin Liu8200e482020-02-26 13:11:42 -08001951 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
1952
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301953 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001954 {
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07001955 (this+coverageZ[0]).collect_coverage (c->input);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001956
Behdad Esfahbod0382b712018-11-02 12:23:26 -04001957 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001958 struct ContextCollectGlyphsLookupContext lookup_context = {
1959 {collect_coverage},
Behdad Esfahbode75943d2012-11-30 08:38:24 +02001960 this
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001961 };
1962
1963 context_collect_glyphs_lookup (c,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001964 glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001965 lookupCount, lookupRecord,
1966 lookup_context);
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001967 }
1968
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301969 bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001970 {
Behdad Esfahbod0382b712018-11-02 12:23:26 -04001971 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001972 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001973 {match_coverage},
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001974 this
1975 };
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07001976 return context_would_apply_lookup (c,
1977 glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
1978 lookupCount, lookupRecord,
1979 lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001980 }
1981
Ebrahim Byagowie4120082018-12-17 21:31:01 +03301982 const Coverage &get_coverage () const { return this+coverageZ[0]; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001983
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301984 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001985 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001986 TRACE_APPLY (this);
Behdad Esfahbodfb059082018-11-30 20:45:40 -05001987 unsigned int index = (this+coverageZ[0]).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001988 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04001989
Behdad Esfahbod0382b712018-11-02 12:23:26 -04001990 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001991 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001992 {match_coverage},
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04001993 this
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001994 };
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001995 return_trace (context_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, lookup_context));
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001996 }
1997
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301998 bool subset (hb_subset_context_t *c) const
Behdad Esfahbod339d3602018-09-03 17:33:34 -07001999 {
2000 TRACE_SUBSET (this);
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002001 auto *out = c->serializer->start_embed (this);
2002 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
2003
2004 out->format = format;
2005 out->glyphCount = glyphCount;
2006 out->lookupCount = lookupCount;
2007
Behdad Esfahbod26111a12020-06-28 02:59:47 -07002008 auto coverages = coverageZ.as_array (glyphCount);
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002009
2010 for (const OffsetTo<Coverage>& offset : coverages)
2011 {
2012 auto *o = c->serializer->allocate_size<OffsetTo<Coverage>> (OffsetTo<Coverage>::static_size);
2013 if (unlikely (!o)) return_trace (false);
2014 if (!o->serialize_subset (c, offset, this)) return_trace (false);
2015 }
2016
2017 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
2018 const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
2019 for (unsigned i = 0; i < (unsigned) lookupCount; i++)
2020 c->serializer->copy (lookupRecord[i], lookup_map);
Ebrahim Byagowia79d0e42020-05-21 07:32:58 +04302021
Qunxin Liu8b5d3eb2020-04-17 11:58:31 -07002022 return_trace (true);
Behdad Esfahbod339d3602018-09-03 17:33:34 -07002023 }
2024
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302025 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002026 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002027 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002028 if (!c->check_struct (this)) return_trace (false);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002029 unsigned int count = glyphCount;
Behdad Esfahbodfb059082018-11-30 20:45:40 -05002030 if (!count) return_trace (false); /* We want to access coverageZ[0] freely. */
Behdad Esfahbod9507b052018-09-10 23:18:07 +02002031 if (!c->check_array (coverageZ.arrayZ, count)) return_trace (false);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002032 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002033 if (!coverageZ[i].sanitize (c, this)) return_trace (false);
Behdad Esfahbod0382b712018-11-02 12:23:26 -04002034 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
Behdad Esfahbod9507b052018-09-10 23:18:07 +02002035 return_trace (c->check_array (lookupRecord, lookupCount));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002036 }
2037
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002038 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002039 HBUINT16 format; /* Format identifier--format = 3 */
2040 HBUINT16 glyphCount; /* Number of glyphs in the input glyph
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002041 * sequence */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002042 HBUINT16 lookupCount; /* Number of LookupRecords */
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002043 UnsizedArrayOf<OffsetTo<Coverage>>
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02002044 coverageZ; /* Array of offsets to Coverage
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002045 * table in glyph sequence order */
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02002046/*UnsizedArrayOf<LookupRecord>
2047 lookupRecordX;*/ /* Array of LookupRecords--in
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002048 * design order */
Behdad Esfahbod569da922010-05-10 16:38:32 -04002049 public:
Behdad Esfahbod6d7c6e12018-02-07 14:09:56 -06002050 DEFINE_SIZE_ARRAY (6, coverageZ);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002051};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002052
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002053struct Context
2054{
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -07002055 template <typename context_t, typename ...Ts>
Behdad Esfahbod83e3eab2019-05-07 20:58:43 -07002056 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002057 {
Behdad Esfahbod00f6a8e2014-12-12 20:36:49 -08002058 TRACE_DISPATCH (this, u.format);
Behdad Esfahbodf396fbb2015-10-09 12:25:55 -04002059 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002060 switch (u.format) {
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -07002061 case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
2062 case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
2063 case 3: return_trace (c->dispatch (u.format3, hb_forward<Ts> (ds)...));
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002064 default:return_trace (c->default_return_value ());
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002065 }
2066 }
2067
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002068 protected:
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002069 union {
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002070 HBUINT16 format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -04002071 ContextFormat1 format1;
2072 ContextFormat2 format2;
2073 ContextFormat3 format3;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002074 } u;
2075};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002076
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002077
2078/* Chaining Contextual lookups */
2079
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002080struct ChainContextClosureLookupContext
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002081{
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002082 ContextClosureFuncs funcs;
2083 const void *intersects_data[3];
2084};
2085
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002086struct ChainContextCollectGlyphsLookupContext
2087{
2088 ContextCollectGlyphsFuncs funcs;
2089 const void *collect_data[3];
2090};
2091
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002092struct ChainContextApplyLookupContext
2093{
2094 ContextApplyFuncs funcs;
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04002095 const void *match_data[3];
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04002096};
2097
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002098static inline bool chain_context_intersects (const hb_set_t *glyphs,
2099 unsigned int backtrackCount,
2100 const HBUINT16 backtrack[],
2101 unsigned int inputCount, /* Including the first glyph (not matched) */
2102 const HBUINT16 input[], /* Array of input values--start with second glyph */
2103 unsigned int lookaheadCount,
2104 const HBUINT16 lookahead[],
2105 ChainContextClosureLookupContext &lookup_context)
2106{
Qunxin Liu44d88cf2020-05-08 15:33:34 -07002107 return array_is_subset_of (glyphs,
2108 backtrackCount, backtrack,
2109 lookup_context.funcs.intersects, lookup_context.intersects_data[0])
2110 && array_is_subset_of (glyphs,
2111 inputCount ? inputCount - 1 : 0, input,
2112 lookup_context.funcs.intersects, lookup_context.intersects_data[1])
2113 && array_is_subset_of (glyphs,
2114 lookaheadCount, lookahead,
2115 lookup_context.funcs.intersects, lookup_context.intersects_data[2]);
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002116}
2117
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002118static inline void chain_context_closure_lookup (hb_closure_context_t *c,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002119 unsigned int backtrackCount,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002120 const HBUINT16 backtrack[],
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002121 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002122 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002123 unsigned int lookaheadCount,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002124 const HBUINT16 lookahead[],
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002125 unsigned int lookupCount,
2126 const LookupRecord lookupRecord[],
2127 ChainContextClosureLookupContext &lookup_context)
2128{
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002129 if (chain_context_intersects (c->glyphs,
2130 backtrackCount, backtrack,
2131 inputCount, input,
2132 lookaheadCount, lookahead,
2133 lookup_context))
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05002134 recurse_lookups (c,
2135 lookupCount, lookupRecord);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002136}
2137
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002138static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03302139 unsigned int backtrackCount,
2140 const HBUINT16 backtrack[],
2141 unsigned int inputCount, /* Including the first glyph (not matched) */
2142 const HBUINT16 input[], /* Array of input values--start with second glyph */
2143 unsigned int lookaheadCount,
2144 const HBUINT16 lookahead[],
2145 unsigned int lookupCount,
2146 const LookupRecord lookupRecord[],
2147 ChainContextCollectGlyphsLookupContext &lookup_context)
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002148{
Behdad Esfahbod83035932012-12-04 17:08:41 -05002149 collect_array (c, c->before,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002150 backtrackCount, backtrack,
2151 lookup_context.funcs.collect, lookup_context.collect_data[0]);
Behdad Esfahbod83035932012-12-04 17:08:41 -05002152 collect_array (c, c->input,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002153 inputCount ? inputCount - 1 : 0, input,
2154 lookup_context.funcs.collect, lookup_context.collect_data[1]);
Behdad Esfahbod83035932012-12-04 17:08:41 -05002155 collect_array (c, c->after,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002156 lookaheadCount, lookahead,
2157 lookup_context.funcs.collect, lookup_context.collect_data[2]);
2158 recurse_lookups (c,
2159 lookupCount, lookupRecord);
2160}
2161
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002162static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c,
2163 unsigned int backtrackCount,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002164 const HBUINT16 backtrack[] HB_UNUSED,
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002165 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002166 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002167 unsigned int lookaheadCount,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002168 const HBUINT16 lookahead[] HB_UNUSED,
Behdad Esfahbod0beb66e2012-12-05 18:46:04 -05002169 unsigned int lookupCount HB_UNUSED,
2170 const LookupRecord lookupRecord[] HB_UNUSED,
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002171 ChainContextApplyLookupContext &lookup_context)
2172{
Behdad Esfahbodd9b204d2012-08-23 16:22:28 -04002173 return (c->zero_context ? !backtrackCount && !lookaheadCount : true)
Behdad Esfahbod1f2bb172012-08-23 16:10:37 -04002174 && would_match_input (c,
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002175 inputCount, input,
2176 lookup_context.funcs.match, lookup_context.match_data[1]);
2177}
2178
Behdad Esfahbodfd034492018-01-17 16:46:51 -08002179static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002180 unsigned int backtrackCount,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002181 const HBUINT16 backtrack[],
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002182 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002183 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002184 unsigned int lookaheadCount,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002185 const HBUINT16 lookahead[],
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002186 unsigned int lookupCount,
2187 const LookupRecord lookupRecord[],
2188 ChainContextApplyLookupContext &lookup_context)
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04002189{
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02002190 unsigned int start_index = 0, match_length = 0, end_index = 0;
Behdad Esfahbod5ba45042015-11-02 15:43:08 -08002191 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
Behdad Esfahbodf19e0b02012-06-09 02:26:57 -04002192 return match_input (c,
Behdad Esfahbod41697102010-05-05 01:37:58 -04002193 inputCount, input,
2194 lookup_context.funcs.match, lookup_context.match_data[1],
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02002195 &match_length, match_positions)
Behdad Esfahbodf19e0b02012-06-09 02:26:57 -04002196 && match_backtrack (c,
2197 backtrackCount, backtrack,
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02002198 lookup_context.funcs.match, lookup_context.match_data[0],
2199 &start_index)
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04002200 && match_lookahead (c,
Behdad Esfahbod41697102010-05-05 01:37:58 -04002201 lookaheadCount, lookahead,
2202 lookup_context.funcs.match, lookup_context.match_data[2],
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02002203 match_length, &end_index)
2204 && (c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index),
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03302205 apply_lookup (c,
2206 inputCount, match_positions,
2207 lookupCount, lookupRecord,
2208 match_length));
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04002209}
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04002210
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002211struct ChainRule
2212{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302213 bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002214 {
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002215 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
2216 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002217 return chain_context_intersects (glyphs,
2218 backtrack.len, backtrack.arrayZ,
Behdad Esfahbodeffc7ce2018-09-13 20:21:54 +02002219 input.lenP1, input.arrayZ,
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002220 lookahead.len, lookahead.arrayZ,
2221 lookup_context);
2222 }
2223
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302224 void closure (hb_closure_context_t *c,
2225 ChainContextClosureLookupContext &lookup_context) const
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002226 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04302227 if (unlikely (c->lookup_limit_exceeded ())) return;
Garret Rieger4ad686b2020-03-25 23:32:28 -07002228
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002229 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
2230 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
2231 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002232 chain_context_closure_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002233 backtrack.len, backtrack.arrayZ,
Behdad Esfahbodeffc7ce2018-09-13 20:21:54 +02002234 input.lenP1, input.arrayZ,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002235 lookahead.len, lookahead.arrayZ,
2236 lookup.len, lookup.arrayZ,
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002237 lookup_context);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002238 }
2239
Qunxin Liu0b39c482019-10-22 16:00:43 -07002240 void closure_lookups (hb_closure_lookups_context_t *c) const
2241 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04302242 if (unlikely (c->lookup_limit_exceeded ())) return;
Garret Rieger4ad686b2020-03-25 23:32:28 -07002243
Qunxin Liu0b39c482019-10-22 16:00:43 -07002244 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
2245 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
2246 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
2247 recurse_lookups (c, lookup.len, lookup.arrayZ);
2248 }
2249
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302250 void collect_glyphs (hb_collect_glyphs_context_t *c,
2251 ChainContextCollectGlyphsLookupContext &lookup_context) const
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002252 {
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002253 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
2254 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
2255 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002256 chain_context_collect_glyphs_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002257 backtrack.len, backtrack.arrayZ,
Behdad Esfahbodeffc7ce2018-09-13 20:21:54 +02002258 input.lenP1, input.arrayZ,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002259 lookahead.len, lookahead.arrayZ,
2260 lookup.len, lookup.arrayZ,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002261 lookup_context);
2262 }
2263
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302264 bool would_apply (hb_would_apply_context_t *c,
2265 ChainContextApplyLookupContext &lookup_context) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002266 {
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002267 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
2268 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
2269 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07002270 return chain_context_would_apply_lookup (c,
2271 backtrack.len, backtrack.arrayZ,
2272 input.lenP1, input.arrayZ,
2273 lookahead.len, lookahead.arrayZ, lookup.len,
2274 lookup.arrayZ, lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002275 }
2276
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302277 bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002278 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002279 TRACE_APPLY (this);
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002280 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
2281 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
2282 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002283 return_trace (chain_context_apply_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002284 backtrack.len, backtrack.arrayZ,
Behdad Esfahbodeffc7ce2018-09-13 20:21:54 +02002285 input.lenP1, input.arrayZ,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002286 lookahead.len, lookahead.arrayZ, lookup.len,
2287 lookup.arrayZ, lookup_context));
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002288 }
2289
Qunxin Liub66094a2019-09-30 16:19:18 -07002290 template<typename Iterator,
2291 hb_requires (hb_is_iterator (Iterator))>
2292 void serialize_array (hb_serialize_context_t *c,
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04302293 HBUINT16 len,
2294 Iterator it) const
Qunxin Liub66094a2019-09-30 16:19:18 -07002295 {
2296 c->copy (len);
2297 for (const auto g : it)
2298 {
2299 HBUINT16 gid;
2300 gid = g;
2301 c->copy (gid);
2302 }
2303 }
2304
2305 ChainRule* copy (hb_serialize_context_t *c,
Qunxin Liu593e58c2020-05-20 18:00:25 -07002306 const hb_map_t *lookup_map,
Qunxin Liub66094a2019-09-30 16:19:18 -07002307 const hb_map_t *backtrack_map,
2308 const hb_map_t *input_map = nullptr,
2309 const hb_map_t *lookahead_map = nullptr) const
2310 {
2311 TRACE_SERIALIZE (this);
2312 auto *out = c->start_embed (this);
2313 if (unlikely (!out)) return_trace (nullptr);
2314
2315 const hb_map_t *mapping = backtrack_map;
2316 serialize_array (c, backtrack.len, + backtrack.iter ()
2317 | hb_map (mapping));
2318
2319 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
2320 if (input_map) mapping = input_map;
2321 serialize_array (c, input.lenP1, + input.iter ()
2322 | hb_map (mapping));
2323
2324 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
2325 if (lookahead_map) mapping = lookahead_map;
2326 serialize_array (c, lookahead.len, + lookahead.iter ()
2327 | hb_map (mapping));
2328
Qunxin Liu593e58c2020-05-20 18:00:25 -07002329 const ArrayOf<LookupRecord> &lookupRecord = StructAfter<ArrayOf<LookupRecord>> (lookahead);
Qunxin Liu593e58c2020-05-20 18:00:25 -07002330
Garret Rieger8f47dd52020-11-04 11:05:22 -08002331 HBUINT16* lookupCount = c->embed (&(lookupRecord.len));
2332 if (!lookupCount) return_trace (nullptr);
2333
2334 for (unsigned i = 0; i < lookupRecord.len; i++)
2335 {
2336 if (!lookup_map->has (lookupRecord[i].lookupListIndex))
2337 {
2338 (*lookupCount)--;
2339 continue;
2340 }
Qunxin Liu593e58c2020-05-20 18:00:25 -07002341 if (!c->copy (lookupRecord[i], lookup_map)) return_trace (nullptr);
Garret Rieger8f47dd52020-11-04 11:05:22 -08002342 }
Qunxin Liub66094a2019-09-30 16:19:18 -07002343
2344 return_trace (out);
2345 }
2346
2347 bool subset (hb_subset_context_t *c,
Qunxin Liu593e58c2020-05-20 18:00:25 -07002348 const hb_map_t *lookup_map,
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04302349 const hb_map_t *backtrack_map = nullptr,
2350 const hb_map_t *input_map = nullptr,
2351 const hb_map_t *lookahead_map = nullptr) const
Qunxin Liub66094a2019-09-30 16:19:18 -07002352 {
2353 TRACE_SUBSET (this);
2354
Qunxin Liub2fcca62019-10-24 15:15:26 -07002355 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
2356 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
2357
Qunxin Liub66094a2019-09-30 16:19:18 -07002358 if (!backtrack_map)
2359 {
2360 const hb_set_t &glyphset = *c->plan->glyphset ();
2361 if (!hb_all (backtrack, glyphset) ||
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04302362 !hb_all (input, glyphset) ||
2363 !hb_all (lookahead, glyphset))
2364 return_trace (false);
Qunxin Liub66094a2019-09-30 16:19:18 -07002365
Qunxin Liu593e58c2020-05-20 18:00:25 -07002366 copy (c->serializer, lookup_map, c->plan->glyph_map);
Qunxin Liub66094a2019-09-30 16:19:18 -07002367 }
2368 else
2369 {
2370 if (!hb_all (backtrack, backtrack_map) ||
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04302371 !hb_all (input, input_map) ||
2372 !hb_all (lookahead, lookahead_map))
2373 return_trace (false);
Ebrahim Byagowiaca63902019-10-22 00:06:46 +03302374
Qunxin Liu593e58c2020-05-20 18:00:25 -07002375 copy (c->serializer, lookup_map, backtrack_map, input_map, lookahead_map);
Qunxin Liub66094a2019-09-30 16:19:18 -07002376 }
2377
2378 return_trace (true);
2379 }
2380
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302381 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002382 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002383 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002384 if (!backtrack.sanitize (c)) return_trace (false);
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002385 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002386 if (!input.sanitize (c)) return_trace (false);
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002387 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002388 if (!lookahead.sanitize (c)) return_trace (false);
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002389 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002390 return_trace (lookup.sanitize (c));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002391 }
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002392
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002393 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002394 ArrayOf<HBUINT16>
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04002395 backtrack; /* Array of backtracking values
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002396 * (to be matched before the input
2397 * sequence) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002398 HeadlessArrayOf<HBUINT16>
Behdad Esfahbode8cbaaf2009-05-18 02:03:58 -04002399 inputX; /* Array of input values (start with
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002400 * second glyph) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002401 ArrayOf<HBUINT16>
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04002402 lookaheadX; /* Array of lookahead values's (to be
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04002403 * matched after the input sequence) */
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04002404 ArrayOf<LookupRecord>
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04002405 lookupX; /* Array of LookupRecords--in
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002406 * design order) */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04002407 public:
Behdad Esfahbodbea34c72010-05-10 17:28:16 -04002408 DEFINE_SIZE_MIN (8);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002409};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002410
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002411struct ChainRuleSet
2412{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302413 bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002414 {
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002415 return
2416 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002417 | hb_map (hb_add (this))
2418 | hb_map ([&] (const ChainRule &_) { return _.intersects (glyphs, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002419 | hb_any
2420 ;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002421 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302422 void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002423 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04302424 if (unlikely (c->lookup_limit_exceeded ())) return;
Garret Rieger4ad686b2020-03-25 23:32:28 -07002425
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002426 return
2427 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002428 | hb_map (hb_add (this))
2429 | hb_apply ([&] (const ChainRule &_) { _.closure (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002430 ;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002431 }
2432
Qunxin Liu0b39c482019-10-22 16:00:43 -07002433 void closure_lookups (hb_closure_lookups_context_t *c) const
2434 {
Ebrahim Byagowi0c65a232020-04-23 11:23:54 +04302435 if (unlikely (c->lookup_limit_exceeded ())) return;
Garret Rieger4ad686b2020-03-25 23:32:28 -07002436
Qunxin Liu0b39c482019-10-22 16:00:43 -07002437 return
2438 + hb_iter (rule)
2439 | hb_map (hb_add (this))
2440 | hb_apply ([&] (const ChainRule &_) { _.closure_lookups (c); })
2441 ;
2442 }
2443
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302444 void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002445 {
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002446 return
2447 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002448 | hb_map (hb_add (this))
2449 | hb_apply ([&] (const ChainRule &_) { _.collect_glyphs (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002450 ;
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002451 }
2452
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302453 bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002454 {
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002455 return
2456 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002457 | hb_map (hb_add (this))
2458 | hb_map ([&] (const ChainRule &_) { return _.would_apply (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002459 | hb_any
2460 ;
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002461 }
2462
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302463 bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002464 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002465 TRACE_APPLY (this);
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002466 return_trace (
2467 + hb_iter (rule)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002468 | hb_map (hb_add (this))
2469 | hb_map ([&] (const ChainRule &_) { return _.apply (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002470 | hb_any
2471 )
2472 ;
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04002473 }
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002474
Qunxin Liub66094a2019-09-30 16:19:18 -07002475 bool subset (hb_subset_context_t *c,
Qunxin Liu593e58c2020-05-20 18:00:25 -07002476 const hb_map_t *lookup_map,
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04302477 const hb_map_t *backtrack_klass_map = nullptr,
2478 const hb_map_t *input_klass_map = nullptr,
2479 const hb_map_t *lookahead_klass_map = nullptr) const
Qunxin Liub66094a2019-09-30 16:19:18 -07002480 {
2481 TRACE_SUBSET (this);
2482
2483 auto snap = c->serializer->snapshot ();
2484 auto *out = c->serializer->start_embed (*this);
2485 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
2486
2487 for (const OffsetTo<ChainRule>& _ : rule)
2488 {
2489 if (!_) continue;
2490 auto *o = out->rule.serialize_append (c->serializer);
2491 if (unlikely (!o)) continue;
Ebrahim Byagowiaca63902019-10-22 00:06:46 +03302492
Qunxin Liub66094a2019-09-30 16:19:18 -07002493 auto o_snap = c->serializer->snapshot ();
ariza188a0a42020-03-07 11:02:36 -08002494 if (!o->serialize_subset (c, _, this,
Qunxin Liu593e58c2020-05-20 18:00:25 -07002495 lookup_map,
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04302496 backtrack_klass_map,
2497 input_klass_map,
2498 lookahead_klass_map))
Qunxin Liub66094a2019-09-30 16:19:18 -07002499 {
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04302500 out->rule.pop ();
2501 c->serializer->revert (o_snap);
Qunxin Liub66094a2019-09-30 16:19:18 -07002502 }
2503 }
2504
2505 bool ret = bool (out->rule);
2506 if (!ret) c->serializer->revert (snap);
Ebrahim Byagowiaca63902019-10-22 00:06:46 +03302507
Qunxin Liub66094a2019-09-30 16:19:18 -07002508 return_trace (ret);
2509 }
2510
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302511 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002512 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002513 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002514 return_trace (rule.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002515 }
2516
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002517 protected:
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04002518 OffsetArrayOf<ChainRule>
2519 rule; /* Array of ChainRule tables
2520 * ordered by preference */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04002521 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04002522 DEFINE_SIZE_ARRAY (2, rule);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002523};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002524
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002525struct ChainContextFormat1
2526{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302527 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002528 {
2529 struct ChainContextClosureLookupContext lookup_context = {
2530 {intersects_glyph},
2531 {nullptr, nullptr, nullptr}
2532 };
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002533
2534 return
2535 + hb_zip (this+coverage, ruleSet)
2536 | hb_filter (*glyphs, hb_first)
2537 | hb_map (hb_second)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002538 | hb_map (hb_add (this))
2539 | hb_map ([&] (const ChainRuleSet &_) { return _.intersects (glyphs, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002540 | hb_any
2541 ;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002542 }
2543
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302544 void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002545 {
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002546 struct ChainContextClosureLookupContext lookup_context = {
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002547 {intersects_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02002548 {nullptr, nullptr, nullptr}
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002549 };
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002550
2551 + hb_zip (this+coverage, ruleSet)
2552 | hb_filter (*c->glyphs, hb_first)
2553 | hb_map (hb_second)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002554 | hb_map (hb_add (this))
2555 | hb_apply ([&] (const ChainRuleSet &_) { _.closure (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002556 ;
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002557 }
2558
Qunxin Liu0b39c482019-10-22 16:00:43 -07002559 void closure_lookups (hb_closure_lookups_context_t *c) const
2560 {
2561 + hb_iter (ruleSet)
2562 | hb_map (hb_add (this))
2563 | hb_apply ([&] (const ChainRuleSet &_) { _.closure_lookups (c); })
2564 ;
2565 }
2566
Qunxin Liu8200e482020-02-26 13:11:42 -08002567 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
2568
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302569 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002570 {
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07002571 (this+coverage).collect_coverage (c->input);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002572
2573 struct ChainContextCollectGlyphsLookupContext lookup_context = {
2574 {collect_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02002575 {nullptr, nullptr, nullptr}
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002576 };
2577
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002578 + hb_iter (ruleSet)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002579 | hb_map (hb_add (this))
2580 | hb_apply ([&] (const ChainRuleSet &_) { _.collect_glyphs (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002581 ;
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002582 }
2583
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302584 bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002585 {
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05002586 const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002587 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002588 {match_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02002589 {nullptr, nullptr, nullptr}
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002590 };
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07002591 return rule_set.would_apply (c, lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002592 }
2593
Ebrahim Byagowie4120082018-12-17 21:31:01 +03302594 const Coverage &get_coverage () const { return this+coverage; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002595
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302596 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002597 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002598 TRACE_APPLY (this);
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05002599 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002600 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002601
2602 const ChainRuleSet &rule_set = this+ruleSet[index];
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002603 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002604 {match_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02002605 {nullptr, nullptr, nullptr}
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002606 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002607 return_trace (rule_set.apply (c, lookup_context));
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002608 }
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002609
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302610 bool subset (hb_subset_context_t *c) const
Behdad Esfahbod339d3602018-09-03 17:33:34 -07002611 {
2612 TRACE_SUBSET (this);
Qunxin Liub66094a2019-09-30 16:19:18 -07002613 const hb_set_t &glyphset = *c->plan->glyphset ();
2614 const hb_map_t &glyph_map = *c->plan->glyph_map;
2615
2616 auto *out = c->serializer->start_embed (*this);
2617 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
2618 out->format = format;
2619
Qunxin Liu593e58c2020-05-20 18:00:25 -07002620 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 -07002621 hb_sorted_vector_t<hb_codepoint_t> new_coverage;
2622 + hb_zip (this+coverage, ruleSet)
2623 | hb_filter (glyphset, hb_first)
Qunxin Liu593e58c2020-05-20 18:00:25 -07002624 | hb_filter (subset_offset_array (c, out->ruleSet, this, lookup_map), hb_second)
Qunxin Liub66094a2019-09-30 16:19:18 -07002625 | hb_map (hb_first)
2626 | hb_map (glyph_map)
2627 | hb_sink (new_coverage)
2628 ;
2629
2630 out->coverage.serialize (c->serializer, out)
2631 .serialize (c->serializer, new_coverage.iter ());
2632 return_trace (bool (new_coverage));
Behdad Esfahbod339d3602018-09-03 17:33:34 -07002633 }
2634
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302635 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002636 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002637 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002638 return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002639 }
2640
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002641 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002642 HBUINT16 format; /* Format identifier--format = 1 */
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04002643 OffsetTo<Coverage>
2644 coverage; /* Offset to Coverage table--from
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002645 * beginning of table */
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002646 OffsetArrayOf<ChainRuleSet>
2647 ruleSet; /* Array of ChainRuleSet tables
2648 * ordered by Coverage Index */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04002649 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04002650 DEFINE_SIZE_ARRAY (6, ruleSet);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002651};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002652
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002653struct ChainContextFormat2
2654{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302655 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002656 {
2657 if (!(this+coverage).intersects (glyphs))
2658 return false;
2659
2660 const ClassDef &backtrack_class_def = this+backtrackClassDef;
2661 const ClassDef &input_class_def = this+inputClassDef;
2662 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2663
2664 struct ChainContextClosureLookupContext lookup_context = {
2665 {intersects_class},
2666 {&backtrack_class_def,
2667 &input_class_def,
2668 &lookahead_class_def}
2669 };
2670
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07002671 return
Behdad Esfahbod26111a12020-06-28 02:59:47 -07002672 + hb_iter (ruleSet)
2673 | hb_map (hb_add (this))
2674 | hb_enumerate
2675 | hb_map ([&] (const hb_pair_t<unsigned, const ChainRuleSet &> p)
Behdad Esfahbod78d35f02019-05-15 18:15:05 -07002676 { return input_class_def.intersects_class (glyphs, p.first) &&
Behdad Esfahbod26111a12020-06-28 02:59:47 -07002677 p.second.intersects (glyphs, lookup_context); })
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07002678 | hb_any
2679 ;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002680 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302681 void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002682 {
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002683 if (!(this+coverage).intersects (c->glyphs))
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002684 return;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002685
2686 const ClassDef &backtrack_class_def = this+backtrackClassDef;
2687 const ClassDef &input_class_def = this+inputClassDef;
2688 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2689
2690 struct ChainContextClosureLookupContext lookup_context = {
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002691 {intersects_class},
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002692 {&backtrack_class_def,
2693 &input_class_def,
2694 &lookahead_class_def}
2695 };
2696
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07002697 return
2698 + hb_enumerate (ruleSet)
Behdad Esfahbod78d35f02019-05-15 18:15:05 -07002699 | hb_filter ([&] (unsigned _)
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07002700 { return input_class_def.intersects_class (c->glyphs, _); },
2701 hb_first)
2702 | hb_map (hb_second)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002703 | hb_map (hb_add (this))
2704 | hb_apply ([&] (const ChainRuleSet &_) { _.closure (c, lookup_context); })
Behdad Esfahbodf505b5d2019-03-29 22:55:02 -07002705 ;
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002706 }
2707
Qunxin Liu0b39c482019-10-22 16:00:43 -07002708 void closure_lookups (hb_closure_lookups_context_t *c) const
2709 {
2710 + hb_iter (ruleSet)
2711 | hb_map (hb_add (this))
2712 | hb_apply ([&] (const ChainRuleSet &_) { _.closure_lookups (c); })
2713 ;
2714 }
2715
Qunxin Liu8200e482020-02-26 13:11:42 -08002716 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
2717
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302718 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002719 {
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07002720 (this+coverage).collect_coverage (c->input);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002721
Behdad Esfahbod11fba792013-01-02 23:36:37 -06002722 const ClassDef &backtrack_class_def = this+backtrackClassDef;
2723 const ClassDef &input_class_def = this+inputClassDef;
2724 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2725
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002726 struct ChainContextCollectGlyphsLookupContext lookup_context = {
2727 {collect_class},
Behdad Esfahbod11fba792013-01-02 23:36:37 -06002728 {&backtrack_class_def,
2729 &input_class_def,
2730 &lookahead_class_def}
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002731 };
2732
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002733 + hb_iter (ruleSet)
Behdad Esfahbod23768672019-05-15 21:57:26 -07002734 | hb_map (hb_add (this))
2735 | hb_apply ([&] (const ChainRuleSet &_) { _.collect_glyphs (c, lookup_context); })
Behdad Esfahbod05f21302019-03-29 22:40:13 -07002736 ;
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002737 }
2738
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302739 bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002740 {
Behdad Esfahbod11fba792013-01-02 23:36:37 -06002741 const ClassDef &backtrack_class_def = this+backtrackClassDef;
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002742 const ClassDef &input_class_def = this+inputClassDef;
Behdad Esfahbod11fba792013-01-02 23:36:37 -06002743 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002744
Behdad Esfahbod2dc11412012-11-24 19:16:34 -05002745 unsigned int index = input_class_def.get_class (c->glyphs[0]);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002746 const ChainRuleSet &rule_set = this+ruleSet[index];
2747 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002748 {match_class},
Behdad Esfahbod11fba792013-01-02 23:36:37 -06002749 {&backtrack_class_def,
2750 &input_class_def,
2751 &lookahead_class_def}
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002752 };
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07002753 return rule_set.would_apply (c, lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002754 }
2755
Ebrahim Byagowie4120082018-12-17 21:31:01 +03302756 const Coverage &get_coverage () const { return this+coverage; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002757
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302758 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002759 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002760 TRACE_APPLY (this);
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05002761 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002762 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002763
2764 const ClassDef &backtrack_class_def = this+backtrackClassDef;
2765 const ClassDef &input_class_def = this+inputClassDef;
2766 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2767
Behdad Esfahbod2dc11412012-11-24 19:16:34 -05002768 index = input_class_def.get_class (c->buffer->cur().codepoint);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002769 const ChainRuleSet &rule_set = this+ruleSet[index];
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002770 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002771 {match_class},
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04002772 {&backtrack_class_def,
2773 &input_class_def,
2774 &lookahead_class_def}
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002775 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002776 return_trace (rule_set.apply (c, lookup_context));
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002777 }
2778
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302779 bool subset (hb_subset_context_t *c) const
Behdad Esfahbod339d3602018-09-03 17:33:34 -07002780 {
2781 TRACE_SUBSET (this);
Qunxin Liub66094a2019-09-30 16:19:18 -07002782 auto *out = c->serializer->start_embed (*this);
2783 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
2784 out->format = format;
ariza188a0a42020-03-07 11:02:36 -08002785 out->coverage.serialize_subset (c, coverage, this);
Qunxin Liub66094a2019-09-30 16:19:18 -07002786
2787 hb_map_t backtrack_klass_map;
ariza188a0a42020-03-07 11:02:36 -08002788 out->backtrackClassDef.serialize_subset (c, backtrackClassDef, this, &backtrack_klass_map);
Garret Rieger06dbb6a2020-07-31 15:56:14 -07002789 if (unlikely (!c->serializer->check_success (!backtrack_klass_map.in_error ())))
2790 return_trace (false);
Ebrahim Byagowiaca63902019-10-22 00:06:46 +03302791
Qunxin Liub66094a2019-09-30 16:19:18 -07002792 // subset inputClassDef based on glyphs survived in Coverage subsetting
2793 hb_map_t input_klass_map;
ariza188a0a42020-03-07 11:02:36 -08002794 out->inputClassDef.serialize_subset (c, inputClassDef, this, &input_klass_map);
Garret Rieger06dbb6a2020-07-31 15:56:14 -07002795 if (unlikely (!c->serializer->check_success (!input_klass_map.in_error ())))
2796 return_trace (false);
Qunxin Liub66094a2019-09-30 16:19:18 -07002797
2798 hb_map_t lookahead_klass_map;
ariza188a0a42020-03-07 11:02:36 -08002799 out->lookaheadClassDef.serialize_subset (c, lookaheadClassDef, this, &lookahead_klass_map);
Garret Rieger06dbb6a2020-07-31 15:56:14 -07002800 if (unlikely (!c->serializer->check_success (!lookahead_klass_map.in_error ())))
2801 return_trace (false);
Qunxin Liub66094a2019-09-30 16:19:18 -07002802
Qunxin Liu593e58c2020-05-20 18:00:25 -07002803 unsigned non_zero_index = 0, index = 0;
Qunxin Liub66094a2019-09-30 16:19:18 -07002804 bool ret = true;
Qunxin Liu593e58c2020-05-20 18:00:25 -07002805 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 -07002806 for (const OffsetTo<ChainRuleSet>& _ : + hb_enumerate (ruleSet)
2807 | hb_filter (input_klass_map, hb_first)
2808 | hb_map (hb_second))
2809 {
2810 auto *o = out->ruleSet.serialize_append (c->serializer);
2811 if (unlikely (!o))
2812 {
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04302813 ret = false;
2814 break;
Qunxin Liub66094a2019-09-30 16:19:18 -07002815 }
Qunxin Liu593e58c2020-05-20 18:00:25 -07002816 if (o->serialize_subset (c, _, this,
2817 lookup_map,
2818 &backtrack_klass_map,
2819 &input_klass_map,
2820 &lookahead_klass_map))
Ebrahim Byagowi5a7cc7f2020-07-29 08:33:32 +04302821 non_zero_index = index;
Qunxin Liu593e58c2020-05-20 18:00:25 -07002822
2823 index++;
Qunxin Liub66094a2019-09-30 16:19:18 -07002824 }
2825
2826 if (!ret) return_trace (ret);
2827
2828 //prune empty trailing ruleSets
Qunxin Liu593e58c2020-05-20 18:00:25 -07002829 --index;
2830 while (index > non_zero_index)
Qunxin Liub66094a2019-09-30 16:19:18 -07002831 {
2832 out->ruleSet.pop ();
Qunxin Liu593e58c2020-05-20 18:00:25 -07002833 index--;
Qunxin Liub66094a2019-09-30 16:19:18 -07002834 }
2835
2836 return_trace (bool (out->ruleSet));
Behdad Esfahbod339d3602018-09-03 17:33:34 -07002837 }
2838
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302839 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002840 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002841 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002842 return_trace (coverage.sanitize (c, this) &&
2843 backtrackClassDef.sanitize (c, this) &&
2844 inputClassDef.sanitize (c, this) &&
2845 lookaheadClassDef.sanitize (c, this) &&
2846 ruleSet.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002847 }
2848
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002849 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002850 HBUINT16 format; /* Format identifier--format = 2 */
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002851 OffsetTo<Coverage>
2852 coverage; /* Offset to Coverage table--from
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002853 * beginning of table */
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002854 OffsetTo<ClassDef>
2855 backtrackClassDef; /* Offset to glyph ClassDef table
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002856 * containing backtrack sequence
2857 * data--from beginning of table */
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002858 OffsetTo<ClassDef>
2859 inputClassDef; /* Offset to glyph ClassDef
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002860 * table containing input sequence
2861 * data--from beginning of table */
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002862 OffsetTo<ClassDef>
2863 lookaheadClassDef; /* Offset to glyph ClassDef table
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002864 * containing lookahead sequence
2865 * data--from beginning of table */
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002866 OffsetArrayOf<ChainRuleSet>
2867 ruleSet; /* Array of ChainRuleSet tables
2868 * ordered by class */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04002869 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04002870 DEFINE_SIZE_ARRAY (12, ruleSet);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002871};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002872
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002873struct ChainContextFormat3
2874{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302875 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002876 {
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002877 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002878
2879 if (!(this+input[0]).intersects (glyphs))
2880 return false;
2881
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002882 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002883 struct ChainContextClosureLookupContext lookup_context = {
2884 {intersects_coverage},
2885 {this, this, this}
2886 };
2887 return chain_context_intersects (glyphs,
2888 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2889 input.len, (const HBUINT16 *) input.arrayZ + 1,
2890 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2891 lookup_context);
2892 }
2893
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302894 void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002895 {
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002896 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002897
2898 if (!(this+input[0]).intersects (c->glyphs))
2899 return;
2900
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002901 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
2902 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002903 struct ChainContextClosureLookupContext lookup_context = {
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002904 {intersects_coverage},
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002905 {this, this, this}
2906 };
2907 chain_context_closure_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002908 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2909 input.len, (const HBUINT16 *) input.arrayZ + 1,
2910 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2911 lookup.len, lookup.arrayZ,
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002912 lookup_context);
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002913 }
2914
Qunxin Liu0b39c482019-10-22 16:00:43 -07002915 void closure_lookups (hb_closure_lookups_context_t *c) const
2916 {
2917 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
2918 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
2919 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
2920 recurse_lookups (c, lookup.len, lookup.arrayZ);
2921 }
2922
Qunxin Liu8200e482020-02-26 13:11:42 -08002923 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const {}
2924
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302925 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002926 {
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002927 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002928
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07002929 (this+input[0]).collect_coverage (c->input);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002930
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002931 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
2932 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002933 struct ChainContextCollectGlyphsLookupContext lookup_context = {
2934 {collect_coverage},
2935 {this, this, this}
2936 };
2937 chain_context_collect_glyphs_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002938 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2939 input.len, (const HBUINT16 *) input.arrayZ + 1,
2940 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2941 lookup.len, lookup.arrayZ,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002942 lookup_context);
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002943 }
2944
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302945 bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002946 {
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002947 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
2948 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
2949 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002950 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002951 {match_coverage},
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002952 {this, this, this}
2953 };
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07002954 return chain_context_would_apply_lookup (c,
2955 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2956 input.len, (const HBUINT16 *) input.arrayZ + 1,
2957 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2958 lookup.len, lookup.arrayZ, lookup_context);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002959 }
2960
Ebrahim Byagowie4120082018-12-17 21:31:01 +03302961 const Coverage &get_coverage () const
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002962 {
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002963 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002964 return this+input[0];
2965 }
2966
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03302967 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002968 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002969 TRACE_APPLY (this);
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002970 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04002971
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05002972 unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002973 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002974
Ebrahim Byagowi92588782019-04-30 13:05:10 -07002975 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
2976 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002977 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002978 {match_coverage},
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04002979 {this, this, this}
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04002980 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002981 return_trace (chain_context_apply_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002982 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2983 input.len, (const HBUINT16 *) input.arrayZ + 1,
2984 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2985 lookup.len, lookup.arrayZ, lookup_context));
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002986 }
2987
Qunxin Liub66094a2019-09-30 16:19:18 -07002988 template<typename Iterator,
2989 hb_requires (hb_is_iterator (Iterator))>
Ebrahim Byagowi07acd1a2020-03-08 23:39:24 +03302990 bool serialize_coverage_offsets (hb_subset_context_t *c, Iterator it, const void* base) const
Qunxin Liub66094a2019-09-30 16:19:18 -07002991 {
2992 TRACE_SERIALIZE (this);
2993 auto *out = c->serializer->start_embed<OffsetArrayOf<Coverage>> ();
2994
2995 if (unlikely (!c->serializer->allocate_size<HBUINT16> (HBUINT16::static_size))) return_trace (false);
2996
2997 + it
Ebrahim Byagowi07acd1a2020-03-08 23:39:24 +03302998 | hb_apply (subset_offset_array (c, *out, base))
Qunxin Liub66094a2019-09-30 16:19:18 -07002999 ;
3000
3001 return_trace (out->len);
3002 }
3003
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303004 bool subset (hb_subset_context_t *c) const
Behdad Esfahbod339d3602018-09-03 17:33:34 -07003005 {
3006 TRACE_SUBSET (this);
Qunxin Liub66094a2019-09-30 16:19:18 -07003007
3008 auto *out = c->serializer->start_embed (this);
3009 if (unlikely (!out)) return_trace (false);
3010 if (unlikely (!c->serializer->embed (this->format))) return_trace (false);
3011
ariza188a0a42020-03-07 11:02:36 -08003012 if (!serialize_coverage_offsets (c, backtrack.iter (), this))
Qunxin Liub66094a2019-09-30 16:19:18 -07003013 return_trace (false);
Ebrahim Byagowiaca63902019-10-22 00:06:46 +03303014
Qunxin Liub66094a2019-09-30 16:19:18 -07003015 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
ariza188a0a42020-03-07 11:02:36 -08003016 if (!serialize_coverage_offsets (c, input.iter (), this))
Qunxin Liub66094a2019-09-30 16:19:18 -07003017 return_trace (false);
3018
3019 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
ariza188a0a42020-03-07 11:02:36 -08003020 if (!serialize_coverage_offsets (c, lookahead.iter (), this))
Qunxin Liub66094a2019-09-30 16:19:18 -07003021 return_trace (false);
Ebrahim Byagowiaca63902019-10-22 00:06:46 +03303022
Qunxin Liu593e58c2020-05-20 18:00:25 -07003023 const ArrayOf<LookupRecord> &lookupRecord = StructAfter<ArrayOf<LookupRecord>> (lookahead);
3024 HBUINT16 lookupCount;
3025 lookupCount = lookupRecord.len;
3026 if (!c->serializer->copy (lookupCount)) return_trace (false);
3027
3028 const hb_map_t *lookup_map = c->table_tag == HB_OT_TAG_GSUB ? c->plan->gsub_lookups : c->plan->gpos_lookups;
3029 for (unsigned i = 0; i < (unsigned) lookupCount; i++)
3030 if (!c->serializer->copy (lookupRecord[i], lookup_map)) return_trace (false);
Ebrahim Byagowid0e2add2020-07-18 22:14:52 +04303031
Qunxin Liu593e58c2020-05-20 18:00:25 -07003032 return_trace (true);
Behdad Esfahbod339d3602018-09-03 17:33:34 -07003033 }
3034
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303035 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03003036 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05003037 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003038 if (!backtrack.sanitize (c, this)) return_trace (false);
Ebrahim Byagowi92588782019-04-30 13:05:10 -07003039 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003040 if (!input.sanitize (c, this)) return_trace (false);
3041 if (!input.len) return_trace (false); /* To be consistent with Context. */
Ebrahim Byagowi92588782019-04-30 13:05:10 -07003042 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003043 if (!lookahead.sanitize (c, this)) return_trace (false);
Ebrahim Byagowi92588782019-04-30 13:05:10 -07003044 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003045 return_trace (lookup.sanitize (c));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04003046 }
3047
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04003048 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01003049 HBUINT16 format; /* Format identifier--format = 3 */
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04003050 OffsetArrayOf<Coverage>
Behdad Esfahbod13ed4402009-05-18 02:14:37 -04003051 backtrack; /* Array of coverage tables
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003052 * in backtracking sequence, in glyph
3053 * sequence order */
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04003054 OffsetArrayOf<Coverage>
Behdad Esfahbod13ed4402009-05-18 02:14:37 -04003055 inputX ; /* Array of coverage
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003056 * tables in input sequence, in glyph
3057 * sequence order */
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04003058 OffsetArrayOf<Coverage>
Behdad Esfahbod13ed4402009-05-18 02:14:37 -04003059 lookaheadX; /* Array of coverage tables
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003060 * in lookahead sequence, in glyph
3061 * sequence order */
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04003062 ArrayOf<LookupRecord>
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04003063 lookupX; /* Array of LookupRecords--in
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04003064 * design order) */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04003065 public:
Behdad Esfahbodbea34c72010-05-10 17:28:16 -04003066 DEFINE_SIZE_MIN (10);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003067};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003068
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04003069struct ChainContext
3070{
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -07003071 template <typename context_t, typename ...Ts>
Behdad Esfahbod83e3eab2019-05-07 20:58:43 -07003072 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04003073 {
Behdad Esfahbod00f6a8e2014-12-12 20:36:49 -08003074 TRACE_DISPATCH (this, u.format);
Behdad Esfahbodf396fbb2015-10-09 12:25:55 -04003075 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04003076 switch (u.format) {
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -07003077 case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
3078 case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
3079 case 3: return_trace (c->dispatch (u.format3, hb_forward<Ts> (ds)...));
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003080 default:return_trace (c->default_return_value ());
Behdad Esfahbode72b3602012-07-19 14:35:23 -04003081 }
3082 }
3083
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04003084 protected:
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003085 union {
Behdad Esfahbod6b191782018-01-10 03:07:30 +01003086 HBUINT16 format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -04003087 ChainContextFormat1 format1;
3088 ChainContextFormat2 format2;
3089 ChainContextFormat3 format3;
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003090 } u;
3091};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04003092
3093
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003094template <typename T>
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003095struct ExtensionFormat1
3096{
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303097 unsigned int get_type () const { return extensionLookupType; }
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003098
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003099 template <typename X>
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303100 const X& get_subtable () const
Behdad Esfahbod858b6272019-12-10 13:18:32 -06003101 { return this + reinterpret_cast<const LOffsetTo<typename T::SubTable> &> (extensionOffset); }
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003102
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -07003103 template <typename context_t, typename ...Ts>
Behdad Esfahbod83e3eab2019-05-07 20:58:43 -07003104 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003105 {
3106 TRACE_DISPATCH (this, format);
Behdad Esfahbodf396fbb2015-10-09 12:25:55 -04003107 if (unlikely (!c->may_dispatch (this, this))) return_trace (c->no_dispatch_return_value ());
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -07003108 return_trace (get_subtable<typename T::SubTable> ().dispatch (c, get_type (), hb_forward<Ts> (ds)...));
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003109 }
3110
Qunxin Liu8200e482020-02-26 13:11:42 -08003111 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
3112 { dispatch (c); }
3113
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003114 /* This is called from may_dispatch() above with hb_sanitize_context_t. */
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303115 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03003116 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05003117 TRACE_SANITIZE (this);
Behdad Esfahbod949f6af2018-01-15 20:44:10 -05003118 return_trace (c->check_struct (this) &&
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07003119 extensionLookupType != T::SubTable::Extension);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04003120 }
3121
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04003122 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01003123 HBUINT16 format; /* Format identifier. Set to 1. */
3124 HBUINT16 extensionLookupType; /* Lookup type of subtable referenced
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003125 * by ExtensionOffset (i.e. the
3126 * extension subtable). */
Behdad Esfahbodcd9bc732019-05-10 13:17:41 -07003127 Offset32 extensionOffset; /* Offset to the extension subtable,
Behdad Esfahbod81f2af42010-04-22 00:58:49 -04003128 * of lookup type subtable. */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04003129 public:
3130 DEFINE_SIZE_STATIC (8);
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003131};
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003132
Behdad Esfahbod653eeb22012-11-23 16:57:36 -05003133template <typename T>
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003134struct Extension
3135{
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303136 unsigned int get_type () const
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003137 {
3138 switch (u.format) {
Behdad Esfahboddacebca2010-05-10 19:45:41 -04003139 case 1: return u.format1.get_type ();
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003140 default:return 0;
3141 }
3142 }
Behdad Esfahbod7dddd4e2012-11-23 17:04:55 -05003143 template <typename X>
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303144 const X& get_subtable () const
Behdad Esfahbod7dddd4e2012-11-23 17:04:55 -05003145 {
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003146 switch (u.format) {
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07003147 case 1: return u.format1.template get_subtable<typename T::SubTable> ();
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04303148 default:return Null (typename T::SubTable);
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003149 }
Behdad Esfahbod7dddd4e2012-11-23 17:04:55 -05003150 }
3151
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -07003152 template <typename context_t, typename ...Ts>
Behdad Esfahbod83e3eab2019-05-07 20:58:43 -07003153 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
Behdad Esfahbod653eeb22012-11-23 16:57:36 -05003154 {
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003155 TRACE_DISPATCH (this, u.format);
Behdad Esfahbodf396fbb2015-10-09 12:25:55 -04003156 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04003157 switch (u.format) {
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -07003158 case 1: return_trace (u.format1.dispatch (c, hb_forward<Ts> (ds)...));
Behdad Esfahbodb4715902015-09-29 14:57:02 +01003159 default:return_trace (c->default_return_value ());
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04003160 }
3161 }
3162
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04003163 protected:
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003164 union {
Behdad Esfahbod6b191782018-01-10 03:07:30 +01003165 HBUINT16 format; /* Format identifier */
Behdad Esfahbod095a1252015-02-19 10:29:41 +03003166 ExtensionFormat1<T> format1;
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003167 } u;
3168};
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04003169
3170
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04003171/*
3172 * GSUB/GPOS Common
3173 */
3174
Behdad Esfahbod97e59132018-10-10 11:41:05 -04003175struct hb_ot_layout_lookup_accelerator_t
3176{
3177 template <typename TLookup>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303178 void init (const TLookup &lookup)
Behdad Esfahbod97e59132018-10-10 11:41:05 -04003179 {
3180 digest.init ();
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07003181 lookup.collect_coverage (&digest);
Behdad Esfahbod78c09bf2018-10-10 11:50:46 -04003182
3183 subtables.init ();
3184 OT::hb_get_subtables_context_t c_get_subtables (subtables);
3185 lookup.dispatch (&c_get_subtables);
Behdad Esfahbod97e59132018-10-10 11:41:05 -04003186 }
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303187 void fini () { subtables.fini (); }
Behdad Esfahbod97e59132018-10-10 11:41:05 -04003188
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303189 bool may_have (hb_codepoint_t g) const
Behdad Esfahbod97e59132018-10-10 11:41:05 -04003190 { return digest.may_have (g); }
3191
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303192 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbode78549e2018-10-10 11:54:48 -04003193 {
Behdad Esfahbod474a1202018-12-21 18:46:51 -05003194 for (unsigned int i = 0; i < subtables.length; i++)
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03303195 if (subtables[i].apply (c))
3196 return true;
3197 return false;
Behdad Esfahbode78549e2018-10-10 11:54:48 -04003198 }
3199
3200 private:
Behdad Esfahbod97e59132018-10-10 11:41:05 -04003201 hb_set_digest_t digest;
Behdad Esfahbod78c09bf2018-10-10 11:50:46 -04003202 hb_get_subtables_context_t::array_t subtables;
Behdad Esfahbod97e59132018-10-10 11:41:05 -04003203};
3204
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04003205struct GSUBGPOS
3206{
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303207 bool has_data () const { return version.to_int (); }
3208 unsigned int get_script_count () const
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04003209 { return (this+scriptList).len; }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303210 const Tag& get_script_tag (unsigned int i) const
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04003211 { return (this+scriptList).get_tag (i); }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303212 unsigned int get_script_tags (unsigned int start_offset,
3213 unsigned int *script_count /* IN/OUT */,
3214 hb_tag_t *script_tags /* OUT */) const
Behdad Esfahbode21899b2009-11-04 16:36:14 -05003215 { return (this+scriptList).get_tags (start_offset, script_count, script_tags); }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303216 const Script& get_script (unsigned int i) const
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04003217 { return (this+scriptList)[i]; }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303218 bool find_script_index (hb_tag_t tag, unsigned int *index) const
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04003219 { return (this+scriptList).find_index (tag, index); }
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04003220
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303221 unsigned int get_feature_count () const
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04003222 { return (this+featureList).len; }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303223 hb_tag_t get_feature_tag (unsigned int i) const
Jonathan Kewda132932014-04-27 14:05:24 +01003224 { return i == Index::NOT_FOUND_INDEX ? HB_TAG_NONE : (this+featureList).get_tag (i); }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303225 unsigned int get_feature_tags (unsigned int start_offset,
3226 unsigned int *feature_count /* IN/OUT */,
3227 hb_tag_t *feature_tags /* OUT */) const
Behdad Esfahbode21899b2009-11-04 16:36:14 -05003228 { return (this+featureList).get_tags (start_offset, feature_count, feature_tags); }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303229 const Feature& get_feature (unsigned int i) const
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04003230 { return (this+featureList)[i]; }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303231 bool find_feature_index (hb_tag_t tag, unsigned int *index) const
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04003232 { return (this+featureList).find_index (tag, index); }
3233
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303234 unsigned int get_lookup_count () const
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04003235 { return (this+lookupList).len; }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303236 const Lookup& get_lookup (unsigned int i) const
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04003237 { return (this+lookupList)[i]; }
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04003238
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303239 bool find_variations_index (const int *coords, unsigned int num_coords,
3240 unsigned int *index) const
Behdad Esfahboda8498732019-06-19 19:26:22 -07003241 {
Qunxin Liu0b39c482019-10-22 16:00:43 -07003242#ifdef HB_NO_VAR
Ebrahim Byagowi2e1bf612020-03-26 22:59:26 +04303243 *index = FeatureVariations::NOT_FOUND_INDEX;
Behdad Esfahboda8498732019-06-19 19:26:22 -07003244 return false;
3245#endif
Ebrahim Byagowi071e2e32020-03-26 12:01:53 +04303246 return (version.to_int () >= 0x00010001u ? this+featureVars : Null (FeatureVariations))
Behdad Esfahboda8498732019-06-19 19:26:22 -07003247 .find_index (coords, num_coords, index);
3248 }
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303249 const Feature& get_feature_variation (unsigned int feature_index,
Behdad Esfahbod3d9a6e62019-01-22 12:02:06 +01003250 unsigned int variations_index) const
Behdad Esfahbodec87ba92016-09-10 03:53:11 -07003251 {
Behdad Esfahboda8498732019-06-19 19:26:22 -07003252#ifndef HB_NO_VAR
Behdad Esfahbodec87ba92016-09-10 03:53:11 -07003253 if (FeatureVariations::NOT_FOUND_INDEX != variations_index &&
3254 version.to_int () >= 0x00010001u)
3255 {
Behdad Esfahbod4ebbeb72016-09-10 04:52:34 -07003256 const Feature *feature = (this+featureVars).find_substitute (variations_index,
3257 feature_index);
Behdad Esfahbodec87ba92016-09-10 03:53:11 -07003258 if (feature)
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03303259 return *feature;
Behdad Esfahbodec87ba92016-09-10 03:53:11 -07003260 }
Behdad Esfahboda8498732019-06-19 19:26:22 -07003261#endif
Behdad Esfahbodec87ba92016-09-10 03:53:11 -07003262 return get_feature (feature_index);
3263 }
Behdad Esfahbod59055b52016-09-10 01:24:28 -07003264
Qunxin Liu0b39c482019-10-22 16:00:43 -07003265 void feature_variation_collect_lookups (const hb_set_t *feature_indexes,
3266 hb_set_t *lookup_indexes /* OUT */) const
3267 {
3268#ifndef HB_NO_VAR
3269 if (version.to_int () >= 0x00010001u)
3270 (this+featureVars).collect_lookups (feature_indexes, lookup_indexes);
3271#endif
3272 }
3273
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07003274 template <typename TLookup>
Qunxin Liu973c47f2020-06-11 11:27:57 -07003275 void closure_lookups (hb_face_t *face,
3276 const hb_set_t *glyphs,
Ebrahim Byagowi5a7cc7f2020-07-29 08:33:32 +04303277 hb_set_t *lookup_indexes /* IN/OUT */) const
Qunxin Liu973c47f2020-06-11 11:27:57 -07003278 {
3279 hb_set_t visited_lookups, inactive_lookups;
3280 OT::hb_closure_lookups_context_t c (face, glyphs, &visited_lookups, &inactive_lookups);
3281
3282 for (unsigned lookup_index : + hb_iter (lookup_indexes))
3283 reinterpret_cast<const TLookup &> (get_lookup (lookup_index)).closure_lookups (&c, lookup_index);
3284
3285 hb_set_union (lookup_indexes, &visited_lookups);
3286 hb_set_subtract (lookup_indexes, &inactive_lookups);
3287 }
3288
3289 template <typename TLookup>
Qunxin Liue565d1f2019-11-01 10:21:36 -07003290 bool subset (hb_subset_layout_context_t *c) const
Behdad Esfahbodbfa72a92018-09-01 18:34:50 -07003291 {
3292 TRACE_SUBSET (this);
Qunxin Liue565d1f2019-11-01 10:21:36 -07003293 auto *out = c->subset_context->serializer->embed (*this);
Behdad Esfahbodbfa72a92018-09-01 18:34:50 -07003294 if (unlikely (!out)) return_trace (false);
Behdad Esfahbod1b6d0c42018-12-13 18:10:48 -05003295
Qunxin Liue565d1f2019-11-01 10:21:36 -07003296 typedef LookupOffsetList<TLookup> TLookupList;
Behdad Esfahbod858b6272019-12-10 13:18:32 -06003297 reinterpret_cast<OffsetTo<TLookupList> &> (out->lookupList)
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04303298 .serialize_subset (c->subset_context,
Qunxin Liue565d1f2019-11-01 10:21:36 -07003299 reinterpret_cast<const OffsetTo<TLookupList> &> (lookupList),
3300 this,
Qunxin Liue565d1f2019-11-01 10:21:36 -07003301 c);
3302
3303 reinterpret_cast<OffsetTo<RecordListOfFeature> &> (out->featureList)
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04303304 .serialize_subset (c->subset_context,
Qunxin Liue565d1f2019-11-01 10:21:36 -07003305 reinterpret_cast<const OffsetTo<RecordListOfFeature> &> (featureList),
3306 this,
Qunxin Liue565d1f2019-11-01 10:21:36 -07003307 c);
3308
3309 out->scriptList.serialize_subset (c->subset_context,
3310 scriptList,
3311 this,
Qunxin Liue565d1f2019-11-01 10:21:36 -07003312 c);
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07003313
Behdad Esfahboda8498732019-06-19 19:26:22 -07003314#ifndef HB_NO_VAR
Behdad Esfahbodbfa72a92018-09-01 18:34:50 -07003315 if (version.to_int () >= 0x00010001u)
Qunxin Liue565d1f2019-11-01 10:21:36 -07003316 {
ariza188a0a42020-03-07 11:02:36 -08003317 bool ret = out->featureVars.serialize_subset (c->subset_context, featureVars, this, c);
Qunxin Liue565d1f2019-11-01 10:21:36 -07003318 if (!ret)
3319 {
Ebrahim Byagowi2dda6dd2020-04-20 14:12:45 +04303320 out->version.major = 1;
3321 out->version.minor = 0;
Qunxin Liue565d1f2019-11-01 10:21:36 -07003322 }
3323 }
Behdad Esfahboda8498732019-06-19 19:26:22 -07003324#endif
Behdad Esfahbod1b6d0c42018-12-13 18:10:48 -05003325
Behdad Esfahbodbfa72a92018-09-01 18:34:50 -07003326 return_trace (true);
3327 }
3328
Qunxin Liu8ffc9ad2019-10-31 15:59:02 -07003329 void closure_features (const hb_map_t *lookup_indexes, /* IN */
3330 hb_set_t *feature_indexes /* OUT */) const
3331 {
Garret Rieger414529e2020-02-28 15:15:55 -08003332 unsigned int feature_count = hb_min (get_feature_count (), (unsigned) HB_MAX_FEATURES);
Garret Rieger75622b02020-02-28 14:11:48 -08003333 for (unsigned i = 0; i < feature_count; i++)
Qunxin Liu8ffc9ad2019-10-31 15:59:02 -07003334 {
Qunxin Liud7c012a2020-02-26 13:11:42 -08003335 const Feature& f = get_feature (i);
3336 if ((!f.featureParams.is_null ()) || f.intersects_lookup_indexes (lookup_indexes))
Ebrahim Byagowi5a7cc7f2020-07-29 08:33:32 +04303337 feature_indexes->add (i);
Qunxin Liu8ffc9ad2019-10-31 15:59:02 -07003338 }
3339#ifndef HB_NO_VAR
3340 if (version.to_int () >= 0x00010001u)
3341 (this+featureVars).closure_features (lookup_indexes, feature_indexes);
3342#endif
3343 }
3344
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303345 unsigned int get_size () const
Behdad Esfahbodbfa72a92018-09-01 18:34:50 -07003346 {
3347 return min_size +
3348 (version.to_int () >= 0x00010001u ? featureVars.static_size : 0);
3349 }
3350
Behdad Esfahbod6d618522018-09-03 16:41:28 -07003351 template <typename TLookup>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303352 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03003353 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05003354 TRACE_SANITIZE (this);
Behdad Esfahbod6d618522018-09-03 16:41:28 -07003355 typedef OffsetListOf<TLookup> TLookupList;
Behdad Esfahbod8e3cde62019-06-19 19:58:24 -07003356 if (unlikely (!(version.sanitize (c) &&
3357 likely (version.major == 1) &&
3358 scriptList.sanitize (c, this) &&
3359 featureList.sanitize (c, this) &&
Behdad Esfahbod858b6272019-12-10 13:18:32 -06003360 reinterpret_cast<const OffsetTo<TLookupList> &> (lookupList).sanitize (c, this))))
Behdad Esfahbod8e3cde62019-06-19 19:58:24 -07003361 return_trace (false);
3362
Behdad Esfahboda8498732019-06-19 19:26:22 -07003363#ifndef HB_NO_VAR
Behdad Esfahbod8e3cde62019-06-19 19:58:24 -07003364 if (unlikely (!(version.to_int () < 0x00010001u || featureVars.sanitize (c, this))))
3365 return_trace (false);
Behdad Esfahboda8498732019-06-19 19:26:22 -07003366#endif
Behdad Esfahbod8e3cde62019-06-19 19:58:24 -07003367
3368 return_trace (true);
Behdad Esfahbodcd3827e2009-08-04 02:09:34 -04003369 }
3370
Behdad Esfahbod963413f2018-08-26 00:47:55 -07003371 template <typename T>
3372 struct accelerator_t
3373 {
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03303374 void init (hb_face_t *face)
Behdad Esfahbod963413f2018-08-26 00:47:55 -07003375 {
Ebrahim Byagowiba22df32020-03-10 10:42:20 +03303376 this->table = hb_sanitize_context_t ().reference_table<T> (face);
Behdad Esfahbod56719472020-06-05 12:57:23 -07003377 if (unlikely (this->table->is_blocklisted (this->table.get_blob (), face)))
Behdad Esfahbod574d8882018-11-25 16:51:22 -05003378 {
3379 hb_blob_destroy (this->table.get_blob ());
3380 this->table = hb_blob_get_empty ();
3381 }
Behdad Esfahbod963413f2018-08-26 00:47:55 -07003382
Behdad Esfahbodb9291002018-08-26 01:15:47 -07003383 this->lookup_count = table->get_lookup_count ();
Behdad Esfahbod963413f2018-08-26 00:47:55 -07003384
3385 this->accels = (hb_ot_layout_lookup_accelerator_t *) calloc (this->lookup_count, sizeof (hb_ot_layout_lookup_accelerator_t));
3386 if (unlikely (!this->accels))
Dominik Röttschesa5f6f862020-10-23 14:25:05 +03003387 {
Ebrahim Byagowi11aa0462018-11-15 23:10:56 +03303388 this->lookup_count = 0;
Behdad Esfahbod53806e52020-11-25 11:51:37 -07003389 this->table.destroy ();
Dominik Röttschesa5f6f862020-10-23 14:25:05 +03003390 this->table = hb_blob_get_empty ();
3391 }
Behdad Esfahbod963413f2018-08-26 00:47:55 -07003392
3393 for (unsigned int i = 0; i < this->lookup_count; i++)
Behdad Esfahbodb9291002018-08-26 01:15:47 -07003394 this->accels[i].init (table->get_lookup (i));
Behdad Esfahbod963413f2018-08-26 00:47:55 -07003395 }
3396
Ebrahim Byagowie4120082018-12-17 21:31:01 +03303397 void fini ()
Behdad Esfahbod963413f2018-08-26 00:47:55 -07003398 {
Behdad Esfahbodb9291002018-08-26 01:15:47 -07003399 for (unsigned int i = 0; i < this->lookup_count; i++)
3400 this->accels[i].fini ();
3401 free (this->accels);
Behdad Esfahbodda6aa3b2018-11-11 11:40:57 -05003402 this->table.destroy ();
Behdad Esfahbod963413f2018-08-26 00:47:55 -07003403 }
3404
Behdad Esfahbod5d0078a2018-11-10 23:52:15 -05003405 hb_blob_ptr_t<T> table;
Behdad Esfahbodb9291002018-08-26 01:15:47 -07003406 unsigned int lookup_count;
3407 hb_ot_layout_lookup_accelerator_t *accels;
Behdad Esfahbod963413f2018-08-26 00:47:55 -07003408 };
3409
Behdad Esfahbod212aba62009-05-24 00:50:27 -04003410 protected:
Behdad Esfahbod9a13ed42016-02-22 11:44:45 +09003411 FixedVersion<>version; /* Version of the GSUB/GPOS table--initially set
Behdad Esfahbod76271002014-07-11 14:54:42 -04003412 * to 0x00010000u */
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04003413 OffsetTo<ScriptList>
Ebrahim Byagowice114d62019-12-31 15:53:02 +03303414 scriptList; /* ScriptList table */
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04003415 OffsetTo<FeatureList>
Ebrahim Byagowice114d62019-12-31 15:53:02 +03303416 featureList; /* FeatureList table */
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04003417 OffsetTo<LookupList>
Ebrahim Byagowice114d62019-12-31 15:53:02 +03303418 lookupList; /* LookupList table */
Behdad Esfahbod5e156fa2017-01-22 20:28:56 -08003419 LOffsetTo<FeatureVariations>
Behdad Esfahbod59055b52016-09-10 01:24:28 -07003420 featureVars; /* Offset to Feature Variations
3421 table--from beginning of table
3422 * (may be NULL). Introduced
3423 * in version 0x00010001. */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04003424 public:
Behdad Esfahbod59055b52016-09-10 01:24:28 -07003425 DEFINE_SIZE_MIN (10);
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04003426};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04003427
Behdad Esfahbod6f20f722009-05-17 20:28:01 -04003428
Behdad Esfahbod7d52e662012-11-16 18:49:54 -08003429} /* namespace OT */
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -04003430
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04003431
Behdad Esfahbodc77ae402018-08-25 22:36:36 -07003432#endif /* HB_OT_LAYOUT_GSUBGPOS_HH */