blob: 6ff19e2320dac4838547f70fc8f42d9f45c3b3e6 [file] [log] [blame]
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001/*
Behdad Esfahbod2409d5f2011-04-21 17:14:28 -04002 * Copyright © 2007,2008,2009,2010 Red Hat, Inc.
Behdad Esfahbod5b93e8d2012-04-23 22:26:13 -04003 * Copyright © 2010,2012 Google, Inc.
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04004 *
Behdad Esfahbodc755cb32010-04-22 00:11:43 -04005 * This is part of HarfBuzz, a text shaping library.
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04006 *
7 * Permission is hereby granted, without written agreement and without
8 * license or royalty fees, to use, copy, modify, and distribute this
9 * software and its documentation for any purpose, provided that the
10 * above copyright notice and the following two paragraphs appear in
11 * all copies of this software.
12 *
13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
17 * DAMAGE.
18 *
19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24 *
25 * Red Hat Author(s): Behdad Esfahbod
Behdad Esfahbod98370e82010-10-27 17:39:01 -040026 * Google Author(s): Behdad Esfahbod
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -040027 */
28
Behdad Esfahbodc77ae402018-08-25 22:36:36 -070029#ifndef HB_OT_LAYOUT_GSUBGPOS_HH
30#define HB_OT_LAYOUT_GSUBGPOS_HH
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -040031
Behdad Esfahbodc77ae402018-08-25 22:36:36 -070032#include "hb.hh"
33#include "hb-buffer.hh"
34#include "hb-map.hh"
Behdad Esfahbodc77ae402018-08-25 22:36:36 -070035#include "hb-set.hh"
Behdad Esfahbod71c9f842018-09-10 22:37:19 +020036#include "hb-ot-map.hh"
Behdad Esfahbodb9291002018-08-26 01:15:47 -070037#include "hb-ot-layout-common.hh"
38#include "hb-ot-layout-gdef-table.hh"
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -040039
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -040040
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -040041namespace OT {
42
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -040043
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -070044struct hb_intersects_context_t :
45 hb_dispatch_context_t<hb_intersects_context_t, bool, 0>
46{
47 inline const char *get_name (void) { return "INTERSECTS"; }
48 template <typename T>
49 inline return_t dispatch (const T &obj) { return obj.intersects (this->glyphs); }
50 static return_t default_return_value (void) { return false; }
51 bool stop_sublookup_iteration (return_t r) const { return r; }
52
53 const hb_set_t *glyphs;
54 unsigned int debug_depth;
55
56 hb_intersects_context_t (const hb_set_t *glyphs_) :
57 glyphs (glyphs_),
58 debug_depth (0) {}
59};
60
Behdad Esfahbod77a1a2b2015-10-09 12:20:58 -040061struct hb_closure_context_t :
62 hb_dispatch_context_t<hb_closure_context_t, hb_void_t, HB_DEBUG_CLOSURE>
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -040063{
Behdad Esfahboda1733db2012-11-23 16:40:04 -050064 inline const char *get_name (void) { return "CLOSURE"; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -050065 typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
66 template <typename T>
Behdad Esfahbod9c5a9ee2013-03-09 01:55:04 -050067 inline return_t dispatch (const T &obj) { obj.closure (this); return HB_VOID; }
Behdad Esfahbod130bb3f2012-12-05 16:49:47 -050068 static return_t default_return_value (void) { return HB_VOID; }
Behdad Esfahbod7b912c12013-01-04 01:25:27 -060069 bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -070070 void recurse (unsigned int lookup_index)
Behdad Esfahbod44fc2372012-11-21 23:33:13 -050071 {
Behdad Esfahbod9b346772012-11-23 17:55:40 -050072 if (unlikely (nesting_level_left == 0 || !recurse_func))
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -070073 return;
Behdad Esfahbod44fc2372012-11-21 23:33:13 -050074
75 nesting_level_left--;
76 recurse_func (this, lookup_index);
77 nesting_level_left++;
Behdad Esfahbod44fc2372012-11-21 23:33:13 -050078 }
79
Behdad Esfahbodba0ea562018-06-11 23:24:41 -040080 bool should_visit_lookup (unsigned int lookup_index)
Garret Rieger45186b92018-06-05 17:14:42 -070081 {
82 if (is_lookup_done (lookup_index))
83 return false;
84 done_lookups->set (lookup_index, glyphs->get_population ());
85 return true;
86 }
87
88 bool is_lookup_done (unsigned int lookup_index)
89 {
Behdad Esfahbodc38bd402018-07-24 09:43:27 -070090 /* Have we visited this lookup with the current set of glyphs? */
Garret Rieger45186b92018-06-05 17:14:42 -070091 return done_lookups->get (lookup_index) == glyphs->get_population ();
92 }
93
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -040094 hb_face_t *face;
Behdad Esfahbod6a9be5b2012-04-23 22:23:17 -040095 hb_set_t *glyphs;
Behdad Esfahbod6b11fea2018-07-25 16:01:37 -070096 hb_auto_t<hb_set_t> out[1];
Behdad Esfahbod44fc2372012-11-21 23:33:13 -050097 recurse_func_t recurse_func;
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -040098 unsigned int nesting_level_left;
99 unsigned int debug_depth;
100
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400101 hb_closure_context_t (hb_face_t *face_,
Behdad Esfahbod6a9be5b2012-04-23 22:23:17 -0400102 hb_set_t *glyphs_,
Garret Rieger45186b92018-06-05 17:14:42 -0700103 hb_map_t *done_lookups_,
Behdad Esfahbod5ba45042015-11-02 15:43:08 -0800104 unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400105 face (face_),
106 glyphs (glyphs_),
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200107 recurse_func (nullptr),
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400108 nesting_level_left (nesting_level_left_),
Behdad Esfahboda7e1b4a2018-06-11 22:05:08 -0400109 debug_depth (0),
110 done_lookups (done_lookups_) {}
Behdad Esfahbod9b346772012-11-23 17:55:40 -0500111
Behdad Esfahbodc38bd402018-07-24 09:43:27 -0700112 ~hb_closure_context_t (void)
113 {
114 flush ();
Behdad Esfahbodc38bd402018-07-24 09:43:27 -0700115 }
116
Behdad Esfahbod9b346772012-11-23 17:55:40 -0500117 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
Garret Rieger45186b92018-06-05 17:14:42 -0700118
Behdad Esfahbodc38bd402018-07-24 09:43:27 -0700119 void flush (void)
120 {
121 hb_set_union (glyphs, out);
122 hb_set_clear (out);
123 }
124
Garret Rieger45186b92018-06-05 17:14:42 -0700125 private:
126 hb_map_t *done_lookups;
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400127};
128
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400129
Behdad Esfahbod77a1a2b2015-10-09 12:20:58 -0400130struct hb_would_apply_context_t :
131 hb_dispatch_context_t<hb_would_apply_context_t, bool, HB_DEBUG_WOULD_APPLY>
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400132{
Behdad Esfahboda1733db2012-11-23 16:40:04 -0500133 inline const char *get_name (void) { return "WOULD_APPLY"; }
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500134 template <typename T>
Behdad Esfahbod9c5a9ee2013-03-09 01:55:04 -0500135 inline return_t dispatch (const T &obj) { return obj.would_apply (this); }
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500136 static return_t default_return_value (void) { return false; }
Behdad Esfahbod7b912c12013-01-04 01:25:27 -0600137 bool stop_sublookup_iteration (return_t r) const { return r; }
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500138
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400139 hb_face_t *face;
Behdad Esfahbod472f2292012-08-07 22:25:24 -0400140 const hb_codepoint_t *glyphs;
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400141 unsigned int len;
Behdad Esfahbodd9b204d2012-08-23 16:22:28 -0400142 bool zero_context;
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400143 unsigned int debug_depth;
144
145 hb_would_apply_context_t (hb_face_t *face_,
Behdad Esfahbod472f2292012-08-07 22:25:24 -0400146 const hb_codepoint_t *glyphs_,
147 unsigned int len_,
Behdad Esfahbod2bd9fe32012-09-04 15:15:19 -0400148 bool zero_context_) :
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400149 face (face_),
Behdad Esfahbod472f2292012-08-07 22:25:24 -0400150 glyphs (glyphs_),
151 len (len_),
Behdad Esfahbodd9b204d2012-08-23 16:22:28 -0400152 zero_context (zero_context_),
Behdad Esfahboda1733db2012-11-23 16:40:04 -0500153 debug_depth (0) {}
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400154};
155
156
Behdad Esfahbod77a1a2b2015-10-09 12:20:58 -0400157struct hb_collect_glyphs_context_t :
158 hb_dispatch_context_t<hb_collect_glyphs_context_t, hb_void_t, HB_DEBUG_COLLECT_GLYPHS>
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800159{
Behdad Esfahboda1733db2012-11-23 16:40:04 -0500160 inline const char *get_name (void) { return "COLLECT_GLYPHS"; }
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500161 typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index);
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500162 template <typename T>
Behdad Esfahbod9c5a9ee2013-03-09 01:55:04 -0500163 inline return_t dispatch (const T &obj) { obj.collect_glyphs (this); return HB_VOID; }
Behdad Esfahbod130bb3f2012-12-05 16:49:47 -0500164 static return_t default_return_value (void) { return HB_VOID; }
Behdad Esfahbod7b912c12013-01-04 01:25:27 -0600165 bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700166 void recurse (unsigned int lookup_index)
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500167 {
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500168 if (unlikely (nesting_level_left == 0 || !recurse_func))
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700169 return;
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500170
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200171 /* Note that GPOS sets recurse_func to nullptr already, so it doesn't get
Behdad Esfahbod1bcfa062012-12-04 16:58:09 -0500172 * past the previous check. For GSUB, we only want to collect the output
Behdad Esfahbod76ea5632013-05-04 16:01:20 -0400173 * glyphs in the recursion. If output is not requested, we can go home now.
174 *
175 * Note further, that the above is not exactly correct. A recursed lookup
176 * is allowed to match input that is not matched in the context, but that's
177 * not how most fonts are built. It's possible to relax that and recurse
178 * with all sets here if it proves to be an issue.
179 */
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500180
181 if (output == hb_set_get_empty ())
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700182 return;
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500183
Behdad Esfahbodfde3e4a2014-10-29 11:23:08 -0700184 /* Return if new lookup was recursed to before. */
Behdad Esfahbod8b9d9b72017-10-22 17:48:06 -0400185 if (recursed_lookups->has (lookup_index))
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700186 return;
Behdad Esfahbodfde3e4a2014-10-29 11:23:08 -0700187
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500188 hb_set_t *old_before = before;
189 hb_set_t *old_input = input;
190 hb_set_t *old_after = after;
191 before = input = after = hb_set_get_empty ();
Behdad Esfahbod1bcfa062012-12-04 16:58:09 -0500192
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500193 nesting_level_left--;
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500194 recurse_func (this, lookup_index);
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500195 nesting_level_left++;
Behdad Esfahbod4a350d02012-12-04 17:13:09 -0500196
197 before = old_before;
198 input = old_input;
199 after = old_after;
200
Behdad Esfahbod8b9d9b72017-10-22 17:48:06 -0400201 recursed_lookups->add (lookup_index);
Behdad Esfahbodfde3e4a2014-10-29 11:23:08 -0700202
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700203 return;
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500204 }
205
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800206 hb_face_t *face;
Behdad Esfahbod83035932012-12-04 17:08:41 -0500207 hb_set_t *before;
208 hb_set_t *input;
209 hb_set_t *after;
210 hb_set_t *output;
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500211 recurse_func_t recurse_func;
Behdad Esfahbod8b9d9b72017-10-22 17:48:06 -0400212 hb_set_t *recursed_lookups;
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500213 unsigned int nesting_level_left;
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800214 unsigned int debug_depth;
215
216 hb_collect_glyphs_context_t (hb_face_t *face_,
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200217 hb_set_t *glyphs_before, /* OUT. May be nullptr */
218 hb_set_t *glyphs_input, /* OUT. May be nullptr */
219 hb_set_t *glyphs_after, /* OUT. May be nullptr */
220 hb_set_t *glyphs_output, /* OUT. May be nullptr */
Behdad Esfahbod5ba45042015-11-02 15:43:08 -0800221 unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800222 face (face_),
Behdad Esfahbod83035932012-12-04 17:08:41 -0500223 before (glyphs_before ? glyphs_before : hb_set_get_empty ()),
224 input (glyphs_input ? glyphs_input : hb_set_get_empty ()),
225 after (glyphs_after ? glyphs_after : hb_set_get_empty ()),
226 output (glyphs_output ? glyphs_output : hb_set_get_empty ()),
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200227 recurse_func (nullptr),
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700228 recursed_lookups (hb_set_create ()),
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500229 nesting_level_left (nesting_level_left_),
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700230 debug_depth (0) {}
231 ~hb_collect_glyphs_context_t (void) { hb_set_destroy (recursed_lookups); }
Behdad Esfahbod26514d52012-11-23 18:13:48 -0500232
233 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800234};
235
236
237
Behdad Esfahbod8e36ccf2015-02-17 19:15:34 +0300238template <typename set_t>
Behdad Esfahbod77a1a2b2015-10-09 12:20:58 -0400239struct hb_add_coverage_context_t :
240 hb_dispatch_context_t<hb_add_coverage_context_t<set_t>, const Coverage &, HB_DEBUG_GET_COVERAGE>
Behdad Esfahbod2005fa52012-11-22 14:38:10 -0500241{
Behdad Esfahboda1733db2012-11-23 16:40:04 -0500242 inline const char *get_name (void) { return "GET_COVERAGE"; }
Behdad Esfahbod2005fa52012-11-22 14:38:10 -0500243 typedef const Coverage &return_t;
244 template <typename T>
Behdad Esfahbod9c5a9ee2013-03-09 01:55:04 -0500245 inline return_t dispatch (const T &obj) { return obj.get_coverage (); }
Behdad Esfahboda1733db2012-11-23 16:40:04 -0500246 static return_t default_return_value (void) { return Null(Coverage); }
Behdad Esfahbod8e36ccf2015-02-17 19:15:34 +0300247 bool stop_sublookup_iteration (return_t r) const
248 {
249 r.add_coverage (set);
250 return false;
251 }
Behdad Esfahbod1d67ef92012-11-22 16:47:53 -0500252
Behdad Esfahbod8e36ccf2015-02-17 19:15:34 +0300253 hb_add_coverage_context_t (set_t *set_) :
254 set (set_),
Behdad Esfahboda1733db2012-11-23 16:40:04 -0500255 debug_depth (0) {}
256
Behdad Esfahbod8e36ccf2015-02-17 19:15:34 +0300257 set_t *set;
Behdad Esfahboda1733db2012-11-23 16:40:04 -0500258 unsigned int debug_depth;
Behdad Esfahbod2005fa52012-11-22 14:38:10 -0500259};
260
261
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800262struct hb_ot_apply_context_t :
263 hb_dispatch_context_t<hb_ot_apply_context_t, bool, HB_DEBUG_APPLY>
Behdad Esfahbod1376fb72010-04-29 02:19:21 -0400264{
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500265 struct matcher_t
266 {
267 inline matcher_t (void) :
268 lookup_props (0),
Behdad Esfahbodcfc507c2013-02-14 10:40:12 -0500269 ignore_zwnj (false),
270 ignore_zwj (false),
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500271 mask (-1),
272#define arg1(arg) (arg) /* Remove the macro to see why it's needed! */
273 syllable arg1(0),
274#undef arg1
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200275 match_func (nullptr),
276 match_data (nullptr) {};
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500277
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100278 typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500279
280 inline void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; }
Behdad Esfahbod0b454792013-02-14 10:46:52 -0500281 inline void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500282 inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
283 inline void set_mask (hb_mask_t mask_) { mask = mask_; }
284 inline void set_syllable (uint8_t syllable_) { syllable = syllable_; }
285 inline void set_match_func (match_func_t match_func_,
286 const void *match_data_)
287 { match_func = match_func_; match_data = match_data_; }
288
Behdad Esfahbod2b2a6e82013-02-21 15:07:03 -0500289 enum may_match_t {
290 MATCH_NO,
291 MATCH_YES,
292 MATCH_MAYBE
293 };
294
295 inline may_match_t may_match (const hb_glyph_info_t &info,
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100296 const HBUINT16 *glyph_data) const
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500297 {
Behdad Esfahbod2b2a6e82013-02-21 15:07:03 -0500298 if (!(info.mask & mask) ||
299 (syllable && syllable != info.syllable ()))
300 return MATCH_NO;
301
302 if (match_func)
303 return match_func (info.codepoint, *glyph_data, match_data) ? MATCH_YES : MATCH_NO;
304
305 return MATCH_MAYBE;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500306 }
307
308 enum may_skip_t {
309 SKIP_NO,
310 SKIP_YES,
311 SKIP_MAYBE
312 };
313
314 inline may_skip_t
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800315 may_skip (const hb_ot_apply_context_t *c,
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500316 const hb_glyph_info_t &info) const
317 {
Behdad Esfahbodb98c5db2014-07-16 13:44:01 -0400318 if (!c->check_glyph_property (&info, lookup_props))
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500319 return SKIP_YES;
320
Khaled Hosny06cfe3f2017-05-17 21:32:47 +0300321 if (unlikely (_hb_glyph_info_is_default_ignorable_and_not_hidden (&info) &&
Behdad Esfahbod0b454792013-02-14 10:46:52 -0500322 (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) &&
Behdad Esfahbod4ba796b2015-07-22 17:41:31 +0100323 (ignore_zwj || !_hb_glyph_info_is_zwj (&info))))
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500324 return SKIP_MAYBE;
325
326 return SKIP_NO;
327 }
328
329 protected:
330 unsigned int lookup_props;
331 bool ignore_zwnj;
Behdad Esfahbod0b454792013-02-14 10:46:52 -0500332 bool ignore_zwj;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500333 hb_mask_t mask;
334 uint8_t syllable;
335 match_func_t match_func;
336 const void *match_data;
337 };
338
Behdad Esfahbod69626692015-01-29 13:08:41 +0100339 struct skipping_iterator_t
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500340 {
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800341 inline void init (hb_ot_apply_context_t *c_, bool context_match = false)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500342 {
Behdad Esfahbod514564f2015-01-29 13:48:48 +0100343 c = c_;
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200344 match_glyph_data = nullptr;
345 matcher.set_match_func (nullptr, nullptr);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500346 matcher.set_lookup_props (c->lookup_props);
Behdad Esfahboda8cf7b42013-03-19 05:53:26 -0400347 /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100348 matcher.set_ignore_zwnj (c->table_index == 1 || (context_match && c->auto_zwnj));
Behdad Esfahboda8cf7b42013-03-19 05:53:26 -0400349 /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100350 matcher.set_ignore_zwj (c->table_index == 1 || (context_match || c->auto_zwj));
Behdad Esfahbod514564f2015-01-29 13:48:48 +0100351 matcher.set_mask (context_match ? -1 : c->lookup_mask);
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500352 }
Behdad Esfahbod514564f2015-01-29 13:48:48 +0100353 inline void set_lookup_props (unsigned int lookup_props)
354 {
355 matcher.set_lookup_props (lookup_props);
356 }
Behdad Esfahbod4a6b1ee2015-10-21 11:20:55 -0200357 inline void set_match_func (matcher_t::match_func_t match_func_,
358 const void *match_data_,
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100359 const HBUINT16 glyph_data[])
Behdad Esfahbodc074ebc2013-02-13 11:22:42 -0500360 {
Behdad Esfahbod4a6b1ee2015-10-21 11:20:55 -0200361 matcher.set_match_func (match_func_, match_data_);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500362 match_glyph_data = glyph_data;
Behdad Esfahbodc074ebc2013-02-13 11:22:42 -0500363 }
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500364
Behdad Esfahbodb051be52015-01-29 13:40:39 +0100365 inline void reset (unsigned int start_index_,
366 unsigned int num_items_)
367 {
368 idx = start_index_;
369 num_items = num_items_;
370 end = c->buffer->len;
371 matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
372 }
373
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500374 inline void reject (void) { num_items++; match_glyph_data--; }
Behdad Esfahbod69626692015-01-29 13:08:41 +0100375
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200376 inline matcher_t::may_skip_t
Behdad Esfahbod12757b62018-01-26 18:14:05 -0800377 may_skip (const hb_glyph_info_t &info) const
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200378 {
379 return matcher.may_skip (c, info);
380 }
381
Behdad Esfahbodc074ebc2013-02-13 11:22:42 -0500382 inline bool next (void)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500383 {
Behdad Esfahbod506ffeb2012-01-18 16:07:53 -0500384 assert (num_items > 0);
Behdad Esfahbod37d13ac2015-01-29 11:38:01 +0100385 while (idx + num_items < end)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500386 {
Behdad Esfahboda4a48fe2012-01-17 18:08:41 -0500387 idx++;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500388 const hb_glyph_info_t &info = c->buffer->info[idx];
389
Behdad Esfahbodff93ac82013-02-21 14:51:40 -0500390 matcher_t::may_skip_t skip = matcher.may_skip (c, info);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500391 if (unlikely (skip == matcher_t::SKIP_YES))
392 continue;
393
Behdad Esfahbod2b2a6e82013-02-21 15:07:03 -0500394 matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
Behdad Esfahbod722e8b82013-02-21 15:37:51 -0500395 if (match == matcher_t::MATCH_YES ||
396 (match == matcher_t::MATCH_MAYBE &&
397 skip == matcher_t::SKIP_NO))
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500398 {
399 num_items--;
400 match_glyph_data++;
401 return true;
402 }
403
404 if (skip == matcher_t::SKIP_NO)
Behdad Esfahbod722e8b82013-02-21 15:37:51 -0500405 return false;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500406 }
407 return false;
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500408 }
Behdad Esfahbodc074ebc2013-02-13 11:22:42 -0500409 inline bool prev (void)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500410 {
Behdad Esfahbod506ffeb2012-01-18 16:07:53 -0500411 assert (num_items > 0);
Behdad Esfahbod18a06f82018-07-05 14:03:48 +0430412 while (idx > num_items - 1)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500413 {
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500414 idx--;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500415 const hb_glyph_info_t &info = c->buffer->out_info[idx];
416
Behdad Esfahbodff93ac82013-02-21 14:51:40 -0500417 matcher_t::may_skip_t skip = matcher.may_skip (c, info);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500418 if (unlikely (skip == matcher_t::SKIP_YES))
419 continue;
420
Behdad Esfahbod2b2a6e82013-02-21 15:07:03 -0500421 matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
Behdad Esfahbod722e8b82013-02-21 15:37:51 -0500422 if (match == matcher_t::MATCH_YES ||
423 (match == matcher_t::MATCH_MAYBE &&
424 skip == matcher_t::SKIP_NO))
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500425 {
426 num_items--;
427 match_glyph_data++;
428 return true;
429 }
430
431 if (skip == matcher_t::SKIP_NO)
Behdad Esfahbod722e8b82013-02-21 15:37:51 -0500432 return false;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500433 }
434 return false;
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500435 }
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500436
437 unsigned int idx;
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400438 protected:
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800439 hb_ot_apply_context_t *c;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500440 matcher_t matcher;
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100441 const HBUINT16 *match_glyph_data;
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500442
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500443 unsigned int num_items;
Behdad Esfahbod69626692015-01-29 13:08:41 +0100444 unsigned int end;
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500445 };
446
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100447
448 inline const char *get_name (void) { return "APPLY"; }
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800449 typedef return_t (*recurse_func_t) (hb_ot_apply_context_t *c, unsigned int lookup_index);
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100450 template <typename T>
451 inline return_t dispatch (const T &obj) { return obj.apply (this); }
452 static return_t default_return_value (void) { return false; }
453 bool stop_sublookup_iteration (return_t r) const { return r; }
Behdad Esfahbod12757b62018-01-26 18:14:05 -0800454 return_t recurse (unsigned int sub_lookup_index)
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100455 {
Behdad Esfahbodbaf77792017-11-14 21:53:48 -0800456 if (unlikely (nesting_level_left == 0 || !recurse_func || buffer->max_ops-- <= 0))
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100457 return default_return_value ();
458
459 nesting_level_left--;
Behdad Esfahbod12757b62018-01-26 18:14:05 -0800460 bool ret = recurse_func (this, sub_lookup_index);
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100461 nesting_level_left++;
462 return ret;
463 }
464
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100465 skipping_iterator_t iter_input, iter_context;
466
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100467 hb_font_t *font;
468 hb_face_t *face;
469 hb_buffer_t *buffer;
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100470 recurse_func_t recurse_func;
471 const GDEF &gdef;
472 const VariationStore &var_store;
473
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100474 hb_direction_t direction;
475 hb_mask_t lookup_mask;
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100476 unsigned int table_index; /* GSUB/GPOS */
Behdad Esfahbod2c8b3b22015-08-18 14:36:43 +0100477 unsigned int lookup_index;
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100478 unsigned int lookup_props;
479 unsigned int nesting_level_left;
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100480 unsigned int debug_depth;
481
Behdad Esfahbod80de4bc2018-09-10 16:24:52 +0200482 bool has_glyph_classes;
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100483 bool auto_zwnj;
484 bool auto_zwj;
David Corbettc2a75e02018-01-25 14:22:03 -0500485 bool random;
Behdad Esfahbod80de4bc2018-09-10 16:24:52 +0200486
Behdad Esfahbodcfdea882018-09-11 10:57:48 +0200487 uint32_t random_state;
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100488
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100489
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800490 hb_ot_apply_context_t (unsigned int table_index_,
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100491 hb_font_t *font_,
492 hb_buffer_t *buffer_) :
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100493 iter_input (), iter_context (),
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100494 font (font_), face (font->face), buffer (buffer_),
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200495 recurse_func (nullptr),
Behdad Esfahbodb9291002018-08-26 01:15:47 -0700496 gdef (_get_gdef (face)),
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100497 var_store (gdef.get_var_store ()),
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100498 direction (buffer_->props.direction),
499 lookup_mask (1),
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100500 table_index (table_index_),
Behdad Esfahbod2c8b3b22015-08-18 14:36:43 +0100501 lookup_index ((unsigned int) -1),
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100502 lookup_props (0),
503 nesting_level_left (HB_MAX_NESTING_LEVEL),
504 debug_depth (0),
Behdad Esfahbod80de4bc2018-09-10 16:24:52 +0200505 has_glyph_classes (gdef.has_glyph_classes ()),
Behdad Esfahbodcdf1fd02017-07-14 12:43:34 +0100506 auto_zwnj (true),
507 auto_zwj (true),
David Corbettc2a75e02018-01-25 14:22:03 -0500508 random (false),
Behdad Esfahbod80de4bc2018-09-10 16:24:52 +0200509 random_state (1) {}
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100510
Behdad Esfahbod9516cbd2018-09-23 22:00:34 -0400511 inline void reinit_iters (void)
Behdad Esfahbod365576d2015-01-29 13:59:42 +0100512 {
Behdad Esfahbod365576d2015-01-29 13:59:42 +0100513 iter_input.init (this, false);
514 iter_context.init (this, true);
515 }
Behdad Esfahbod2cecc382015-01-29 13:32:05 +0100516
Behdad Esfahbod9516cbd2018-09-23 22:00:34 -0400517 inline void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; }
518 inline void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; reinit_iters (); }
519 inline void set_auto_zwnj (bool auto_zwnj_) { auto_zwnj = auto_zwnj_; reinit_iters (); }
520 inline void set_random (bool random_) { random = random_; }
521 inline void set_recurse_func (recurse_func_t func) { recurse_func = func; }
522 inline void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; }
523 inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; reinit_iters (); }
524
Behdad Esfahbod08260c72018-09-11 10:51:19 +0200525 inline uint32_t random_number (void)
526 {
Behdad Esfahbodcfdea882018-09-11 10:57:48 +0200527 /* http://www.cplusplus.com/reference/random/minstd_rand/ */
528 random_state = random_state * 48271 % 2147483647;
529 return random_state;
Behdad Esfahbod08260c72018-09-11 10:51:19 +0200530 }
531
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400532 inline bool
533 match_properties_mark (hb_codepoint_t glyph,
534 unsigned int glyph_props,
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700535 unsigned int match_props) const
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400536 {
537 /* If using mark filtering sets, the high short of
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700538 * match_props has the set index.
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400539 */
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700540 if (match_props & LookupFlag::UseMarkFilteringSet)
541 return gdef.mark_set_covers (match_props >> 16, glyph);
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400542
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700543 /* The second byte of match_props has the meaning
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400544 * "ignore marks of attachment type different than
545 * the attachment type specified."
546 */
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700547 if (match_props & LookupFlag::MarkAttachmentType)
548 return (match_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400549
550 return true;
551 }
552
553 inline bool
Behdad Esfahbodb98c5db2014-07-16 13:44:01 -0400554 check_glyph_property (const hb_glyph_info_t *info,
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700555 unsigned int match_props) const
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400556 {
Behdad Esfahbodb98c5db2014-07-16 13:44:01 -0400557 hb_codepoint_t glyph = info->codepoint;
558 unsigned int glyph_props = _hb_glyph_info_get_glyph_props (info);
559
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400560 /* Not covered, if, for example, glyph class is ligature and
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700561 * match_props includes LookupFlags::IgnoreLigatures
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400562 */
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700563 if (glyph_props & match_props & LookupFlag::IgnoreFlags)
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400564 return false;
565
Behdad Esfahbod5a08ecf2012-11-16 13:34:29 -0800566 if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK))
Behdad Esfahbodb931e0b2015-04-08 14:39:00 -0700567 return match_properties_mark (glyph, glyph_props, match_props);
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -0400568
569 return true;
570 }
571
Behdad Esfahboda0161742013-10-18 00:06:30 +0200572 inline void _set_glyph_props (hb_codepoint_t glyph_index,
Behdad Esfahbod71b4c992013-10-28 00:20:59 +0100573 unsigned int class_guess = 0,
Behdad Esfahbod832a6f92014-06-04 16:57:42 -0400574 bool ligature = false,
575 bool component = false) const
Behdad Esfahbod60da7632012-07-16 16:13:32 -0400576 {
Behdad Esfahbod09675a82013-10-18 01:05:58 +0200577 unsigned int add_in = _hb_glyph_info_get_glyph_props (&buffer->cur()) &
578 HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE;
579 add_in |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED;
580 if (ligature)
Behdad Esfahbod832a6f92014-06-04 16:57:42 -0400581 {
Behdad Esfahbod09675a82013-10-18 01:05:58 +0200582 add_in |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED;
Behdad Esfahbod832a6f92014-06-04 16:57:42 -0400583 /* In the only place that the MULTIPLIED bit is used, Uniscribe
584 * seems to only care about the "last" transformation between
585 * Ligature and Multiple substitions. Ie. if you ligate, expand,
586 * and ligate again, it forgives the multiplication and acts as
587 * if only ligation happened. As such, clear MULTIPLIED bit.
588 */
589 add_in &= ~HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
590 }
591 if (component)
592 add_in |= HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
Behdad Esfahbod2fca1422012-07-30 18:46:41 -0400593 if (likely (has_glyph_classes))
Behdad Esfahbod05ad6b52013-10-18 00:45:59 +0200594 _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | gdef.get_glyph_props (glyph_index));
Behdad Esfahbod05bd1b62012-07-30 19:30:01 -0400595 else if (class_guess)
Behdad Esfahbod09675a82013-10-18 01:05:58 +0200596 _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | class_guess);
Behdad Esfahbod60da7632012-07-16 16:13:32 -0400597 }
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500598
Behdad Esfahboda0161742013-10-18 00:06:30 +0200599 inline void replace_glyph (hb_codepoint_t glyph_index) const
Behdad Esfahbod3ec77d62012-06-08 21:44:06 -0400600 {
Behdad Esfahboda0161742013-10-18 00:06:30 +0200601 _set_glyph_props (glyph_index);
Behdad Esfahbod98370e82010-10-27 17:39:01 -0400602 buffer->replace_glyph (glyph_index);
603 }
Behdad Esfahboda0161742013-10-18 00:06:30 +0200604 inline void replace_glyph_inplace (hb_codepoint_t glyph_index) const
Behdad Esfahbod7fbbf862012-07-30 18:36:42 -0400605 {
Behdad Esfahboda0161742013-10-18 00:06:30 +0200606 _set_glyph_props (glyph_index);
Behdad Esfahbod7fbbf862012-07-30 18:36:42 -0400607 buffer->cur().codepoint = glyph_index;
608 }
Behdad Esfahboda0161742013-10-18 00:06:30 +0200609 inline void replace_glyph_with_ligature (hb_codepoint_t glyph_index,
610 unsigned int class_guess) const
611 {
Behdad Esfahbod09675a82013-10-18 01:05:58 +0200612 _set_glyph_props (glyph_index, class_guess, true);
Behdad Esfahboda0161742013-10-18 00:06:30 +0200613 buffer->replace_glyph (glyph_index);
614 }
Behdad Esfahbod832a6f92014-06-04 16:57:42 -0400615 inline void output_glyph_for_component (hb_codepoint_t glyph_index,
616 unsigned int class_guess) const
Behdad Esfahboda0161742013-10-18 00:06:30 +0200617 {
Behdad Esfahbod832a6f92014-06-04 16:57:42 -0400618 _set_glyph_props (glyph_index, class_guess, false, true);
Behdad Esfahboda0161742013-10-18 00:06:30 +0200619 buffer->output_glyph (glyph_index);
620 }
Behdad Esfahbod1376fb72010-04-29 02:19:21 -0400621};
622
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -0400623
Behdad Esfahbod94a23aa2010-05-05 01:13:09 -0400624
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700625typedef bool (*intersects_func_t) (const hb_set_t *glyphs, const HBUINT16 &value, const void *data);
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100626typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const HBUINT16 &value, const void *data);
627typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -0400628
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400629struct ContextClosureFuncs
630{
631 intersects_func_t intersects;
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400632};
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500633struct ContextCollectGlyphsFuncs
634{
635 collect_glyphs_func_t collect;
636};
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400637struct ContextApplyFuncs
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400638{
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -0400639 match_func_t match;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -0400640};
641
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500642
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700643static inline bool intersects_glyph (const hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400644{
645 return glyphs->has (value);
646}
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700647static inline bool intersects_class (const hb_set_t *glyphs, const HBUINT16 &value, const void *data)
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400648{
649 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
650 return class_def.intersects_class (glyphs, value);
651}
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700652static inline bool intersects_coverage (const hb_set_t *glyphs, const HBUINT16 &value, const void *data)
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400653{
654 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
655 return (data+coverage).intersects (glyphs);
656}
657
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700658static inline bool intersects_array (const hb_set_t *glyphs,
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400659 unsigned int count,
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100660 const HBUINT16 values[],
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400661 intersects_func_t intersects_func,
662 const void *intersects_data)
663{
664 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700665 if (likely (!intersects_func (glyphs, values[i], intersects_data)))
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400666 return false;
667 return true;
668}
669
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -0400670
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100671static inline void collect_glyph (hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500672{
673 glyphs->add (value);
674}
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100675static inline void collect_class (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500676{
677 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
Behdad Esfahbod71e6adf2017-12-16 11:07:37 -0500678 class_def.add_class (glyphs, value);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500679}
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100680static inline void collect_coverage (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500681{
682 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
683 (data+coverage).add_coverage (glyphs);
684}
Behdad Esfahbod0beb66e2012-12-05 18:46:04 -0500685static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -0500686 hb_set_t *glyphs,
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500687 unsigned int count,
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100688 const HBUINT16 values[],
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500689 collect_glyphs_func_t collect_func,
690 const void *collect_data)
691{
692 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbodf1b12782012-11-24 01:55:34 -0500693 collect_func (glyphs, values[i], collect_data);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -0500694}
695
696
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100697static inline bool match_glyph (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data HB_UNUSED)
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400698{
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -0400699 return glyph_id == value;
700}
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100701static inline bool match_class (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data)
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400702{
Behdad Esfahbod2b5a59c2009-08-04 11:38:50 -0400703 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -0400704 return class_def.get_class (glyph_id) == value;
705}
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100706static inline bool match_coverage (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data)
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400707{
Behdad Esfahbod6b54c5d2009-05-18 18:30:25 -0400708 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
Behdad Esfahbod31081f72012-04-23 16:54:58 -0400709 return (data+coverage).get_coverage (glyph_id) != NOT_COVERED;
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -0400710}
711
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400712static inline bool would_match_input (hb_would_apply_context_t *c,
713 unsigned int count, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100714 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400715 match_func_t match_func,
716 const void *match_data)
717{
718 if (count != c->len)
719 return false;
720
721 for (unsigned int i = 1; i < count; i++)
Behdad Esfahbod472f2292012-08-07 22:25:24 -0400722 if (likely (!match_func (c->glyphs[i], input[i - 1], match_data)))
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400723 return false;
724
725 return true;
726}
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800727static inline bool match_input (hb_ot_apply_context_t *c,
Behdad Esfahbode072c242009-05-18 03:47:31 -0400728 unsigned int count, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100729 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -0400730 match_func_t match_func,
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -0400731 const void *match_data,
Behdad Esfahbod6cc136f2013-10-17 13:55:48 +0200732 unsigned int *end_offset,
Behdad Esfahbod5ba45042015-11-02 15:43:08 -0800733 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200734 bool *p_is_mark_ligature = nullptr,
735 unsigned int *p_total_component_count = nullptr)
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -0400736{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200737 TRACE_APPLY (nullptr);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400738
Behdad Esfahbod5ba45042015-11-02 15:43:08 -0800739 if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return_trace (false);
Behdad Esfahbod6b65a762013-10-14 18:51:39 +0200740
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200741 hb_buffer_t *buffer = c->buffer;
742
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800743 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
Behdad Esfahbodb051be52015-01-29 13:40:39 +0100744 skippy_iter.reset (buffer->idx, count - 1);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500745 skippy_iter.set_match_func (match_func, match_data, input);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400746
Behdad Esfahbod191fa882012-08-28 22:58:55 -0400747 /*
748 * This is perhaps the trickiest part of OpenType... Remarks:
749 *
750 * - If all components of the ligature were marks, we call this a mark ligature.
751 *
752 * - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize
753 * it as a ligature glyph.
754 *
755 * - Ligatures cannot be formed across glyphs attached to different components
756 * of previous ligatures. Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and
757 * LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother.
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200758 * However, it would be wrong to ligate that SHADDA,FATHA sequence.
759 * There are a couple of exceptions to this:
760 *
761 * o If a ligature tries ligating with marks that belong to it itself, go ahead,
762 * assuming that the font designer knows what they are doing (otherwise it can
763 * break Indic stuff when a matra wants to ligate with a conjunct,
764 *
765 * o If two marks want to ligate and they belong to different components of the
766 * same ligature glyph, and said ligature glyph is to be ignored according to
767 * mark-filtering rules, then allow.
ebraminio7c6937e2017-11-20 14:49:22 -0500768 * https://github.com/harfbuzz/harfbuzz/issues/545
Behdad Esfahbod191fa882012-08-28 22:58:55 -0400769 */
770
Behdad Esfahbod101303d2013-10-18 00:42:39 +0200771 bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->cur());
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400772
773 unsigned int total_component_count = 0;
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200774 total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur());
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400775
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200776 unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
777 unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -0400778
Behdad Esfahbod621c49c2017-10-04 15:06:48 +0200779 enum {
780 LIGBASE_NOT_CHECKED,
781 LIGBASE_MAY_NOT_SKIP,
782 LIGBASE_MAY_SKIP
783 } ligbase = LIGBASE_NOT_CHECKED;
784
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200785 match_positions[0] = buffer->idx;
Behdad Esfahbod370f03e2012-01-16 17:03:55 -0500786 for (unsigned int i = 1; i < count; i++)
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400787 {
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100788 if (!skippy_iter.next ()) return_trace (false);
Behdad Esfahbod6cc136f2013-10-17 13:55:48 +0200789
790 match_positions[i] = skippy_iter.idx;
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400791
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200792 unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]);
793 unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400794
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200795 if (first_lig_id && first_lig_comp)
796 {
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400797 /* If first component was attached to a previous ligature component,
798 * all subsequent components should be attached to the same ligature
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200799 * component, otherwise we shouldn't ligate them... */
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400800 if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200801 {
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200802 /* ...unless, we are attached to a base ligature and that base
803 * ligature is ignorable. */
Behdad Esfahbod621c49c2017-10-04 15:06:48 +0200804 if (ligbase == LIGBASE_NOT_CHECKED)
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200805 {
Behdad Esfahbod621c49c2017-10-04 15:06:48 +0200806 bool found = false;
807 const hb_glyph_info_t *out = buffer->out_info;
808 unsigned int j = buffer->out_len;
809 while (j && _hb_glyph_info_get_lig_id (&out[j - 1]) == first_lig_id)
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200810 {
Behdad Esfahbod621c49c2017-10-04 15:06:48 +0200811 if (_hb_glyph_info_get_lig_comp (&out[j - 1]) == 0)
812 {
813 j--;
814 found = true;
815 break;
816 }
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200817 j--;
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200818 }
Behdad Esfahbod621c49c2017-10-04 15:06:48 +0200819
Behdad Esfahbod12757b62018-01-26 18:14:05 -0800820 if (found && skippy_iter.may_skip (out[j]) == hb_ot_apply_context_t::matcher_t::SKIP_YES)
Behdad Esfahbod621c49c2017-10-04 15:06:48 +0200821 ligbase = LIGBASE_MAY_SKIP;
822 else
823 ligbase = LIGBASE_MAY_NOT_SKIP;
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200824 }
825
Behdad Esfahbod621c49c2017-10-04 15:06:48 +0200826 if (ligbase == LIGBASE_MAY_NOT_SKIP)
Behdad Esfahbod8b2c94c2017-10-02 20:02:45 +0200827 return_trace (false);
828 }
829 }
830 else
Behdad Esfahbod621c49c2017-10-04 15:06:48 +0200831 {
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400832 /* If first component was NOT attached to a previous ligature component,
833 * all subsequent components should also NOT be attached to any ligature
834 * component, unless they are attached to the first component itself! */
835 if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id))
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100836 return_trace (false);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400837 }
838
Behdad Esfahbod101303d2013-10-18 00:42:39 +0200839 is_mark_ligature = is_mark_ligature && _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx]);
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200840 total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -0400841 }
842
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200843 *end_offset = skippy_iter.idx - buffer->idx + 1;
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400844
Behdad Esfahbod191fa882012-08-28 22:58:55 -0400845 if (p_is_mark_ligature)
846 *p_is_mark_ligature = is_mark_ligature;
847
848 if (p_total_component_count)
849 *p_total_component_count = total_component_count;
850
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100851 return_trace (true);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400852}
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800853static inline bool ligate_input (hb_ot_apply_context_t *c,
Behdad Esfahbode714fe62013-10-17 13:49:51 +0200854 unsigned int count, /* Including the first glyph */
Behdad Esfahbod5ba45042015-11-02 15:43:08 -0800855 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
Behdad Esfahbode714fe62013-10-17 13:49:51 +0200856 unsigned int match_length,
Behdad Esfahboda177d022012-08-28 23:18:22 -0400857 hb_codepoint_t lig_glyph,
Behdad Esfahboda177d022012-08-28 23:18:22 -0400858 bool is_mark_ligature,
859 unsigned int total_component_count)
860{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200861 TRACE_APPLY (nullptr);
Behdad Esfahbode714fe62013-10-17 13:49:51 +0200862
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200863 hb_buffer_t *buffer = c->buffer;
864
865 buffer->merge_clusters (buffer->idx, buffer->idx + match_length);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500866
Behdad Esfahboda177d022012-08-28 23:18:22 -0400867 /*
868 * - If it *is* a mark ligature, we don't allocate a new ligature id, and leave
869 * the ligature to keep its old ligature id. This will allow it to attach to
870 * a base ligature in GPOS. Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH,
871 * and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA wit a
872 * ligature id and component value of 2. Then if SHADDA,FATHA form a ligature
873 * later, we don't want them to lose their ligature id/component, otherwise
874 * GPOS will fail to correctly position the mark ligature on top of the
875 * LAM,LAM,HEH ligature. See:
876 * https://bugzilla.gnome.org/show_bug.cgi?id=676343
877 *
878 * - If a ligature is formed of components that some of which are also ligatures
879 * themselves, and those ligature components had marks attached to *their*
880 * components, we have to attach the marks to the new ligature component
881 * positions! Now *that*'s tricky! And these marks may be following the
882 * last component of the whole sequence, so we should loop forward looking
883 * for them and update them.
884 *
885 * Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a
886 * 'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature
887 * id and component == 1. Now, during 'liga', the LAM and the LAM-HEH ligature
888 * form a LAM-LAM-HEH ligature. We need to reassign the SHADDA and FATHA to
889 * the new ligature with a component value of 2.
890 *
891 * This in fact happened to a font... See:
892 * https://bugzilla.gnome.org/show_bug.cgi?id=437633
893 */
894
Behdad Esfahbod5a08ecf2012-11-16 13:34:29 -0800895 unsigned int klass = is_mark_ligature ? 0 : HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200896 unsigned int lig_id = is_mark_ligature ? 0 : _hb_allocate_lig_id (buffer);
897 unsigned int last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
898 unsigned int last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
Behdad Esfahboda177d022012-08-28 23:18:22 -0400899 unsigned int components_so_far = last_num_components;
900
901 if (!is_mark_ligature)
Behdad Esfahbod7e08f122013-05-27 14:48:34 -0400902 {
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200903 _hb_glyph_info_set_lig_props_for_ligature (&buffer->cur(), lig_id, total_component_count);
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200904 if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
Behdad Esfahbod3d436d32013-10-28 21:00:37 +0100905 {
Behdad Esfahbod82596692015-11-02 17:44:05 -0800906 _hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER);
Behdad Esfahbod3d436d32013-10-28 21:00:37 +0100907 }
Behdad Esfahbod7e08f122013-05-27 14:48:34 -0400908 }
Behdad Esfahboda0161742013-10-18 00:06:30 +0200909 c->replace_glyph_with_ligature (lig_glyph, klass);
Behdad Esfahboda177d022012-08-28 23:18:22 -0400910
911 for (unsigned int i = 1; i < count; i++)
912 {
Behdad Esfahbod7185b272018-05-31 20:03:00 -0700913 while (buffer->idx < match_positions[i] && buffer->successful)
Behdad Esfahboda177d022012-08-28 23:18:22 -0400914 {
915 if (!is_mark_ligature) {
Behdad Esfahbod2f02fc72015-12-17 15:21:14 +0000916 unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
917 if (this_comp == 0)
Behdad Esfahbod100fbea2015-12-17 15:23:09 +0000918 this_comp = last_num_components;
Behdad Esfahboda177d022012-08-28 23:18:22 -0400919 unsigned int new_lig_comp = components_so_far - last_num_components +
Behdad Esfahbod2f02fc72015-12-17 15:21:14 +0000920 MIN (this_comp, last_num_components);
921 _hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
Behdad Esfahboda177d022012-08-28 23:18:22 -0400922 }
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200923 buffer->next_glyph ();
Behdad Esfahboda177d022012-08-28 23:18:22 -0400924 }
925
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200926 last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
927 last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
Behdad Esfahboda177d022012-08-28 23:18:22 -0400928 components_so_far += last_num_components;
929
930 /* Skip the base glyph */
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200931 buffer->idx++;
Behdad Esfahboda177d022012-08-28 23:18:22 -0400932 }
933
934 if (!is_mark_ligature && last_lig_id) {
935 /* Re-adjust components for any marks following. */
Behdad Esfahbod3c3df9c2013-10-17 13:58:31 +0200936 for (unsigned int i = buffer->idx; i < buffer->len; i++) {
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200937 if (last_lig_id == _hb_glyph_info_get_lig_id (&buffer->info[i])) {
Behdad Esfahbod2f02fc72015-12-17 15:21:14 +0000938 unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->info[i]);
939 if (!this_comp)
940 break;
Behdad Esfahboda177d022012-08-28 23:18:22 -0400941 unsigned int new_lig_comp = components_so_far - last_num_components +
Behdad Esfahbod2f02fc72015-12-17 15:21:14 +0000942 MIN (this_comp, last_num_components);
Behdad Esfahbod3ddf8922013-10-18 00:02:43 +0200943 _hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
Behdad Esfahboda177d022012-08-28 23:18:22 -0400944 } else
945 break;
946 }
947 }
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100948 return_trace (true);
Behdad Esfahboda177d022012-08-28 23:18:22 -0400949}
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400950
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800951static inline bool match_backtrack (hb_ot_apply_context_t *c,
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400952 unsigned int count,
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100953 const HBUINT16 backtrack[],
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400954 match_func_t match_func,
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +0200955 const void *match_data,
956 unsigned int *match_start)
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400957{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200958 TRACE_APPLY (nullptr);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400959
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800960 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
Behdad Esfahbodb051be52015-01-29 13:40:39 +0100961 skippy_iter.reset (c->buffer->backtrack_len (), count);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500962 skippy_iter.set_match_func (match_func, match_data, backtrack);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400963
Behdad Esfahbod4d3aeb82012-01-16 16:43:26 -0500964 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500965 if (!skippy_iter.prev ())
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100966 return_trace (false);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400967
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +0200968 *match_start = skippy_iter.idx;
969
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100970 return_trace (true);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400971}
972
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800973static inline bool match_lookahead (hb_ot_apply_context_t *c,
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400974 unsigned int count,
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100975 const HBUINT16 lookahead[],
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400976 match_func_t match_func,
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -0400977 const void *match_data,
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +0200978 unsigned int offset,
979 unsigned int *end_index)
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400980{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200981 TRACE_APPLY (nullptr);
Behdad Esfahbod93814ca2012-08-28 22:24:51 -0400982
Behdad Esfahbodfd034492018-01-17 16:46:51 -0800983 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
Behdad Esfahbodb051be52015-01-29 13:40:39 +0100984 skippy_iter.reset (c->buffer->idx + offset - 1, count);
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500985 skippy_iter.set_match_func (match_func, match_data, lookahead);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400986
Behdad Esfahbod370f03e2012-01-16 17:03:55 -0500987 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500988 if (!skippy_iter.next ())
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100989 return_trace (false);
Behdad Esfahbodd0ba0552009-05-18 03:56:39 -0400990
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +0200991 *end_index = skippy_iter.idx + 1;
992
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100993 return_trace (true);
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -0400994}
995
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -0400996
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -0400997
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -0400998struct LookupRecord
999{
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001000 inline bool sanitize (hb_sanitize_context_t *c) const
1001 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001002 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001003 return_trace (c->check_struct (this));
Behdad Esfahbodcd3827e2009-08-04 02:09:34 -04001004 }
1005
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001006 HBUINT16 sequenceIndex; /* Index into current glyph
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001007 * sequence--first glyph = 0 */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001008 HBUINT16 lookupListIndex; /* Lookup to apply to that
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001009 * position--zero--based */
Behdad Esfahbod569da922010-05-10 16:38:32 -04001010 public:
1011 DEFINE_SIZE_STATIC (4);
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001012};
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001013
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001014template <typename context_t>
1015static inline void recurse_lookups (context_t *c,
1016 unsigned int lookupCount,
1017 const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001018{
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001019 for (unsigned int i = 0; i < lookupCount; i++)
Behdad Esfahbod86522e42013-07-22 19:07:53 -04001020 c->recurse (lookupRecord[i].lookupListIndex);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001021}
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04001022
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001023static inline bool apply_lookup (hb_ot_apply_context_t *c,
Behdad Esfahbode072c242009-05-18 03:47:31 -04001024 unsigned int count, /* Including the first glyph */
Behdad Esfahbod5ba45042015-11-02 15:43:08 -08001025 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
Behdad Esfahbode072c242009-05-18 03:47:31 -04001026 unsigned int lookupCount,
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001027 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
1028 unsigned int match_length)
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001029{
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001030 TRACE_APPLY (nullptr);
Behdad Esfahbod902cc8a2012-11-23 15:06:59 -05001031
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001032 hb_buffer_t *buffer = c->buffer;
jfkthame44f7d6e2017-02-17 03:03:24 +00001033 int end;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001034
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001035 /* All positions are distance from beginning of *output* buffer.
1036 * Adjust. */
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001037 {
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001038 unsigned int bl = buffer->backtrack_len ();
1039 end = bl + match_length;
Behdad Esfahbod8751de52013-07-18 16:29:50 -04001040
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001041 int delta = bl - buffer->idx;
1042 /* Convert positions to new indexing. */
1043 for (unsigned int j = 0; j < count; j++)
1044 match_positions[j] += delta;
Behdad Esfahbod8820bb22013-02-14 07:41:03 -05001045 }
Behdad Esfahbode73a0c22009-05-18 04:15:25 -04001046
Behdad Esfahbod7185b272018-05-31 20:03:00 -07001047 for (unsigned int i = 0; i < lookupCount && buffer->successful; i++)
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001048 {
1049 unsigned int idx = lookupRecord[i].sequenceIndex;
1050 if (idx >= count)
1051 continue;
1052
Behdad Esfahbod9cc1ed42015-11-19 12:39:09 -08001053 /* Don't recurse to ourself at same position.
1054 * Note that this test is too naive, it doesn't catch longer loops. */
1055 if (idx == 0 && lookupRecord[i].lookupListIndex == c->lookup_index)
1056 continue;
1057
Behdad Esfahbode5930722017-11-14 15:47:55 -08001058 if (unlikely (!buffer->move_to (match_positions[idx])))
1059 break;
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001060
Behdad Esfahbodbaf77792017-11-14 21:53:48 -08001061 if (unlikely (buffer->max_ops <= 0))
1062 break;
1063
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001064 unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
1065 if (!c->recurse (lookupRecord[i].lookupListIndex))
1066 continue;
1067
1068 unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len ();
1069 int delta = new_len - orig_len;
1070
1071 if (!delta)
1072 continue;
1073
Behdad Esfahbod9ac9af72017-03-05 13:51:01 -08001074 /* Recursed lookup changed buffer len. Adjust.
1075 *
1076 * TODO:
1077 *
1078 * Right now, if buffer length increased by n, we assume n new glyphs
1079 * were added right after the current position, and if buffer length
1080 * was decreased by n, we assume n match positions after the current
1081 * one where removed. The former (buffer length increased) case is
1082 * fine, but the decrease case can be improved in at least two ways,
1083 * both of which are significant:
1084 *
1085 * - If recursed-to lookup is MultipleSubst and buffer length
1086 * decreased, then it's current match position that was deleted,
1087 * NOT the one after it.
1088 *
1089 * - If buffer length was decreased by n, it does not necessarily
1090 * mean that n match positions where removed, as there might
1091 * have been marks and default-ignorables in the sequence. We
1092 * should instead drop match positions between current-position
1093 * and current-position + n instead.
1094 *
1095 * It should be possible to construct tests for both of these cases.
1096 */
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001097
jfkthame44f7d6e2017-02-17 03:03:24 +00001098 end += delta;
Behdad Esfahbod47e7a182017-03-10 13:23:02 -08001099 if (end <= int (match_positions[idx]))
Behdad Esfahbod359dead2016-05-06 16:19:19 +01001100 {
Behdad Esfahbod4b4a1b92016-12-21 23:10:43 -06001101 /* End might end up being smaller than match_positions[idx] if the recursed
Behdad Esfahbod47e7a182017-03-10 13:23:02 -08001102 * lookup ended up removing many items, more than we have had matched.
Behdad Esfahbod4b4a1b92016-12-21 23:10:43 -06001103 * Just never rewind end back and get out of here.
1104 * https://bugs.chromium.org/p/chromium/issues/detail?id=659496 */
1105 end = match_positions[idx];
Behdad Esfahbod47e7a182017-03-10 13:23:02 -08001106 /* There can't be any further changes. */
Behdad Esfahbod359dead2016-05-06 16:19:19 +01001107 break;
1108 }
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001109
1110 unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */
1111
1112 if (delta > 0)
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001113 {
Behdad Esfahbod5ba45042015-11-02 15:43:08 -08001114 if (unlikely (delta + count > HB_MAX_CONTEXT_LENGTH))
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001115 break;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001116 }
1117 else
1118 {
Behdad Esfahbod47e7a182017-03-10 13:23:02 -08001119 /* NOTE: delta is negative. */
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001120 delta = MAX (delta, (int) next - (int) count);
1121 next -= delta;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001122 }
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001123
1124 /* Shift! */
1125 memmove (match_positions + next + delta, match_positions + next,
1126 (count - next) * sizeof (match_positions[0]));
1127 next += delta;
1128 count += delta;
1129
1130 /* Fill in new entries. */
1131 for (unsigned int j = idx + 1; j < next; j++)
1132 match_positions[j] = match_positions[j - 1] + 1;
1133
1134 /* And fixup the rest. */
1135 for (; next < count; next++)
1136 match_positions[next] += delta;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001137 }
1138
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001139 buffer->move_to (end);
1140
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001141 return_trace (true);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001142}
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001143
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04001144
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001145
1146/* Contextual lookups */
1147
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001148struct ContextClosureLookupContext
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001149{
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001150 ContextClosureFuncs funcs;
1151 const void *intersects_data;
1152};
1153
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001154struct ContextCollectGlyphsLookupContext
1155{
1156 ContextCollectGlyphsFuncs funcs;
1157 const void *collect_data;
1158};
1159
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001160struct ContextApplyLookupContext
1161{
1162 ContextApplyFuncs funcs;
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04001163 const void *match_data;
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001164};
1165
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001166static inline bool context_intersects (const hb_set_t *glyphs,
1167 unsigned int inputCount, /* Including the first glyph (not matched) */
1168 const HBUINT16 input[], /* Array of input values--start with second glyph */
1169 ContextClosureLookupContext &lookup_context)
1170{
1171 return intersects_array (glyphs,
1172 inputCount ? inputCount - 1 : 0, input,
1173 lookup_context.funcs.intersects, lookup_context.intersects_data);
1174}
1175
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001176static inline void context_closure_lookup (hb_closure_context_t *c,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001177 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001178 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001179 unsigned int lookupCount,
1180 const LookupRecord lookupRecord[],
1181 ContextClosureLookupContext &lookup_context)
1182{
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001183 if (context_intersects (c->glyphs,
1184 inputCount, input,
1185 lookup_context))
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001186 recurse_lookups (c,
1187 lookupCount, lookupRecord);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001188}
1189
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001190static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
1191 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001192 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001193 unsigned int lookupCount,
1194 const LookupRecord lookupRecord[],
1195 ContextCollectGlyphsLookupContext &lookup_context)
1196{
Behdad Esfahbod83035932012-12-04 17:08:41 -05001197 collect_array (c, c->input,
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001198 inputCount ? inputCount - 1 : 0, input,
1199 lookup_context.funcs.collect, lookup_context.collect_data);
1200 recurse_lookups (c,
1201 lookupCount, lookupRecord);
1202}
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001203
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001204static inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
1205 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001206 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbod0beb66e2012-12-05 18:46:04 -05001207 unsigned int lookupCount HB_UNUSED,
1208 const LookupRecord lookupRecord[] HB_UNUSED,
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001209 ContextApplyLookupContext &lookup_context)
1210{
1211 return would_match_input (c,
1212 inputCount, input,
1213 lookup_context.funcs.match, lookup_context.match_data);
1214}
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001215static inline bool context_apply_lookup (hb_ot_apply_context_t *c,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001216 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001217 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001218 unsigned int lookupCount,
1219 const LookupRecord lookupRecord[],
1220 ContextApplyLookupContext &lookup_context)
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001221{
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001222 unsigned int match_length = 0;
Behdad Esfahbod5ba45042015-11-02 15:43:08 -08001223 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001224 return match_input (c,
Behdad Esfahbod41697102010-05-05 01:37:58 -04001225 inputCount, input,
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001226 lookup_context.funcs.match, lookup_context.match_data,
1227 &match_length, match_positions)
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001228 && (c->buffer->unsafe_to_break (c->buffer->idx, c->buffer->idx + match_length),
1229 apply_lookup (c,
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001230 inputCount, match_positions,
1231 lookupCount, lookupRecord,
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001232 match_length));
Behdad Esfahbodf14c2b72009-05-18 02:36:18 -04001233}
1234
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001235struct Rule
1236{
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001237 inline bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const
1238 {
1239 return context_intersects (glyphs,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001240 inputCount, inputZ.arrayZ,
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001241 lookup_context);
1242 }
1243
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001244 inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001245 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001246 TRACE_CLOSURE (this);
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001247 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAtOffset<UnsizedArrayOf<LookupRecord> > (inputZ.arrayZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001248 context_closure_lookup (c,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001249 inputCount, inputZ.arrayZ,
1250 lookupCount, lookupRecord.arrayZ,
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001251 lookup_context);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001252 }
1253
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001254 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const
1255 {
1256 TRACE_COLLECT_GLYPHS (this);
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001257 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAtOffset<UnsizedArrayOf<LookupRecord> > (inputZ.arrayZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001258 context_collect_glyphs_lookup (c,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001259 inputCount, inputZ.arrayZ,
1260 lookupCount, lookupRecord.arrayZ,
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001261 lookup_context);
1262 }
1263
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001264 inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
1265 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001266 TRACE_WOULD_APPLY (this);
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001267 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAtOffset<UnsizedArrayOf<LookupRecord> > (inputZ.arrayZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
1268 return_trace (context_would_apply_lookup (c, inputCount, inputZ.arrayZ, lookupCount, lookupRecord.arrayZ, lookup_context));
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001269 }
1270
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001271 inline bool apply (hb_ot_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001272 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001273 TRACE_APPLY (this);
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001274 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAtOffset<UnsizedArrayOf<LookupRecord> > (inputZ.arrayZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
1275 return_trace (context_apply_lookup (c, inputCount, inputZ.arrayZ, lookupCount, lookupRecord.arrayZ, lookup_context));
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001276 }
1277
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001278 public:
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001279 inline bool sanitize (hb_sanitize_context_t *c) const
1280 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001281 TRACE_SANITIZE (this);
Behdad Esfahbod5aad8192017-11-03 17:16:26 -04001282 return_trace (inputCount.sanitize (c) &&
1283 lookupCount.sanitize (c) &&
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001284 c->check_range (inputZ.arrayZ,
Behdad Esfahbod5dfd6e02018-09-10 15:45:32 +02001285 inputZ[0].static_size * (inputCount ? inputCount - 1 : 0) +
Behdad Esfahbod6d7c6e12018-02-07 14:09:56 -06001286 LookupRecord::static_size * lookupCount));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001287 }
1288
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001289 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001290 HBUINT16 inputCount; /* Total number of glyphs in input
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001291 * glyph sequence--includes the first
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001292 * glyph */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001293 HBUINT16 lookupCount; /* Number of LookupRecords */
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001294 UnsizedArrayOf<HBUINT16>
1295 inputZ; /* Array of match inputs--start with
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001296 * second glyph */
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001297/*UnsizedArrayOf<LookupRecord>
1298 lookupRecordX;*/ /* Array of LookupRecords--in
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001299 * design order */
Behdad Esfahbod569da922010-05-10 16:38:32 -04001300 public:
Behdad Esfahbod6d7c6e12018-02-07 14:09:56 -06001301 DEFINE_SIZE_ARRAY (4, inputZ);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001302};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001303
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001304struct RuleSet
1305{
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001306 inline bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const
1307 {
1308 unsigned int num_rules = rule.len;
1309 for (unsigned int i = 0; i < num_rules; i++)
1310 if ((this+rule[i]).intersects (glyphs, lookup_context))
1311 return true;
1312 return false;
1313 }
1314
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001315 inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001316 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001317 TRACE_CLOSURE (this);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001318 unsigned int num_rules = rule.len;
1319 for (unsigned int i = 0; i < num_rules; i++)
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001320 (this+rule[i]).closure (c, lookup_context);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001321 }
1322
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001323 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const
1324 {
1325 TRACE_COLLECT_GLYPHS (this);
1326 unsigned int num_rules = rule.len;
1327 for (unsigned int i = 0; i < num_rules; i++)
1328 (this+rule[i]).collect_glyphs (c, lookup_context);
1329 }
1330
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001331 inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
1332 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001333 TRACE_WOULD_APPLY (this);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001334 unsigned int num_rules = rule.len;
1335 for (unsigned int i = 0; i < num_rules; i++)
1336 {
1337 if ((this+rule[i]).would_apply (c, lookup_context))
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001338 return_trace (true);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001339 }
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001340 return_trace (false);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001341 }
1342
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001343 inline bool apply (hb_ot_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001344 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001345 TRACE_APPLY (this);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001346 unsigned int num_rules = rule.len;
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001347 for (unsigned int i = 0; i < num_rules; i++)
1348 {
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001349 if ((this+rule[i]).apply (c, lookup_context))
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001350 return_trace (true);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001351 }
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001352 return_trace (false);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001353 }
1354
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001355 inline bool sanitize (hb_sanitize_context_t *c) const
1356 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001357 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001358 return_trace (rule.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001359 }
1360
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001361 protected:
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001362 OffsetArrayOf<Rule>
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001363 rule; /* Array of Rule tables
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001364 * ordered by preference */
Behdad Esfahboded074222010-05-10 18:08:46 -04001365 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04001366 DEFINE_SIZE_ARRAY (2, rule);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001367};
1368
1369
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001370struct ContextFormat1
1371{
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001372 inline bool intersects (const hb_set_t *glyphs) const
1373 {
1374 struct ContextClosureLookupContext lookup_context = {
1375 {intersects_glyph},
1376 nullptr
1377 };
1378
1379 unsigned int count = ruleSet.len;
1380 for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
1381 {
1382 if (unlikely (iter.get_coverage () >= count))
1383 break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
1384 if (glyphs->has (iter.get_glyph ()) &&
1385 (this+ruleSet[iter.get_coverage ()]).intersects (glyphs, lookup_context))
1386 return true;
1387 }
1388 return false;
1389 }
1390
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001391 inline void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001392 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001393 TRACE_CLOSURE (this);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001394
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001395 struct ContextClosureLookupContext lookup_context = {
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001396 {intersects_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001397 nullptr
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001398 };
1399
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001400 unsigned int count = ruleSet.len;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001401 for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
1402 {
1403 if (unlikely (iter.get_coverage () >= count))
1404 break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
1405 if (c->glyphs->has (iter.get_glyph ()))
1406 (this+ruleSet[iter.get_coverage ()]).closure (c, lookup_context);
1407 }
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001408 }
1409
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001410 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1411 {
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001412 TRACE_COLLECT_GLYPHS (this);
Behdad Esfahbod83035932012-12-04 17:08:41 -05001413 (this+coverage).add_coverage (c->input);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001414
1415 struct ContextCollectGlyphsLookupContext lookup_context = {
1416 {collect_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001417 nullptr
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001418 };
1419
1420 unsigned int count = ruleSet.len;
1421 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001422 (this+ruleSet[i]).collect_glyphs (c, lookup_context);
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001423 }
1424
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001425 inline bool would_apply (hb_would_apply_context_t *c) const
1426 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001427 TRACE_WOULD_APPLY (this);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001428
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05001429 const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001430 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001431 {match_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001432 nullptr
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001433 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001434 return_trace (rule_set.would_apply (c, lookup_context));
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001435 }
1436
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001437 inline const Coverage &get_coverage (void) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001438 { return this+coverage; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001439
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001440 inline bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001441 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001442 TRACE_APPLY (this);
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05001443 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -04001444 if (likely (index == NOT_COVERED))
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001445 return_trace (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04001446
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001447 const RuleSet &rule_set = this+ruleSet[index];
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001448 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001449 {match_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02001450 nullptr
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001451 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001452 return_trace (rule_set.apply (c, lookup_context));
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001453 }
1454
Behdad Esfahbod339d3602018-09-03 17:33:34 -07001455 inline bool subset (hb_subset_context_t *c) const
1456 {
1457 TRACE_SUBSET (this);
1458 // TODO(subset)
1459 return_trace (false);
1460 }
1461
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001462 inline bool sanitize (hb_sanitize_context_t *c) const
1463 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001464 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001465 return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001466 }
1467
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001468 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001469 HBUINT16 format; /* Format identifier--format = 1 */
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001470 OffsetTo<Coverage>
1471 coverage; /* Offset to Coverage table--from
1472 * beginning of table */
1473 OffsetArrayOf<RuleSet>
1474 ruleSet; /* Array of RuleSet tables
1475 * ordered by Coverage Index */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04001476 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04001477 DEFINE_SIZE_ARRAY (6, ruleSet);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001478};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001479
1480
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001481struct ContextFormat2
1482{
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001483 inline bool intersects (const hb_set_t *glyphs) const
1484 {
1485 if (!(this+coverage).intersects (glyphs))
1486 return false;
1487
1488 const ClassDef &class_def = this+classDef;
1489
1490 struct ContextClosureLookupContext lookup_context = {
1491 {intersects_class},
1492 &class_def
1493 };
1494
1495 unsigned int count = ruleSet.len;
1496 for (unsigned int i = 0; i < count; i++)
1497 if (class_def.intersects_class (glyphs, i) &&
1498 (this+ruleSet[i]).intersects (glyphs, lookup_context))
1499 return true;
1500
1501 return false;
1502 }
1503
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001504 inline void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001505 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001506 TRACE_CLOSURE (this);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001507 if (!(this+coverage).intersects (c->glyphs))
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001508 return;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001509
1510 const ClassDef &class_def = this+classDef;
1511
1512 struct ContextClosureLookupContext lookup_context = {
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001513 {intersects_class},
Behdad Esfahbod11fba792013-01-02 23:36:37 -06001514 &class_def
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001515 };
1516
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001517 unsigned int count = ruleSet.len;
1518 for (unsigned int i = 0; i < count; i++)
1519 if (class_def.intersects_class (c->glyphs, i)) {
1520 const RuleSet &rule_set = this+ruleSet[i];
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001521 rule_set.closure (c, lookup_context);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001522 }
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001523 }
1524
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001525 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1526 {
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001527 TRACE_COLLECT_GLYPHS (this);
Behdad Esfahbod83035932012-12-04 17:08:41 -05001528 (this+coverage).add_coverage (c->input);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001529
Behdad Esfahbod11fba792013-01-02 23:36:37 -06001530 const ClassDef &class_def = this+classDef;
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001531 struct ContextCollectGlyphsLookupContext lookup_context = {
1532 {collect_class},
Behdad Esfahbod11fba792013-01-02 23:36:37 -06001533 &class_def
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001534 };
1535
1536 unsigned int count = ruleSet.len;
1537 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001538 (this+ruleSet[i]).collect_glyphs (c, lookup_context);
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001539 }
1540
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001541 inline bool would_apply (hb_would_apply_context_t *c) const
1542 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001543 TRACE_WOULD_APPLY (this);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001544
1545 const ClassDef &class_def = this+classDef;
Behdad Esfahbod2dc11412012-11-24 19:16:34 -05001546 unsigned int index = class_def.get_class (c->glyphs[0]);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001547 const RuleSet &rule_set = this+ruleSet[index];
1548 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001549 {match_class},
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001550 &class_def
1551 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001552 return_trace (rule_set.would_apply (c, lookup_context));
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001553 }
1554
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001555 inline const Coverage &get_coverage (void) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001556 { return this+coverage; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001557
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001558 inline bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001559 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001560 TRACE_APPLY (this);
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05001561 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001562 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04001563
1564 const ClassDef &class_def = this+classDef;
Behdad Esfahbod2dc11412012-11-24 19:16:34 -05001565 index = class_def.get_class (c->buffer->cur().codepoint);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001566 const RuleSet &rule_set = this+ruleSet[index];
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001567 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001568 {match_class},
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04001569 &class_def
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001570 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001571 return_trace (rule_set.apply (c, lookup_context));
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001572 }
1573
Behdad Esfahbod339d3602018-09-03 17:33:34 -07001574 inline bool subset (hb_subset_context_t *c) const
1575 {
1576 TRACE_SUBSET (this);
1577 // TODO(subset)
1578 return_trace (false);
1579 }
1580
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001581 inline bool sanitize (hb_sanitize_context_t *c) const
1582 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001583 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001584 return_trace (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001585 }
1586
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001587 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001588 HBUINT16 format; /* Format identifier--format = 2 */
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001589 OffsetTo<Coverage>
1590 coverage; /* Offset to Coverage table--from
1591 * beginning of table */
1592 OffsetTo<ClassDef>
1593 classDef; /* Offset to glyph ClassDef table--from
1594 * beginning of table */
1595 OffsetArrayOf<RuleSet>
1596 ruleSet; /* Array of RuleSet tables
1597 * ordered by class */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04001598 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04001599 DEFINE_SIZE_ARRAY (8, ruleSet);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001600};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001601
1602
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001603struct ContextFormat3
1604{
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001605 inline bool intersects (const hb_set_t *glyphs) const
1606 {
1607 if (!(this+coverageZ[0]).intersects (glyphs))
1608 return false;
1609
1610 struct ContextClosureLookupContext lookup_context = {
1611 {intersects_coverage},
1612 this
1613 };
1614 return context_intersects (glyphs,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001615 glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001616 lookup_context);
1617 }
1618
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001619 inline void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001620 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001621 TRACE_CLOSURE (this);
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001622 if (!(this+coverageZ[0]).intersects (c->glyphs))
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001623 return;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001624
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001625 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ.arrayZ, coverageZ[0].static_size * glyphCount);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001626 struct ContextClosureLookupContext lookup_context = {
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001627 {intersects_coverage},
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001628 this
1629 };
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001630 context_closure_lookup (c,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001631 glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001632 lookupCount, lookupRecord,
1633 lookup_context);
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001634 }
1635
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001636 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1637 {
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001638 TRACE_COLLECT_GLYPHS (this);
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001639 (this+coverageZ[0]).add_coverage (c->input);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001640
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001641 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ.arrayZ, coverageZ[0].static_size * glyphCount);
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001642 struct ContextCollectGlyphsLookupContext lookup_context = {
1643 {collect_coverage},
Behdad Esfahbode75943d2012-11-30 08:38:24 +02001644 this
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001645 };
1646
1647 context_collect_glyphs_lookup (c,
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001648 glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001649 lookupCount, lookupRecord,
1650 lookup_context);
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001651 }
1652
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001653 inline bool would_apply (hb_would_apply_context_t *c) const
1654 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001655 TRACE_WOULD_APPLY (this);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001656
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001657 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ.arrayZ, coverageZ[0].static_size * glyphCount);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001658 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001659 {match_coverage},
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001660 this
1661 };
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001662 return_trace (context_would_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, lookup_context));
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001663 }
1664
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001665 inline const Coverage &get_coverage (void) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001666 { return this+coverageZ[0]; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001667
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001668 inline bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001669 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001670 TRACE_APPLY (this);
Behdad Esfahbod093c5202014-12-12 21:07:53 -08001671 unsigned int index = (this+coverageZ[0]).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001672 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04001673
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001674 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ.arrayZ, coverageZ[0].static_size * glyphCount);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001675 struct ContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05001676 {match_coverage},
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04001677 this
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001678 };
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001679 return_trace (context_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, lookup_context));
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001680 }
1681
Behdad Esfahbod339d3602018-09-03 17:33:34 -07001682 inline bool subset (hb_subset_context_t *c) const
1683 {
1684 TRACE_SUBSET (this);
1685 // TODO(subset)
1686 return_trace (false);
1687 }
1688
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001689 inline bool sanitize (hb_sanitize_context_t *c) const
1690 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001691 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001692 if (!c->check_struct (this)) return_trace (false);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001693 unsigned int count = glyphCount;
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001694 if (!count) return_trace (false); /* We want to access coverageZ[0] freely. */
Behdad Esfahbod9507b052018-09-10 23:18:07 +02001695 if (!c->check_array (coverageZ.arrayZ, count)) return_trace (false);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001696 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001697 if (!coverageZ[i].sanitize (c, this)) return_trace (false);
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001698 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ.arrayZ, coverageZ[0].static_size * count);
Behdad Esfahbod9507b052018-09-10 23:18:07 +02001699 return_trace (c->check_array (lookupRecord, lookupCount));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001700 }
1701
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001702 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001703 HBUINT16 format; /* Format identifier--format = 3 */
1704 HBUINT16 glyphCount; /* Number of glyphs in the input glyph
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001705 * sequence */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001706 HBUINT16 lookupCount; /* Number of LookupRecords */
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001707 UnsizedArrayOf<OffsetTo<Coverage> >
1708 coverageZ; /* Array of offsets to Coverage
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04001709 * table in glyph sequence order */
Behdad Esfahbodbc485a92018-09-10 23:02:24 +02001710/*UnsizedArrayOf<LookupRecord>
1711 lookupRecordX;*/ /* Array of LookupRecords--in
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001712 * design order */
Behdad Esfahbod569da922010-05-10 16:38:32 -04001713 public:
Behdad Esfahbod6d7c6e12018-02-07 14:09:56 -06001714 DEFINE_SIZE_ARRAY (6, coverageZ);
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001715};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001716
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001717struct Context
1718{
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05001719 template <typename context_t>
Behdad Esfahbod9c5a9ee2013-03-09 01:55:04 -05001720 inline typename context_t::return_t dispatch (context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001721 {
Behdad Esfahbod00f6a8e2014-12-12 20:36:49 -08001722 TRACE_DISPATCH (this, u.format);
Behdad Esfahbodf396fbb2015-10-09 12:25:55 -04001723 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001724 switch (u.format) {
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001725 case 1: return_trace (c->dispatch (u.format1));
1726 case 2: return_trace (c->dispatch (u.format2));
1727 case 3: return_trace (c->dispatch (u.format3));
1728 default:return_trace (c->default_return_value ());
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001729 }
1730 }
1731
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001732 protected:
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001733 union {
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001734 HBUINT16 format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -04001735 ContextFormat1 format1;
1736 ContextFormat2 format2;
1737 ContextFormat3 format3;
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001738 } u;
1739};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04001740
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001741
1742/* Chaining Contextual lookups */
1743
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001744struct ChainContextClosureLookupContext
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001745{
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001746 ContextClosureFuncs funcs;
1747 const void *intersects_data[3];
1748};
1749
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001750struct ChainContextCollectGlyphsLookupContext
1751{
1752 ContextCollectGlyphsFuncs funcs;
1753 const void *collect_data[3];
1754};
1755
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001756struct ChainContextApplyLookupContext
1757{
1758 ContextApplyFuncs funcs;
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04001759 const void *match_data[3];
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001760};
1761
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001762static inline bool chain_context_intersects (const hb_set_t *glyphs,
1763 unsigned int backtrackCount,
1764 const HBUINT16 backtrack[],
1765 unsigned int inputCount, /* Including the first glyph (not matched) */
1766 const HBUINT16 input[], /* Array of input values--start with second glyph */
1767 unsigned int lookaheadCount,
1768 const HBUINT16 lookahead[],
1769 ChainContextClosureLookupContext &lookup_context)
1770{
1771 return intersects_array (glyphs,
1772 backtrackCount, backtrack,
1773 lookup_context.funcs.intersects, lookup_context.intersects_data[0])
1774 && intersects_array (glyphs,
1775 inputCount ? inputCount - 1 : 0, input,
1776 lookup_context.funcs.intersects, lookup_context.intersects_data[1])
1777 && intersects_array (glyphs,
1778 lookaheadCount, lookahead,
1779 lookup_context.funcs.intersects, lookup_context.intersects_data[2]);
1780}
1781
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001782static inline void chain_context_closure_lookup (hb_closure_context_t *c,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001783 unsigned int backtrackCount,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001784 const HBUINT16 backtrack[],
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001785 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001786 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001787 unsigned int lookaheadCount,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001788 const HBUINT16 lookahead[],
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001789 unsigned int lookupCount,
1790 const LookupRecord lookupRecord[],
1791 ChainContextClosureLookupContext &lookup_context)
1792{
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001793 if (chain_context_intersects (c->glyphs,
1794 backtrackCount, backtrack,
1795 inputCount, input,
1796 lookaheadCount, lookahead,
1797 lookup_context))
Behdad Esfahbodd0a52332012-11-23 18:54:59 -05001798 recurse_lookups (c,
1799 lookupCount, lookupRecord);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001800}
1801
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001802static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
1803 unsigned int backtrackCount,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001804 const HBUINT16 backtrack[],
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001805 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001806 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001807 unsigned int lookaheadCount,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001808 const HBUINT16 lookahead[],
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001809 unsigned int lookupCount,
1810 const LookupRecord lookupRecord[],
1811 ChainContextCollectGlyphsLookupContext &lookup_context)
1812{
Behdad Esfahbod83035932012-12-04 17:08:41 -05001813 collect_array (c, c->before,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001814 backtrackCount, backtrack,
1815 lookup_context.funcs.collect, lookup_context.collect_data[0]);
Behdad Esfahbod83035932012-12-04 17:08:41 -05001816 collect_array (c, c->input,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001817 inputCount ? inputCount - 1 : 0, input,
1818 lookup_context.funcs.collect, lookup_context.collect_data[1]);
Behdad Esfahbod83035932012-12-04 17:08:41 -05001819 collect_array (c, c->after,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001820 lookaheadCount, lookahead,
1821 lookup_context.funcs.collect, lookup_context.collect_data[2]);
1822 recurse_lookups (c,
1823 lookupCount, lookupRecord);
1824}
1825
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001826static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c,
1827 unsigned int backtrackCount,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001828 const HBUINT16 backtrack[] HB_UNUSED,
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001829 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001830 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001831 unsigned int lookaheadCount,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001832 const HBUINT16 lookahead[] HB_UNUSED,
Behdad Esfahbod0beb66e2012-12-05 18:46:04 -05001833 unsigned int lookupCount HB_UNUSED,
1834 const LookupRecord lookupRecord[] HB_UNUSED,
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001835 ChainContextApplyLookupContext &lookup_context)
1836{
Behdad Esfahbodd9b204d2012-08-23 16:22:28 -04001837 return (c->zero_context ? !backtrackCount && !lookaheadCount : true)
Behdad Esfahbod1f2bb172012-08-23 16:10:37 -04001838 && would_match_input (c,
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001839 inputCount, input,
1840 lookup_context.funcs.match, lookup_context.match_data[1]);
1841}
1842
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001843static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001844 unsigned int backtrackCount,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001845 const HBUINT16 backtrack[],
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001846 unsigned int inputCount, /* Including the first glyph (not matched) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001847 const HBUINT16 input[], /* Array of input values--start with second glyph */
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001848 unsigned int lookaheadCount,
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001849 const HBUINT16 lookahead[],
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001850 unsigned int lookupCount,
1851 const LookupRecord lookupRecord[],
1852 ChainContextApplyLookupContext &lookup_context)
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04001853{
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001854 unsigned int start_index = 0, match_length = 0, end_index = 0;
Behdad Esfahbod5ba45042015-11-02 15:43:08 -08001855 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
Behdad Esfahbodf19e0b02012-06-09 02:26:57 -04001856 return match_input (c,
Behdad Esfahbod41697102010-05-05 01:37:58 -04001857 inputCount, input,
1858 lookup_context.funcs.match, lookup_context.match_data[1],
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001859 &match_length, match_positions)
Behdad Esfahbodf19e0b02012-06-09 02:26:57 -04001860 && match_backtrack (c,
1861 backtrackCount, backtrack,
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001862 lookup_context.funcs.match, lookup_context.match_data[0],
1863 &start_index)
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001864 && match_lookahead (c,
Behdad Esfahbod41697102010-05-05 01:37:58 -04001865 lookaheadCount, lookahead,
1866 lookup_context.funcs.match, lookup_context.match_data[2],
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001867 match_length, &end_index)
1868 && (c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index),
1869 apply_lookup (c,
Behdad Esfahbod6b65a762013-10-14 18:51:39 +02001870 inputCount, match_positions,
1871 lookupCount, lookupRecord,
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001872 match_length));
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04001873}
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001874
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001875struct ChainRule
1876{
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001877 inline bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
1878 {
1879 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
1880 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
1881 return chain_context_intersects (glyphs,
1882 backtrack.len, backtrack.arrayZ,
Behdad Esfahbodeffc7ce2018-09-13 20:21:54 +02001883 input.lenP1, input.arrayZ,
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001884 lookahead.len, lookahead.arrayZ,
1885 lookup_context);
1886 }
1887
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001888 inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001889 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001890 TRACE_CLOSURE (this);
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001891 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
1892 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001893 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001894 chain_context_closure_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07001895 backtrack.len, backtrack.arrayZ,
Behdad Esfahbodeffc7ce2018-09-13 20:21:54 +02001896 input.lenP1, input.arrayZ,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07001897 lookahead.len, lookahead.arrayZ,
1898 lookup.len, lookup.arrayZ,
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001899 lookup_context);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001900 }
1901
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001902 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
1903 {
1904 TRACE_COLLECT_GLYPHS (this);
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001905 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
1906 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001907 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1908 chain_context_collect_glyphs_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07001909 backtrack.len, backtrack.arrayZ,
Behdad Esfahbodeffc7ce2018-09-13 20:21:54 +02001910 input.lenP1, input.arrayZ,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07001911 lookahead.len, lookahead.arrayZ,
1912 lookup.len, lookup.arrayZ,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001913 lookup_context);
1914 }
1915
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001916 inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
1917 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001918 TRACE_WOULD_APPLY (this);
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001919 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
1920 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001921 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001922 return_trace (chain_context_would_apply_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07001923 backtrack.len, backtrack.arrayZ,
Behdad Esfahbodeffc7ce2018-09-13 20:21:54 +02001924 input.lenP1, input.arrayZ,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07001925 lookahead.len, lookahead.arrayZ, lookup.len,
1926 lookup.arrayZ, lookup_context));
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001927 }
1928
Behdad Esfahbodfd034492018-01-17 16:46:51 -08001929 inline bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001930 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001931 TRACE_APPLY (this);
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001932 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
1933 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
Behdad Esfahbode961c862010-04-21 15:56:11 -04001934 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001935 return_trace (chain_context_apply_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07001936 backtrack.len, backtrack.arrayZ,
Behdad Esfahbodeffc7ce2018-09-13 20:21:54 +02001937 input.lenP1, input.arrayZ,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07001938 lookahead.len, lookahead.arrayZ, lookup.len,
1939 lookup.arrayZ, lookup_context));
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04001940 }
1941
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001942 inline bool sanitize (hb_sanitize_context_t *c) const
1943 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001944 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001945 if (!backtrack.sanitize (c)) return_trace (false);
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001946 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001947 if (!input.sanitize (c)) return_trace (false);
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001948 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001949 if (!lookahead.sanitize (c)) return_trace (false);
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001950 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001951 return_trace (lookup.sanitize (c));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001952 }
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001953
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001954 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001955 ArrayOf<HBUINT16>
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04001956 backtrack; /* Array of backtracking values
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001957 * (to be matched before the input
1958 * sequence) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001959 HeadlessArrayOf<HBUINT16>
Behdad Esfahbode8cbaaf2009-05-18 02:03:58 -04001960 inputX; /* Array of input values (start with
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001961 * second glyph) */
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001962 ArrayOf<HBUINT16>
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04001963 lookaheadX; /* Array of lookahead values's (to be
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04001964 * matched after the input sequence) */
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04001965 ArrayOf<LookupRecord>
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04001966 lookupX; /* Array of LookupRecords--in
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001967 * design order) */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04001968 public:
Behdad Esfahbodbea34c72010-05-10 17:28:16 -04001969 DEFINE_SIZE_MIN (8);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001970};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001971
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04001972struct ChainRuleSet
1973{
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001974 inline bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
1975 {
1976 unsigned int num_rules = rule.len;
1977 for (unsigned int i = 0; i < num_rules; i++)
1978 if ((this+rule[i]).intersects (glyphs, lookup_context))
1979 return true;
1980 return false;
1981 }
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001982 inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001983 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001984 TRACE_CLOSURE (this);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001985 unsigned int num_rules = rule.len;
1986 for (unsigned int i = 0; i < num_rules; i++)
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001987 (this+rule[i]).closure (c, lookup_context);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04001988 }
1989
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05001990 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
1991 {
1992 TRACE_COLLECT_GLYPHS (this);
1993 unsigned int num_rules = rule.len;
1994 for (unsigned int i = 0; i < num_rules; i++)
1995 (this+rule[i]).collect_glyphs (c, lookup_context);
1996 }
1997
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001998 inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
1999 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002000 TRACE_WOULD_APPLY (this);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002001 unsigned int num_rules = rule.len;
2002 for (unsigned int i = 0; i < num_rules; i++)
2003 if ((this+rule[i]).would_apply (c, lookup_context))
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002004 return_trace (true);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002005
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002006 return_trace (false);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002007 }
2008
Behdad Esfahbodfd034492018-01-17 16:46:51 -08002009 inline bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002010 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002011 TRACE_APPLY (this);
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04002012 unsigned int num_rules = rule.len;
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002013 for (unsigned int i = 0; i < num_rules; i++)
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04002014 if ((this+rule[i]).apply (c, lookup_context))
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002015 return_trace (true);
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04002016
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002017 return_trace (false);
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04002018 }
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002019
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002020 inline bool sanitize (hb_sanitize_context_t *c) const
2021 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002022 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002023 return_trace (rule.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002024 }
2025
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002026 protected:
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04002027 OffsetArrayOf<ChainRule>
2028 rule; /* Array of ChainRule tables
2029 * ordered by preference */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04002030 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04002031 DEFINE_SIZE_ARRAY (2, rule);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002032};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002033
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002034struct ChainContextFormat1
2035{
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002036 inline bool intersects (const hb_set_t *glyphs) const
2037 {
2038 struct ChainContextClosureLookupContext lookup_context = {
2039 {intersects_glyph},
2040 {nullptr, nullptr, nullptr}
2041 };
2042
2043 unsigned int count = ruleSet.len;
2044 for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
2045 {
2046 if (unlikely (iter.get_coverage () >= count))
2047 break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
2048 if (glyphs->has (iter.get_glyph ()) &&
2049 (this+ruleSet[iter.get_coverage ()]).intersects (glyphs, lookup_context))
2050 return true;
2051 }
2052 return false;
2053 }
2054
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002055 inline void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002056 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002057 TRACE_CLOSURE (this);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002058
2059 struct ChainContextClosureLookupContext lookup_context = {
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002060 {intersects_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02002061 {nullptr, nullptr, nullptr}
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002062 };
2063
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002064 unsigned int count = ruleSet.len;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002065 for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
2066 {
2067 if (unlikely (iter.get_coverage () >= count))
2068 break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
2069 if (c->glyphs->has (iter.get_glyph ()))
2070 (this+ruleSet[iter.get_coverage ()]).closure (c, lookup_context);
2071 }
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002072 }
2073
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002074 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
2075 {
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002076 TRACE_COLLECT_GLYPHS (this);
Behdad Esfahbod83035932012-12-04 17:08:41 -05002077 (this+coverage).add_coverage (c->input);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002078
2079 struct ChainContextCollectGlyphsLookupContext lookup_context = {
2080 {collect_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02002081 {nullptr, nullptr, nullptr}
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002082 };
2083
2084 unsigned int count = ruleSet.len;
2085 for (unsigned int i = 0; i < count; i++)
2086 (this+ruleSet[i]).collect_glyphs (c, lookup_context);
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002087 }
2088
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002089 inline bool would_apply (hb_would_apply_context_t *c) const
2090 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002091 TRACE_WOULD_APPLY (this);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002092
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05002093 const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002094 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002095 {match_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02002096 {nullptr, nullptr, nullptr}
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002097 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002098 return_trace (rule_set.would_apply (c, lookup_context));
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002099 }
2100
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002101 inline const Coverage &get_coverage (void) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002102 { return this+coverage; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002103
Behdad Esfahbodfd034492018-01-17 16:46:51 -08002104 inline bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002105 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002106 TRACE_APPLY (this);
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05002107 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002108 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002109
2110 const ChainRuleSet &rule_set = this+ruleSet[index];
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002111 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002112 {match_glyph},
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +02002113 {nullptr, nullptr, nullptr}
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002114 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002115 return_trace (rule_set.apply (c, lookup_context));
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002116 }
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002117
Behdad Esfahbod339d3602018-09-03 17:33:34 -07002118 inline bool subset (hb_subset_context_t *c) const
2119 {
2120 TRACE_SUBSET (this);
2121 // TODO(subset)
2122 return_trace (false);
2123 }
2124
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002125 inline bool sanitize (hb_sanitize_context_t *c) const
2126 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002127 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002128 return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002129 }
2130
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002131 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002132 HBUINT16 format; /* Format identifier--format = 1 */
Behdad Esfahbod48f16ed2009-05-17 22:11:30 -04002133 OffsetTo<Coverage>
2134 coverage; /* Offset to Coverage table--from
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002135 * beginning of table */
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002136 OffsetArrayOf<ChainRuleSet>
2137 ruleSet; /* Array of ChainRuleSet tables
2138 * ordered by Coverage Index */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04002139 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04002140 DEFINE_SIZE_ARRAY (6, ruleSet);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002141};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002142
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002143struct ChainContextFormat2
2144{
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002145 inline bool intersects (const hb_set_t *glyphs) const
2146 {
2147 if (!(this+coverage).intersects (glyphs))
2148 return false;
2149
2150 const ClassDef &backtrack_class_def = this+backtrackClassDef;
2151 const ClassDef &input_class_def = this+inputClassDef;
2152 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2153
2154 struct ChainContextClosureLookupContext lookup_context = {
2155 {intersects_class},
2156 {&backtrack_class_def,
2157 &input_class_def,
2158 &lookahead_class_def}
2159 };
2160
2161 unsigned int count = ruleSet.len;
2162 for (unsigned int i = 0; i < count; i++)
2163 if (input_class_def.intersects_class (glyphs, i) &&
2164 (this+ruleSet[i]).intersects (glyphs, lookup_context))
2165 return true;
2166
2167 return false;
2168 }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002169 inline void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002170 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002171 TRACE_CLOSURE (this);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002172 if (!(this+coverage).intersects (c->glyphs))
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002173 return;
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002174
2175 const ClassDef &backtrack_class_def = this+backtrackClassDef;
2176 const ClassDef &input_class_def = this+inputClassDef;
2177 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2178
2179 struct ChainContextClosureLookupContext lookup_context = {
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002180 {intersects_class},
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002181 {&backtrack_class_def,
2182 &input_class_def,
2183 &lookahead_class_def}
2184 };
2185
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002186 unsigned int count = ruleSet.len;
2187 for (unsigned int i = 0; i < count; i++)
2188 if (input_class_def.intersects_class (c->glyphs, i)) {
2189 const ChainRuleSet &rule_set = this+ruleSet[i];
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002190 rule_set.closure (c, lookup_context);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002191 }
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002192 }
2193
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002194 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
2195 {
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002196 TRACE_COLLECT_GLYPHS (this);
Behdad Esfahbod83035932012-12-04 17:08:41 -05002197 (this+coverage).add_coverage (c->input);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002198
Behdad Esfahbod11fba792013-01-02 23:36:37 -06002199 const ClassDef &backtrack_class_def = this+backtrackClassDef;
2200 const ClassDef &input_class_def = this+inputClassDef;
2201 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2202
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002203 struct ChainContextCollectGlyphsLookupContext lookup_context = {
2204 {collect_class},
Behdad Esfahbod11fba792013-01-02 23:36:37 -06002205 {&backtrack_class_def,
2206 &input_class_def,
2207 &lookahead_class_def}
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002208 };
2209
2210 unsigned int count = ruleSet.len;
2211 for (unsigned int i = 0; i < count; i++)
2212 (this+ruleSet[i]).collect_glyphs (c, lookup_context);
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002213 }
2214
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002215 inline bool would_apply (hb_would_apply_context_t *c) const
2216 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002217 TRACE_WOULD_APPLY (this);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002218
Behdad Esfahbod11fba792013-01-02 23:36:37 -06002219 const ClassDef &backtrack_class_def = this+backtrackClassDef;
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002220 const ClassDef &input_class_def = this+inputClassDef;
Behdad Esfahbod11fba792013-01-02 23:36:37 -06002221 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002222
Behdad Esfahbod2dc11412012-11-24 19:16:34 -05002223 unsigned int index = input_class_def.get_class (c->glyphs[0]);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002224 const ChainRuleSet &rule_set = this+ruleSet[index];
2225 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002226 {match_class},
Behdad Esfahbod11fba792013-01-02 23:36:37 -06002227 {&backtrack_class_def,
2228 &input_class_def,
2229 &lookahead_class_def}
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002230 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002231 return_trace (rule_set.would_apply (c, lookup_context));
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002232 }
2233
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002234 inline const Coverage &get_coverage (void) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002235 { return this+coverage; }
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002236
Behdad Esfahbodfd034492018-01-17 16:46:51 -08002237 inline bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002238 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002239 TRACE_APPLY (this);
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05002240 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002241 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002242
2243 const ClassDef &backtrack_class_def = this+backtrackClassDef;
2244 const ClassDef &input_class_def = this+inputClassDef;
2245 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2246
Behdad Esfahbod2dc11412012-11-24 19:16:34 -05002247 index = input_class_def.get_class (c->buffer->cur().codepoint);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002248 const ChainRuleSet &rule_set = this+ruleSet[index];
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002249 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002250 {match_class},
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04002251 {&backtrack_class_def,
2252 &input_class_def,
2253 &lookahead_class_def}
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002254 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002255 return_trace (rule_set.apply (c, lookup_context));
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002256 }
2257
Behdad Esfahbod339d3602018-09-03 17:33:34 -07002258 inline bool subset (hb_subset_context_t *c) const
2259 {
2260 TRACE_SUBSET (this);
2261 // TODO(subset)
2262 return_trace (false);
2263 }
2264
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002265 inline bool sanitize (hb_sanitize_context_t *c) const
2266 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002267 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002268 return_trace (coverage.sanitize (c, this) &&
2269 backtrackClassDef.sanitize (c, this) &&
2270 inputClassDef.sanitize (c, this) &&
2271 lookaheadClassDef.sanitize (c, this) &&
2272 ruleSet.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002273 }
2274
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002275 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002276 HBUINT16 format; /* Format identifier--format = 2 */
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002277 OffsetTo<Coverage>
2278 coverage; /* Offset to Coverage table--from
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002279 * beginning of table */
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002280 OffsetTo<ClassDef>
2281 backtrackClassDef; /* Offset to glyph ClassDef table
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002282 * containing backtrack sequence
2283 * data--from beginning of table */
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002284 OffsetTo<ClassDef>
2285 inputClassDef; /* Offset to glyph ClassDef
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002286 * table containing input sequence
2287 * data--from beginning of table */
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002288 OffsetTo<ClassDef>
2289 lookaheadClassDef; /* Offset to glyph ClassDef table
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002290 * containing lookahead sequence
2291 * data--from beginning of table */
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04002292 OffsetArrayOf<ChainRuleSet>
2293 ruleSet; /* Array of ChainRuleSet tables
2294 * ordered by class */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04002295 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04002296 DEFINE_SIZE_ARRAY (12, ruleSet);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002297};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002298
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002299struct ChainContextFormat3
2300{
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07002301 inline bool intersects (const hb_set_t *glyphs) const
2302 {
2303 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2304
2305 if (!(this+input[0]).intersects (glyphs))
2306 return false;
2307
2308 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2309 struct ChainContextClosureLookupContext lookup_context = {
2310 {intersects_coverage},
2311 {this, this, this}
2312 };
2313 return chain_context_intersects (glyphs,
2314 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2315 input.len, (const HBUINT16 *) input.arrayZ + 1,
2316 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2317 lookup_context);
2318 }
2319
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002320 inline void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002321 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002322 TRACE_CLOSURE (this);
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002323 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2324
2325 if (!(this+input[0]).intersects (c->glyphs))
2326 return;
2327
2328 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2329 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2330 struct ChainContextClosureLookupContext lookup_context = {
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002331 {intersects_coverage},
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002332 {this, this, this}
2333 };
2334 chain_context_closure_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002335 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2336 input.len, (const HBUINT16 *) input.arrayZ + 1,
2337 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2338 lookup.len, lookup.arrayZ,
Behdad Esfahbod5caece62012-04-23 23:03:12 -04002339 lookup_context);
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002340 }
2341
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002342 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
2343 {
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002344 TRACE_COLLECT_GLYPHS (this);
2345 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2346
Behdad Esfahbod83035932012-12-04 17:08:41 -05002347 (this+input[0]).add_coverage (c->input);
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002348
2349 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2350 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2351 struct ChainContextCollectGlyphsLookupContext lookup_context = {
2352 {collect_coverage},
2353 {this, this, this}
2354 };
2355 chain_context_collect_glyphs_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002356 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2357 input.len, (const HBUINT16 *) input.arrayZ + 1,
2358 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2359 lookup.len, lookup.arrayZ,
Behdad Esfahbodf1b12782012-11-24 01:55:34 -05002360 lookup_context);
Behdad Esfahbod26514d52012-11-23 18:13:48 -05002361 }
2362
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002363 inline bool would_apply (hb_would_apply_context_t *c) const
2364 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002365 TRACE_WOULD_APPLY (this);
Behdad Esfahbode6f74792012-07-28 18:34:58 -04002366
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002367 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002368 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2369 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2370 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002371 {match_coverage},
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002372 {this, this, this}
2373 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002374 return_trace (chain_context_would_apply_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002375 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2376 input.len, (const HBUINT16 *) input.arrayZ + 1,
2377 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2378 lookup.len, lookup.arrayZ, lookup_context));
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002379 }
2380
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002381 inline const Coverage &get_coverage (void) const
2382 {
2383 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2384 return this+input[0];
2385 }
2386
Behdad Esfahbodfd034492018-01-17 16:46:51 -08002387 inline bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002388 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002389 TRACE_APPLY (this);
Behdad Esfahbode961c862010-04-21 15:56:11 -04002390 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04002391
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05002392 unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002393 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002394
Behdad Esfahbode961c862010-04-21 15:56:11 -04002395 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2396 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
Behdad Esfahbod31081f72012-04-23 16:54:58 -04002397 struct ChainContextApplyLookupContext lookup_context = {
Behdad Esfahbodec35a722012-11-22 16:05:59 -05002398 {match_coverage},
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04002399 {this, this, this}
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04002400 };
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002401 return_trace (chain_context_apply_lookup (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07002402 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2403 input.len, (const HBUINT16 *) input.arrayZ + 1,
2404 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2405 lookup.len, lookup.arrayZ, lookup_context));
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002406 }
2407
Behdad Esfahbod339d3602018-09-03 17:33:34 -07002408 inline bool subset (hb_subset_context_t *c) const
2409 {
2410 TRACE_SUBSET (this);
2411 // TODO(subset)
2412 return_trace (false);
2413 }
2414
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002415 inline bool sanitize (hb_sanitize_context_t *c) const
2416 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002417 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002418 if (!backtrack.sanitize (c, this)) return_trace (false);
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002419 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002420 if (!input.sanitize (c, this)) return_trace (false);
2421 if (!input.len) return_trace (false); /* To be consistent with Context. */
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002422 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002423 if (!lookahead.sanitize (c, this)) return_trace (false);
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002424 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002425 return_trace (lookup.sanitize (c));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002426 }
2427
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002428 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002429 HBUINT16 format; /* Format identifier--format = 3 */
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04002430 OffsetArrayOf<Coverage>
Behdad Esfahbod13ed4402009-05-18 02:14:37 -04002431 backtrack; /* Array of coverage tables
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002432 * in backtracking sequence, in glyph
2433 * sequence order */
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04002434 OffsetArrayOf<Coverage>
Behdad Esfahbod13ed4402009-05-18 02:14:37 -04002435 inputX ; /* Array of coverage
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002436 * tables in input sequence, in glyph
2437 * sequence order */
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04002438 OffsetArrayOf<Coverage>
Behdad Esfahbod13ed4402009-05-18 02:14:37 -04002439 lookaheadX; /* Array of coverage tables
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002440 * in lookahead sequence, in glyph
2441 * sequence order */
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04002442 ArrayOf<LookupRecord>
Behdad Esfahbod02e1e5c2009-05-18 02:47:57 -04002443 lookupX; /* Array of LookupRecords--in
Behdad Esfahboddcb6b602009-05-18 01:49:57 -04002444 * design order) */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04002445 public:
Behdad Esfahbodbea34c72010-05-10 17:28:16 -04002446 DEFINE_SIZE_MIN (10);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002447};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002448
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002449struct ChainContext
2450{
Behdad Esfahbod44fc2372012-11-21 23:33:13 -05002451 template <typename context_t>
Behdad Esfahbod9c5a9ee2013-03-09 01:55:04 -05002452 inline typename context_t::return_t dispatch (context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002453 {
Behdad Esfahbod00f6a8e2014-12-12 20:36:49 -08002454 TRACE_DISPATCH (this, u.format);
Behdad Esfahbodf396fbb2015-10-09 12:25:55 -04002455 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04002456 switch (u.format) {
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002457 case 1: return_trace (c->dispatch (u.format1));
2458 case 2: return_trace (c->dispatch (u.format2));
2459 case 3: return_trace (c->dispatch (u.format3));
2460 default:return_trace (c->default_return_value ());
Behdad Esfahbode72b3602012-07-19 14:35:23 -04002461 }
2462 }
2463
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002464 protected:
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002465 union {
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002466 HBUINT16 format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -04002467 ChainContextFormat1 format1;
2468 ChainContextFormat2 format2;
2469 ChainContextFormat3 format3;
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002470 } u;
2471};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04002472
2473
Behdad Esfahbod095a1252015-02-19 10:29:41 +03002474template <typename T>
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002475struct ExtensionFormat1
2476{
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002477 inline unsigned int get_type (void) const { return extensionLookupType; }
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002478
Behdad Esfahbod095a1252015-02-19 10:29:41 +03002479 template <typename X>
2480 inline const X& get_subtable (void) const
2481 {
2482 unsigned int offset = extensionOffset;
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07002483 if (unlikely (!offset)) return Null(typename T::SubTable);
2484 return StructAtOffset<typename T::SubTable> (this, offset);
Behdad Esfahbod095a1252015-02-19 10:29:41 +03002485 }
2486
2487 template <typename context_t>
2488 inline typename context_t::return_t dispatch (context_t *c) const
2489 {
2490 TRACE_DISPATCH (this, format);
Behdad Esfahbodf396fbb2015-10-09 12:25:55 -04002491 if (unlikely (!c->may_dispatch (this, this))) return_trace (c->no_dispatch_return_value ());
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07002492 return_trace (get_subtable<typename T::SubTable> ().dispatch (c, get_type ()));
Behdad Esfahbod095a1252015-02-19 10:29:41 +03002493 }
2494
2495 /* This is called from may_dispatch() above with hb_sanitize_context_t. */
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002496 inline bool sanitize (hb_sanitize_context_t *c) const
2497 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002498 TRACE_SANITIZE (this);
Behdad Esfahbod949f6af2018-01-15 20:44:10 -05002499 return_trace (c->check_struct (this) &&
2500 extensionOffset != 0 &&
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07002501 extensionLookupType != T::SubTable::Extension);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002502 }
2503
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002504 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002505 HBUINT16 format; /* Format identifier. Set to 1. */
2506 HBUINT16 extensionLookupType; /* Lookup type of subtable referenced
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002507 * by ExtensionOffset (i.e. the
2508 * extension subtable). */
Behdad Esfahbodbcb6f1a2018-01-15 20:34:05 -05002509 HBUINT32 extensionOffset; /* Offset to the extension subtable,
Behdad Esfahbod81f2af42010-04-22 00:58:49 -04002510 * of lookup type subtable. */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04002511 public:
2512 DEFINE_SIZE_STATIC (8);
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002513};
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002514
Behdad Esfahbod653eeb22012-11-23 16:57:36 -05002515template <typename T>
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002516struct Extension
2517{
2518 inline unsigned int get_type (void) const
2519 {
2520 switch (u.format) {
Behdad Esfahboddacebca2010-05-10 19:45:41 -04002521 case 1: return u.format1.get_type ();
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002522 default:return 0;
2523 }
2524 }
Behdad Esfahbod7dddd4e2012-11-23 17:04:55 -05002525 template <typename X>
2526 inline const X& get_subtable (void) const
2527 {
Behdad Esfahbod095a1252015-02-19 10:29:41 +03002528 switch (u.format) {
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07002529 case 1: return u.format1.template get_subtable<typename T::SubTable> ();
2530 default:return Null(typename T::SubTable);
Behdad Esfahbod095a1252015-02-19 10:29:41 +03002531 }
Behdad Esfahbod7dddd4e2012-11-23 17:04:55 -05002532 }
2533
Behdad Esfahbod653eeb22012-11-23 16:57:36 -05002534 template <typename context_t>
Behdad Esfahbod9c5a9ee2013-03-09 01:55:04 -05002535 inline typename context_t::return_t dispatch (context_t *c) const
Behdad Esfahbod653eeb22012-11-23 16:57:36 -05002536 {
Behdad Esfahbod095a1252015-02-19 10:29:41 +03002537 TRACE_DISPATCH (this, u.format);
Behdad Esfahbodf396fbb2015-10-09 12:25:55 -04002538 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002539 switch (u.format) {
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002540 case 1: return_trace (u.format1.dispatch (c));
2541 default:return_trace (c->default_return_value ());
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04002542 }
2543 }
2544
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04002545 protected:
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002546 union {
Behdad Esfahbod6b191782018-01-10 03:07:30 +01002547 HBUINT16 format; /* Format identifier */
Behdad Esfahbod095a1252015-02-19 10:29:41 +03002548 ExtensionFormat1<T> format1;
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002549 } u;
2550};
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -04002551
2552
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04002553/*
2554 * GSUB/GPOS Common
2555 */
2556
Behdad Esfahbod60d77cf2009-05-19 23:58:54 -04002557struct GSUBGPOS
2558{
Behdad Esfahbodb912fbe2018-08-06 06:30:12 -07002559 inline bool has_data (void) const { return version.to_int () != 0; }
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04002560 inline unsigned int get_script_count (void) const
2561 { return (this+scriptList).len; }
2562 inline const Tag& get_script_tag (unsigned int i) const
2563 { return (this+scriptList).get_tag (i); }
Behdad Esfahbode21899b2009-11-04 16:36:14 -05002564 inline unsigned int get_script_tags (unsigned int start_offset,
2565 unsigned int *script_count /* IN/OUT */,
2566 hb_tag_t *script_tags /* OUT */) const
2567 { return (this+scriptList).get_tags (start_offset, script_count, script_tags); }
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04002568 inline const Script& get_script (unsigned int i) const
2569 { return (this+scriptList)[i]; }
2570 inline bool find_script_index (hb_tag_t tag, unsigned int *index) const
2571 { return (this+scriptList).find_index (tag, index); }
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04002572
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04002573 inline unsigned int get_feature_count (void) const
2574 { return (this+featureList).len; }
Jonathan Kewda132932014-04-27 14:05:24 +01002575 inline hb_tag_t get_feature_tag (unsigned int i) const
2576 { return i == Index::NOT_FOUND_INDEX ? HB_TAG_NONE : (this+featureList).get_tag (i); }
Behdad Esfahbode21899b2009-11-04 16:36:14 -05002577 inline unsigned int get_feature_tags (unsigned int start_offset,
2578 unsigned int *feature_count /* IN/OUT */,
2579 hb_tag_t *feature_tags /* OUT */) const
2580 { return (this+featureList).get_tags (start_offset, feature_count, feature_tags); }
Behdad Esfahbodbff3c0f2009-08-07 19:46:30 -04002581 inline const Feature& get_feature (unsigned int i) const
2582 { return (this+featureList)[i]; }
2583 inline bool find_feature_index (hb_tag_t tag, unsigned int *index) const
2584 { return (this+featureList).find_index (tag, index); }
2585
2586 inline unsigned int get_lookup_count (void) const
2587 { return (this+lookupList).len; }
2588 inline const Lookup& get_lookup (unsigned int i) const
2589 { return (this+lookupList)[i]; }
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04002590
Behdad Esfahbod30c42b62016-09-10 03:32:39 -07002591 inline bool find_variations_index (const int *coords, unsigned int num_coords,
2592 unsigned int *index) const
Behdad Esfahbod59055b52016-09-10 01:24:28 -07002593 { return (version.to_int () >= 0x00010001u ? this+featureVars : Null(FeatureVariations))
Behdad Esfahbod30c42b62016-09-10 03:32:39 -07002594 .find_index (coords, num_coords, index); }
Behdad Esfahbodec87ba92016-09-10 03:53:11 -07002595 inline const Feature& get_feature_variation (unsigned int feature_index,
2596 unsigned int variations_index) const
2597 {
2598 if (FeatureVariations::NOT_FOUND_INDEX != variations_index &&
2599 version.to_int () >= 0x00010001u)
2600 {
Behdad Esfahbod4ebbeb72016-09-10 04:52:34 -07002601 const Feature *feature = (this+featureVars).find_substitute (variations_index,
2602 feature_index);
Behdad Esfahbodec87ba92016-09-10 03:53:11 -07002603 if (feature)
2604 return *feature;
2605 }
2606 return get_feature (feature_index);
2607 }
Behdad Esfahbod59055b52016-09-10 01:24:28 -07002608
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07002609 template <typename TLookup>
Behdad Esfahbodbfa72a92018-09-01 18:34:50 -07002610 inline bool subset (hb_subset_context_t *c) const
2611 {
2612 TRACE_SUBSET (this);
2613 struct GSUBGPOS *out = c->serializer->embed (*this);
2614 if (unlikely (!out)) return_trace (false);
Behdad Esfahbod49c44b52018-09-03 16:37:17 -07002615 out->scriptList.serialize_subset (c, this+scriptList, out);
2616 out->featureList.serialize_subset (c, this+featureList, out);
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07002617
2618 typedef OffsetListOf<TLookup> TLookupList;
2619 /* TODO Use intersects() to count how many subtables survive? */
2620 CastR<OffsetTo<TLookupList> > (out->lookupList)
2621 .serialize_subset (c,
2622 this+CastR<const OffsetTo<TLookupList> > (lookupList),
2623 out);
2624
Behdad Esfahbodbfa72a92018-09-01 18:34:50 -07002625 if (version.to_int () >= 0x00010001u)
Behdad Esfahbod49c44b52018-09-03 16:37:17 -07002626 out->featureVars.serialize_subset (c, this+featureVars, out);
Behdad Esfahbodbfa72a92018-09-01 18:34:50 -07002627 return_trace (true);
2628 }
2629
2630 inline unsigned int get_size (void) const
2631 {
2632 return min_size +
2633 (version.to_int () >= 0x00010001u ? featureVars.static_size : 0);
2634 }
2635
Behdad Esfahbod6d618522018-09-03 16:41:28 -07002636 template <typename TLookup>
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03002637 inline bool sanitize (hb_sanitize_context_t *c) const
2638 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05002639 TRACE_SANITIZE (this);
Behdad Esfahbod6d618522018-09-03 16:41:28 -07002640 typedef OffsetListOf<TLookup> TLookupList;
Behdad Esfahbodb4715902015-09-29 14:57:02 +01002641 return_trace (version.sanitize (c) &&
2642 likely (version.major == 1) &&
2643 scriptList.sanitize (c, this) &&
2644 featureList.sanitize (c, this) &&
Behdad Esfahbod6d618522018-09-03 16:41:28 -07002645 CastR<OffsetTo<TLookupList> > (lookupList).sanitize (c, this) &&
Behdad Esfahbod59055b52016-09-10 01:24:28 -07002646 (version.to_int () < 0x00010001u || featureVars.sanitize (c, this)));
Behdad Esfahbodcd3827e2009-08-04 02:09:34 -04002647 }
2648
Behdad Esfahbod963413f2018-08-26 00:47:55 -07002649 template <typename T>
2650 struct accelerator_t
2651 {
2652 inline void init (hb_face_t *face)
2653 {
2654 this->blob = hb_sanitize_context_t().reference_table<T> (face);
Behdad Esfahbod453e0c62018-08-26 01:30:52 -07002655 table = this->blob->template as<T> ();
Behdad Esfahbod963413f2018-08-26 00:47:55 -07002656
Behdad Esfahbodb9291002018-08-26 01:15:47 -07002657 this->lookup_count = table->get_lookup_count ();
Behdad Esfahbod963413f2018-08-26 00:47:55 -07002658
2659 this->accels = (hb_ot_layout_lookup_accelerator_t *) calloc (this->lookup_count, sizeof (hb_ot_layout_lookup_accelerator_t));
2660 if (unlikely (!this->accels))
2661 this->lookup_count = 0;
2662
2663 for (unsigned int i = 0; i < this->lookup_count; i++)
Behdad Esfahbodb9291002018-08-26 01:15:47 -07002664 this->accels[i].init (table->get_lookup (i));
Behdad Esfahbod963413f2018-08-26 00:47:55 -07002665 }
2666
2667 inline void fini (void)
2668 {
Behdad Esfahbodb9291002018-08-26 01:15:47 -07002669 for (unsigned int i = 0; i < this->lookup_count; i++)
2670 this->accels[i].fini ();
2671 free (this->accels);
Behdad Esfahbod963413f2018-08-26 00:47:55 -07002672 hb_blob_destroy (this->blob);
Behdad Esfahbod963413f2018-08-26 00:47:55 -07002673 }
2674
Behdad Esfahbodb9291002018-08-26 01:15:47 -07002675 hb_blob_t *blob;
2676 const T *table;
2677 unsigned int lookup_count;
2678 hb_ot_layout_lookup_accelerator_t *accels;
Behdad Esfahbod963413f2018-08-26 00:47:55 -07002679 };
2680
Behdad Esfahbod212aba62009-05-24 00:50:27 -04002681 protected:
Behdad Esfahbod9a13ed42016-02-22 11:44:45 +09002682 FixedVersion<>version; /* Version of the GSUB/GPOS table--initially set
Behdad Esfahbod76271002014-07-11 14:54:42 -04002683 * to 0x00010000u */
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04002684 OffsetTo<ScriptList>
2685 scriptList; /* ScriptList table */
2686 OffsetTo<FeatureList>
2687 featureList; /* FeatureList table */
2688 OffsetTo<LookupList>
2689 lookupList; /* LookupList table */
Behdad Esfahbod5e156fa2017-01-22 20:28:56 -08002690 LOffsetTo<FeatureVariations>
Behdad Esfahbod59055b52016-09-10 01:24:28 -07002691 featureVars; /* Offset to Feature Variations
2692 table--from beginning of table
2693 * (may be NULL). Introduced
2694 * in version 0x00010001. */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04002695 public:
Behdad Esfahbod59055b52016-09-10 01:24:28 -07002696 DEFINE_SIZE_MIN (10);
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04002697};
Behdad Esfahbod66bf7ce2009-05-17 08:28:42 -04002698
Behdad Esfahbod6f20f722009-05-17 20:28:01 -04002699
Behdad Esfahbod7d52e662012-11-16 18:49:54 -08002700} /* namespace OT */
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -04002701
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04002702
Behdad Esfahbodc77ae402018-08-25 22:36:36 -07002703#endif /* HB_OT_LAYOUT_GSUBGPOS_HH */