blob: 55edfd4daac20b585e2dfa33f52875d5890a0bd7 [file] [log] [blame]
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -05001/*
Behdad Esfahbod2409d5f2011-04-21 17:14:28 -04002 * Copyright © 2007,2008,2009,2010 Red Hat, Inc.
Behdad Esfahbod2e0c44f2013-04-24 16:42:05 -04003 * Copyright © 2010,2012,2013 Google, Inc.
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -05004 *
Behdad Esfahbodc755cb32010-04-22 00:11:43 -04005 * This is part of HarfBuzz, a text shaping library.
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -05006 *
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 Esfahboda16ecbf2008-01-23 17:01:55 -050027 */
28
Behdad Esfahbod7a750ac2011-08-17 14:19:59 +020029#ifndef HB_OT_LAYOUT_GSUB_TABLE_HH
30#define HB_OT_LAYOUT_GSUB_TABLE_HH
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -050031
Behdad Esfahbodc77ae402018-08-25 22:36:36 -070032#include "hb-ot-layout-gsubgpos.hh"
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -050033
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -040034
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -040035namespace OT {
36
Garret Rieger962f95c2019-05-09 13:04:11 -070037typedef hb_pair_t<hb_codepoint_t, hb_codepoint_t> hb_codepoint_pair_t;
Behdad Esfahbod6f20f722009-05-17 20:28:01 -040038
Behdad Esfahbodd214b072019-05-15 19:07:39 -070039template<typename Iterator>
Behdad Esfahboddd3972a2019-12-10 13:21:26 -060040static void SingleSubst_serialize (hb_serialize_context_t *c,
41 Iterator it);
Garret Rieger962f95c2019-05-09 13:04:11 -070042
Behdad Esfahbod0d160d52018-09-03 20:50:11 -070043
Behdad Esfahbod4c44d832009-05-19 23:42:30 -040044struct SingleSubstFormat1
45{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +033046 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -070047 { return (this+coverage).intersects (glyphs); }
48
Qunxin Liub4fc5932020-12-09 10:44:18 -080049 bool may_have_non_1to1 () const
50 { return false; }
51
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +033052 void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -040053 {
Behdad Esfahbod78d35f02019-05-15 18:15:05 -070054 unsigned d = deltaGlyphID;
Qunxin Liub4fc5932020-12-09 10:44:18 -080055
Behdad Esfahbod896b3162019-03-29 21:16:30 -070056 + hb_iter (this+coverage)
Qunxin Liub8a58a02021-01-10 15:50:04 -080057 | hb_filter (c->parent_active_glyphs ())
Behdad Esfahbod78d35f02019-05-15 18:15:05 -070058 | hb_map ([d] (hb_codepoint_t g) { return (g + d) & 0xFFFFu; })
Behdad Esfahbod896b3162019-03-29 21:16:30 -070059 | hb_sink (c->output)
60 ;
Qunxin Liub4fc5932020-12-09 10:44:18 -080061
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -040062 }
63
Qunxin Liu0b39c482019-10-22 16:00:43 -070064 void closure_lookups (hb_closure_lookups_context_t *c) const {}
65
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +033066 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -080067 {
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -070068 if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
Behdad Esfahbod78d35f02019-05-15 18:15:05 -070069 unsigned d = deltaGlyphID;
Behdad Esfahbod896b3162019-03-29 21:16:30 -070070 + hb_iter (this+coverage)
Behdad Esfahbod78d35f02019-05-15 18:15:05 -070071 | hb_map ([d] (hb_codepoint_t g) { return (g + d) & 0xFFFFu; })
Behdad Esfahbod896b3162019-03-29 21:16:30 -070072 | hb_sink (c->output)
73 ;
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -080074 }
75
Ebrahim Byagowie4120082018-12-17 21:31:01 +033076 const Coverage &get_coverage () const { return this+coverage; }
Behdad Esfahbod0b994292012-07-28 17:31:01 -040077
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +033078 bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -070079 { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
Behdad Esfahbod2005fa52012-11-22 14:38:10 -050080
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +033081 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -040082 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -050083 TRACE_APPLY (this);
Behdad Esfahbod99c26952012-05-13 15:45:18 +020084 hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
Behdad Esfahbodb67881b2012-11-24 19:13:55 -050085 unsigned int index = (this+coverage).get_coverage (glyph_id);
Behdad Esfahbodb4715902015-09-29 14:57:02 +010086 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -040087
Behdad Esfahbod52ebdff2011-09-27 12:38:16 -040088 /* According to the Adobe Annotated OpenType Suite, result is always
89 * limited to 16bit. */
Behdad Esfahbod76271002014-07-11 14:54:42 -040090 glyph_id = (glyph_id + deltaGlyphID) & 0xFFFFu;
Behdad Esfahbod98370e82010-10-27 17:39:01 -040091 c->replace_glyph (glyph_id);
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -040092
Behdad Esfahbodb4715902015-09-29 14:57:02 +010093 return_trace (true);
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -040094 }
95
Garret Rieger962f95c2019-05-09 13:04:11 -070096 template<typename Iterator,
Behdad Esfahbod2dbdec62019-05-31 15:38:11 -070097 hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +033098 bool serialize (hb_serialize_context_t *c,
Garret Rieger962f95c2019-05-09 13:04:11 -070099 Iterator glyphs,
Behdad Esfahbod42526d12019-04-24 10:24:33 -0400100 unsigned delta)
Behdad Esfahbodbc5be242012-09-01 20:48:22 -0400101 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500102 TRACE_SERIALIZE (this);
Behdad Esfahbodf0a18922021-07-28 17:36:22 -0600103 if (unlikely (!c->extend_min (this))) return_trace (false);
Garret Rieger35458b62021-06-11 13:14:51 -0700104 if (unlikely (!coverage.serialize_serialize (c, glyphs))) return_trace (false);
Garret Riegerb14475d2021-03-18 10:51:26 -0700105 c->check_assign (deltaGlyphID, delta, HB_SERIALIZE_ERROR_INT_OVERFLOW);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100106 return_trace (true);
Behdad Esfahbodbc5be242012-09-01 20:48:22 -0400107 }
108
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330109 bool subset (hb_subset_context_t *c) const
Behdad Esfahbod339d3602018-09-03 17:33:34 -0700110 {
111 TRACE_SUBSET (this);
Garret Rieger0af9de12019-05-20 15:04:20 -0700112 const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
Behdad Esfahbod1aea8692018-12-11 22:53:58 -0500113 const hb_map_t &glyph_map = *c->plan->glyph_map;
Behdad Esfahbod4c751582019-03-29 21:46:13 -0700114
Behdad Esfahboddc504932018-09-03 18:23:23 -0700115 hb_codepoint_t delta = deltaGlyphID;
Behdad Esfahbod4c751582019-03-29 21:46:13 -0700116
Garret Rieger962f95c2019-05-09 13:04:11 -0700117 auto it =
Behdad Esfahbod4c751582019-03-29 21:46:13 -0700118 + hb_iter (this+coverage)
119 | hb_filter (glyphset)
Garret Rieger962f95c2019-05-09 13:04:11 -0700120 | hb_map_retains_sorting ([&] (hb_codepoint_t g) {
Behdad Esfahbod38f95ba2019-08-29 13:40:46 -0700121 return hb_codepoint_pair_t (g,
122 (g + delta) & 0xFFFF); })
123 | hb_filter (glyphset, hb_second)
124 | hb_map_retains_sorting ([&] (hb_codepoint_pair_t p) -> hb_codepoint_pair_t
125 { return hb_pair (glyph_map[p.first], glyph_map[p.second]); })
Garret Rieger962f95c2019-05-09 13:04:11 -0700126 ;
Behdad Esfahbod4c751582019-03-29 21:46:13 -0700127
Behdad Esfahbod05bc5f92019-05-16 13:05:58 -0700128 bool ret = bool (it);
Garret Rieger962f95c2019-05-09 13:04:11 -0700129 SingleSubst_serialize (c->serializer, it);
Behdad Esfahbod05bc5f92019-05-16 13:05:58 -0700130 return_trace (ret);
Behdad Esfahbod339d3602018-09-03 17:33:34 -0700131 }
132
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330133 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300134 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500135 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100136 return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400137 }
138
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400139 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100140 HBUINT16 format; /* Format identifier--format = 1 */
Behdad Esfahbodad28f972021-03-31 12:49:14 -0600141 Offset16To<Coverage>
Behdad Esfahbod238c8552009-05-17 00:22:37 -0400142 coverage; /* Offset to Coverage table--from
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400143 * beginning of Substitution table */
Behdad Esfahbod42526d12019-04-24 10:24:33 -0400144 HBUINT16 deltaGlyphID; /* Add to original GlyphID to get
145 * substitute GlyphID, modulo 0x10000 */
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400146 public:
147 DEFINE_SIZE_STATIC (6);
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400148};
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400149
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400150struct SingleSubstFormat2
151{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330152 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700153 { return (this+coverage).intersects (glyphs); }
154
Qunxin Liub4fc5932020-12-09 10:44:18 -0800155 bool may_have_non_1to1 () const
156 { return false; }
157
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330158 void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400159 {
Behdad Esfahbod16cc3132019-02-14 10:40:05 -0800160 + hb_zip (this+coverage, substitute)
Qunxin Liub8a58a02021-01-10 15:50:04 -0800161 | hb_filter (c->parent_active_glyphs (), hb_first)
Behdad Esfahbod16cc3132019-02-14 10:40:05 -0800162 | hb_map (hb_second)
Behdad Esfahbodf8fcfb22019-02-14 11:03:29 -0800163 | hb_sink (c->output)
Behdad Esfahbodbb139cb2019-02-14 10:51:47 -0800164 ;
Qunxin Liub4fc5932020-12-09 10:44:18 -0800165
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400166 }
167
Qunxin Liu0b39c482019-10-22 16:00:43 -0700168 void closure_lookups (hb_closure_lookups_context_t *c) const {}
169
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330170 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800171 {
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -0700172 if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
Behdad Esfahbod16cc3132019-02-14 10:40:05 -0800173 + hb_zip (this+coverage, substitute)
174 | hb_map (hb_second)
Behdad Esfahbodf8fcfb22019-02-14 11:03:29 -0800175 | hb_sink (c->output)
Behdad Esfahbodbb139cb2019-02-14 10:51:47 -0800176 ;
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800177 }
178
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330179 const Coverage &get_coverage () const { return this+coverage; }
Behdad Esfahbod0b994292012-07-28 17:31:01 -0400180
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330181 bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -0700182 { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
Behdad Esfahbod2005fa52012-11-22 14:38:10 -0500183
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330184 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400185 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500186 TRACE_APPLY (this);
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700187 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100188 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400189
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100190 if (unlikely (index >= substitute.len)) return_trace (false);
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400191
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700192 c->replace_glyph (substitute[index]);
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400193
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100194 return_trace (true);
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400195 }
196
Garret Rieger962f95c2019-05-09 13:04:11 -0700197 template<typename Iterator,
Behdad Esfahbodf92d1882019-05-15 18:52:57 -0700198 hb_requires (hb_is_sorted_source_of (Iterator,
Behdad Esfahbod2ad4ba72019-05-31 15:48:54 -0700199 hb_codepoint_pair_t))>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330200 bool serialize (hb_serialize_context_t *c,
Garret Rieger962f95c2019-05-09 13:04:11 -0700201 Iterator it)
Behdad Esfahbodc61be032012-09-01 21:43:38 -0400202 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500203 TRACE_SERIALIZE (this);
Garret Rieger962f95c2019-05-09 13:04:11 -0700204 auto substitutes =
205 + it
206 | hb_map (hb_second)
207 ;
208 auto glyphs =
209 + it
210 | hb_map_retains_sorting (hb_first)
211 ;
Behdad Esfahbodf0a18922021-07-28 17:36:22 -0600212 if (unlikely (!c->extend_min (this))) return_trace (false);
Behdad Esfahbodf1e95e42018-12-18 16:49:08 -0500213 if (unlikely (!substitute.serialize (c, substitutes))) return_trace (false);
Garret Rieger5ba46ed2021-06-11 13:34:00 -0700214 if (unlikely (!coverage.serialize_serialize (c, glyphs))) return_trace (false);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100215 return_trace (true);
Behdad Esfahbodc61be032012-09-01 21:43:38 -0400216 }
217
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330218 bool subset (hb_subset_context_t *c) const
Behdad Esfahbod339d3602018-09-03 17:33:34 -0700219 {
220 TRACE_SUBSET (this);
Garret Rieger0af9de12019-05-20 15:04:20 -0700221 const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
Behdad Esfahbod1aea8692018-12-11 22:53:58 -0500222 const hb_map_t &glyph_map = *c->plan->glyph_map;
Behdad Esfahbod4c751582019-03-29 21:46:13 -0700223
Garret Rieger962f95c2019-05-09 13:04:11 -0700224 auto it =
Behdad Esfahbod4c751582019-03-29 21:46:13 -0700225 + hb_zip (this+coverage, substitute)
226 | hb_filter (glyphset, hb_first)
Behdad Esfahbod38f95ba2019-08-29 13:40:46 -0700227 | hb_filter (glyphset, hb_second)
Behdad Esfahbodc852b862021-09-19 16:30:12 -0400228 | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const HBGlyphID16 &> p) -> hb_codepoint_pair_t
Behdad Esfahbodbcd3ffc2019-05-16 13:22:09 -0700229 { return hb_pair (glyph_map[p.first], glyph_map[p.second]); })
Garret Rieger962f95c2019-05-09 13:04:11 -0700230 ;
Behdad Esfahbod4c751582019-03-29 21:46:13 -0700231
Behdad Esfahbod05bc5f92019-05-16 13:05:58 -0700232 bool ret = bool (it);
Garret Rieger962f95c2019-05-09 13:04:11 -0700233 SingleSubst_serialize (c->serializer, it);
Behdad Esfahbod05bc5f92019-05-16 13:05:58 -0700234 return_trace (ret);
Behdad Esfahbod339d3602018-09-03 17:33:34 -0700235 }
236
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330237 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300238 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500239 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100240 return_trace (coverage.sanitize (c, this) && substitute.sanitize (c));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400241 }
242
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400243 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100244 HBUINT16 format; /* Format identifier--format = 2 */
Behdad Esfahbodad28f972021-03-31 12:49:14 -0600245 Offset16To<Coverage>
Behdad Esfahbod238c8552009-05-17 00:22:37 -0400246 coverage; /* Offset to Coverage table--from
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400247 * beginning of Substitution table */
Behdad Esfahbodc852b862021-09-19 16:30:12 -0400248 Array16Of<HBGlyphID16>
Behdad Esfahbodc9a7cbe2009-05-17 01:22:51 -0400249 substitute; /* Array of substitute
250 * GlyphIDs--ordered by Coverage Index */
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400251 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400252 DEFINE_SIZE_ARRAY (6, substitute);
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400253};
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400254
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400255struct SingleSubst
256{
Garret Rieger962f95c2019-05-09 13:04:11 -0700257
258 template<typename Iterator,
Behdad Esfahbodf92d1882019-05-15 18:52:57 -0700259 hb_requires (hb_is_sorted_source_of (Iterator,
260 const hb_codepoint_pair_t))>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330261 bool serialize (hb_serialize_context_t *c,
Garret Rieger962f95c2019-05-09 13:04:11 -0700262 Iterator glyphs)
Behdad Esfahbodc61be032012-09-01 21:43:38 -0400263 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500264 TRACE_SERIALIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100265 if (unlikely (!c->extend_min (u.format))) return_trace (false);
Behdad Esfahbod00a00bc2019-04-24 10:01:30 -0400266 unsigned format = 2;
267 unsigned delta = 0;
Behdad Esfahbod0a18efd2019-07-26 14:34:26 -0700268 if (glyphs)
Behdad Esfahbodf1e95e42018-12-18 16:49:08 -0500269 {
Behdad Esfahbodc61be032012-09-01 21:43:38 -0400270 format = 1;
Ebrahim Byagowi07504562020-02-21 13:05:44 +0330271 auto get_delta = [=] (hb_codepoint_pair_t _)
272 { return (unsigned) (_.second - _.first) & 0xFFFF; };
Garret Rieger962f95c2019-05-09 13:04:11 -0700273 delta = get_delta (*glyphs);
274 if (!hb_all (++(+glyphs), delta, get_delta)) format = 2;
Behdad Esfahbodc61be032012-09-01 21:43:38 -0400275 }
Behdad Esfahbodb986c6a2019-03-29 20:17:46 -0700276 u.format = format;
Behdad Esfahbodc61be032012-09-01 21:43:38 -0400277 switch (u.format) {
Garret Rieger962f95c2019-05-09 13:04:11 -0700278 case 1: return_trace (u.format1.serialize (c,
Behdad Esfahbodbcd3ffc2019-05-16 13:22:09 -0700279 + glyphs
280 | hb_map_retains_sorting (hb_first),
281 delta));
Garret Rieger962f95c2019-05-09 13:04:11 -0700282 case 2: return_trace (u.format2.serialize (c, glyphs));
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100283 default:return_trace (false);
Behdad Esfahbodc61be032012-09-01 21:43:38 -0400284 }
285 }
286
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -0700287 template <typename context_t, typename ...Ts>
Behdad Esfahbod83e3eab2019-05-07 20:58:43 -0700288 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
Behdad Esfahbodee5464d2013-03-09 01:59:30 -0500289 {
Behdad Esfahbod00f6a8e2014-12-12 20:36:49 -0800290 TRACE_DISPATCH (this, u.format);
Behdad Esfahbodf396fbb2015-10-09 12:25:55 -0400291 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
Behdad Esfahbodee5464d2013-03-09 01:59:30 -0500292 switch (u.format) {
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -0700293 case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
294 case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100295 default:return_trace (c->default_return_value ());
Behdad Esfahbodee5464d2013-03-09 01:59:30 -0500296 }
297 }
298
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400299 protected:
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400300 union {
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100301 HBUINT16 format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -0400302 SingleSubstFormat1 format1;
303 SingleSubstFormat2 format2;
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400304 } u;
305};
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400306
Behdad Esfahbod371b55c2019-05-15 18:54:07 -0700307template<typename Iterator>
Behdad Esfahboddd3972a2019-12-10 13:21:26 -0600308static void
Behdad Esfahbod0d160d52018-09-03 20:50:11 -0700309SingleSubst_serialize (hb_serialize_context_t *c,
Garret Rieger962f95c2019-05-09 13:04:11 -0700310 Iterator it)
311{ c->start_embed<SingleSubst> ()->serialize (c, it); }
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400312
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400313struct Sequence
314{
Behdad Esfahbod23681b62019-08-28 15:30:37 -0700315 bool intersects (const hb_set_t *glyphs) const
316 { return hb_all (substitute, glyphs); }
317
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330318 void closure (hb_closure_context_t *c) const
Behdad Esfahbod23681b62019-08-28 15:30:37 -0700319 { c->output->add_array (substitute.arrayZ, substitute.len); }
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400320
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330321 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbod89bcfb22019-01-18 14:59:18 -0500322 { c->output->add_array (substitute.arrayZ, substitute.len); }
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800323
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330324 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400325 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500326 TRACE_APPLY (this);
Behdad Esfahbodaae69452014-06-05 18:54:44 -0400327 unsigned int count = substitute.len;
Behdad Esfahbodb6b304f2014-06-05 17:12:54 -0400328
Behdad Esfahbodaae69452014-06-05 18:54:44 -0400329 /* Special-case to make it in-place and not consider this
330 * as a "multiplied" substitution. */
331 if (unlikely (count == 1))
332 {
Behdad Esfahbod63f57f42018-05-08 16:56:11 -0700333 c->replace_glyph (substitute.arrayZ[0]);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100334 return_trace (true);
Behdad Esfahbodaae69452014-06-05 18:54:44 -0400335 }
Behdad Esfahbod359dead2016-05-06 16:19:19 +0100336 /* Spec disallows this, but Uniscribe allows it.
ebraminio7c6937e2017-11-20 14:49:22 -0500337 * https://github.com/harfbuzz/harfbuzz/issues/253 */
Behdad Esfahbod359dead2016-05-06 16:19:19 +0100338 else if (unlikely (count == 0))
339 {
340 c->buffer->delete_glyph ();
341 return_trace (true);
342 }
Behdad Esfahbodc9c6a782009-05-05 16:22:02 -0400343
Behdad Esfahbod101303d2013-10-18 00:42:39 +0200344 unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ?
Behdad Esfahbod03058c32013-10-17 20:55:34 +0200345 HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
Behdad Esfahbod6fe0d7d2021-07-28 12:06:49 -0600346 unsigned lig_id = _hb_glyph_info_get_lig_id (&c->buffer->cur());
Behdad Esfahbodaae69452014-06-05 18:54:44 -0400347
Behdad Esfahbod6fe0d7d2021-07-28 12:06:49 -0600348 for (unsigned int i = 0; i < count; i++)
349 {
350 /* If is attached to a ligature, don't disturb that.
351 * https://github.com/harfbuzz/harfbuzz/issues/3069 */
352 if (!lig_id)
353 _hb_glyph_info_set_lig_props_for_component (&c->buffer->cur(), i);
Behdad Esfahbod63f57f42018-05-08 16:56:11 -0700354 c->output_glyph_for_component (substitute.arrayZ[i], klass);
Behdad Esfahbodec57e0c2012-06-08 21:47:23 -0400355 }
Behdad Esfahbodaae69452014-06-05 18:54:44 -0400356 c->buffer->skip_glyph ();
Behdad Esfahbodc9c6a782009-05-05 16:22:02 -0400357
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100358 return_trace (true);
Behdad Esfahbodc9c6a782009-05-05 16:22:02 -0400359 }
360
Behdad Esfahbod2dbdec62019-05-31 15:38:11 -0700361 template <typename Iterator,
362 hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330363 bool serialize (hb_serialize_context_t *c,
Behdad Esfahbod2dbdec62019-05-31 15:38:11 -0700364 Iterator subst)
Behdad Esfahbod1f07e332012-09-03 23:28:34 -0400365 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500366 TRACE_SERIALIZE (this);
Behdad Esfahbod815cde92019-01-07 18:33:04 -0500367 return_trace (substitute.serialize (c, subst));
Behdad Esfahbod1f07e332012-09-03 23:28:34 -0400368 }
369
Behdad Esfahbod33c8e232019-08-28 15:25:55 -0700370 bool subset (hb_subset_context_t *c) const
371 {
372 TRACE_SUBSET (this);
Garret Riegere5835052020-09-29 11:05:08 -0700373 const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
Behdad Esfahbod33c8e232019-08-28 15:25:55 -0700374 const hb_map_t &glyph_map = *c->plan->glyph_map;
375
Behdad Esfahbod23681b62019-08-28 15:30:37 -0700376 if (!intersects (&glyphset)) return_trace (false);
Behdad Esfahbod33c8e232019-08-28 15:25:55 -0700377
378 auto it =
Ebrahim Byagowi07504562020-02-21 13:05:44 +0330379 + hb_iter (substitute)
380 | hb_map (glyph_map)
381 ;
Behdad Esfahbod33c8e232019-08-28 15:25:55 -0700382
383 auto *out = c->serializer->start_embed (*this);
Behdad Esfahboddc9222b2019-08-28 15:38:46 -0700384 return_trace (out->serialize (c->serializer, it));
Behdad Esfahbod33c8e232019-08-28 15:25:55 -0700385 }
386
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330387 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300388 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500389 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100390 return_trace (substitute.sanitize (c));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400391 }
392
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400393 protected:
Behdad Esfahbodc852b862021-09-19 16:30:12 -0400394 Array16Of<HBGlyphID16>
Behdad Esfahbodc9a7cbe2009-05-17 01:22:51 -0400395 substitute; /* String of GlyphIDs to substitute */
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400396 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400397 DEFINE_SIZE_ARRAY (2, substitute);
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400398};
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400399
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400400struct MultipleSubstFormat1
401{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330402 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700403 { return (this+coverage).intersects (glyphs); }
404
Qunxin Liub4fc5932020-12-09 10:44:18 -0800405 bool may_have_non_1to1 () const
406 { return true; }
407
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330408 void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400409 {
Behdad Esfahbod7514a492019-02-14 13:16:33 -0800410 + hb_zip (this+coverage, sequence)
Qunxin Liub8a58a02021-01-10 15:50:04 -0800411 | hb_filter (c->parent_active_glyphs (), hb_first)
Behdad Esfahbod7514a492019-02-14 13:16:33 -0800412 | hb_map (hb_second)
Behdad Esfahbod23768672019-05-15 21:57:26 -0700413 | hb_map (hb_add (this))
414 | hb_apply ([c] (const Sequence &_) { _.closure (c); })
Behdad Esfahbod7514a492019-02-14 13:16:33 -0800415 ;
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400416 }
417
Qunxin Liu0b39c482019-10-22 16:00:43 -0700418 void closure_lookups (hb_closure_lookups_context_t *c) const {}
419
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330420 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800421 {
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -0700422 if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
Behdad Esfahbod7514a492019-02-14 13:16:33 -0800423 + hb_zip (this+coverage, sequence)
424 | hb_map (hb_second)
Behdad Esfahbod23768672019-05-15 21:57:26 -0700425 | hb_map (hb_add (this))
426 | hb_apply ([c] (const Sequence &_) { _.collect_glyphs (c); })
Behdad Esfahbod7514a492019-02-14 13:16:33 -0800427 ;
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800428 }
429
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330430 const Coverage &get_coverage () const { return this+coverage; }
Behdad Esfahbod0b994292012-07-28 17:31:01 -0400431
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330432 bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -0700433 { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
Behdad Esfahbod2005fa52012-11-22 14:38:10 -0500434
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330435 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400436 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500437 TRACE_APPLY (this);
Behdad Esfahbod30bd7632009-04-15 22:56:15 -0400438
Behdad Esfahbodb67881b2012-11-24 19:13:55 -0500439 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100440 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -0400441
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100442 return_trace ((this+sequence[index]).apply (c));
Behdad Esfahbod2d15e722009-04-15 19:50:16 -0400443 }
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500444
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330445 bool serialize (hb_serialize_context_t *c,
Behdad Esfahbodc852b862021-09-19 16:30:12 -0400446 hb_sorted_array_t<const HBGlyphID16> glyphs,
Behdad Esfahbodf1e95e42018-12-18 16:49:08 -0500447 hb_array_t<const unsigned int> substitute_len_list,
Behdad Esfahbodc852b862021-09-19 16:30:12 -0400448 hb_array_t<const HBGlyphID16> substitute_glyphs_list)
Behdad Esfahbod1f07e332012-09-03 23:28:34 -0400449 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500450 TRACE_SERIALIZE (this);
Behdad Esfahbodf0a18922021-07-28 17:36:22 -0600451 if (unlikely (!c->extend_min (this))) return_trace (false);
Behdad Esfahbod474a1202018-12-21 18:46:51 -0500452 if (unlikely (!sequence.serialize (c, glyphs.length))) return_trace (false);
453 for (unsigned int i = 0; i < glyphs.length; i++)
Behdad Esfahbodf1e95e42018-12-18 16:49:08 -0500454 {
455 unsigned int substitute_len = substitute_len_list[i];
Garret Rieger5ba46ed2021-06-11 13:34:00 -0700456 if (unlikely (!sequence[i]
457 .serialize_serialize (c, substitute_glyphs_list.sub_array (0, substitute_len))))
Behdad Esfahbodf1e95e42018-12-18 16:49:08 -0500458 return_trace (false);
459 substitute_glyphs_list += substitute_len;
460 }
Garret Rieger5ba46ed2021-06-11 13:34:00 -0700461 return_trace (coverage.serialize_serialize (c, glyphs));
Behdad Esfahbod1f07e332012-09-03 23:28:34 -0400462 }
463
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330464 bool subset (hb_subset_context_t *c) const
Behdad Esfahbod339d3602018-09-03 17:33:34 -0700465 {
466 TRACE_SUBSET (this);
Garret Riegere5835052020-09-29 11:05:08 -0700467 const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
Behdad Esfahbod33c8e232019-08-28 15:25:55 -0700468 const hb_map_t &glyph_map = *c->plan->glyph_map;
469
470 auto *out = c->serializer->start_embed (*this);
471 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
472 out->format = format;
473
474 hb_sorted_vector_t<hb_codepoint_t> new_coverage;
475 + hb_zip (this+coverage, sequence)
476 | hb_filter (glyphset, hb_first)
ariza188a0a42020-03-07 11:02:36 -0800477 | hb_filter (subset_offset_array (c, out->sequence, this), hb_second)
Behdad Esfahbod33c8e232019-08-28 15:25:55 -0700478 | hb_map (hb_first)
479 | hb_map (glyph_map)
Ebrahim Byagowi49902962019-08-29 15:09:39 +0430480 | hb_sink (new_coverage)
Behdad Esfahbod33c8e232019-08-28 15:25:55 -0700481 ;
Garret Rieger5ba46ed2021-06-11 13:34:00 -0700482 out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
Behdad Esfahbod33c8e232019-08-28 15:25:55 -0700483 return_trace (bool (new_coverage));
Behdad Esfahbod339d3602018-09-03 17:33:34 -0700484 }
485
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330486 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300487 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500488 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100489 return_trace (coverage.sanitize (c, this) && sequence.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400490 }
491
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400492 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100493 HBUINT16 format; /* Format identifier--format = 1 */
Behdad Esfahbodad28f972021-03-31 12:49:14 -0600494 Offset16To<Coverage>
Behdad Esfahbod238c8552009-05-17 00:22:37 -0400495 coverage; /* Offset to Coverage table--from
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500496 * beginning of Substitution table */
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -0600497 Array16OfOffset16To<Sequence>
Behdad Esfahbodc9a7cbe2009-05-17 01:22:51 -0400498 sequence; /* Array of Sequence tables
499 * ordered by Coverage Index */
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400500 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400501 DEFINE_SIZE_ARRAY (6, sequence);
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500502};
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500503
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400504struct MultipleSubst
505{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330506 bool serialize (hb_serialize_context_t *c,
Behdad Esfahbodc852b862021-09-19 16:30:12 -0400507 hb_sorted_array_t<const HBGlyphID16> glyphs,
Behdad Esfahbodf1e95e42018-12-18 16:49:08 -0500508 hb_array_t<const unsigned int> substitute_len_list,
Behdad Esfahbodc852b862021-09-19 16:30:12 -0400509 hb_array_t<const HBGlyphID16> substitute_glyphs_list)
Behdad Esfahbod1f07e332012-09-03 23:28:34 -0400510 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500511 TRACE_SERIALIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100512 if (unlikely (!c->extend_min (u.format))) return_trace (false);
Behdad Esfahbod1f07e332012-09-03 23:28:34 -0400513 unsigned int format = 1;
Behdad Esfahbodb986c6a2019-03-29 20:17:46 -0700514 u.format = format;
Behdad Esfahbod1f07e332012-09-03 23:28:34 -0400515 switch (u.format) {
Behdad Esfahbodf1e95e42018-12-18 16:49:08 -0500516 case 1: return_trace (u.format1.serialize (c, glyphs, substitute_len_list, substitute_glyphs_list));
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100517 default:return_trace (false);
Behdad Esfahbod1f07e332012-09-03 23:28:34 -0400518 }
519 }
520
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -0700521 template <typename context_t, typename ...Ts>
Behdad Esfahbod83e3eab2019-05-07 20:58:43 -0700522 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
Behdad Esfahbodee5464d2013-03-09 01:59:30 -0500523 {
Behdad Esfahbod00f6a8e2014-12-12 20:36:49 -0800524 TRACE_DISPATCH (this, u.format);
Behdad Esfahbodf396fbb2015-10-09 12:25:55 -0400525 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
Behdad Esfahbodee5464d2013-03-09 01:59:30 -0500526 switch (u.format) {
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -0700527 case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100528 default:return_trace (c->default_return_value ());
Behdad Esfahbodee5464d2013-03-09 01:59:30 -0500529 }
530 }
531
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400532 protected:
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400533 union {
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100534 HBUINT16 format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -0400535 MultipleSubstFormat1 format1;
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400536 } u;
537};
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400538
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700539struct AlternateSet
540{
Behdad Esfahboddc9222b2019-08-28 15:38:46 -0700541 bool intersects (const hb_set_t *glyphs) const
542 { return hb_any (alternates, glyphs); }
543
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330544 void closure (hb_closure_context_t *c) const
Behdad Esfahbod23681b62019-08-28 15:30:37 -0700545 { c->output->add_array (alternates.arrayZ, alternates.len); }
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400546
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330547 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbod89bcfb22019-01-18 14:59:18 -0500548 { c->output->add_array (alternates.arrayZ, alternates.len); }
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700549
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330550 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700551 {
552 TRACE_APPLY (this);
553 unsigned int count = alternates.len;
554
555 if (unlikely (!count)) return_trace (false);
556
Behdad Esfahbodcc1c4fd2018-09-10 16:36:05 +0200557 hb_mask_t glyph_mask = c->buffer->cur().mask;
558 hb_mask_t lookup_mask = c->lookup_mask;
559
560 /* Note: This breaks badly if two features enabled this lookup together. */
561 unsigned int shift = hb_ctz (lookup_mask);
562 unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
563
Behdad Esfahbod41248cc2019-05-07 20:54:31 -0700564 /* If alt_index is MAX_VALUE, randomize feature if it is the rand feature. */
Behdad Esfahbod71c9f842018-09-10 22:37:19 +0200565 if (alt_index == HB_OT_MAP_MAX_VALUE && c->random)
Behdad Esfahbod40884af2021-07-09 17:17:05 -0600566 {
567 /* Maybe we can do better than unsafe-to-break all; but since we are
568 * changing random state, it would be hard to track that. Good 'nough. */
569 c->buffer->unsafe_to_break_all ();
Behdad Esfahbod08260c72018-09-11 10:51:19 +0200570 alt_index = c->random_number () % count + 1;
Behdad Esfahbod40884af2021-07-09 17:17:05 -0600571 }
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700572
Behdad Esfahbod71c9f842018-09-10 22:37:19 +0200573 if (unlikely (alt_index > count || alt_index == 0)) return_trace (false);
574
Behdad Esfahbodcc1c4fd2018-09-10 16:36:05 +0200575 c->replace_glyph (alternates[alt_index - 1]);
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700576
577 return_trace (true);
578 }
579
Ebrahim Byagowid3c16972020-06-18 08:37:21 +0430580 unsigned
Behdad Esfahbodbedf4172020-06-18 15:49:01 -0700581 get_alternates (unsigned start_offset,
582 unsigned *alternate_count /* IN/OUT. May be NULL. */,
583 hb_codepoint_t *alternate_glyphs /* OUT. May be NULL. */) const
Ebrahim Byagowid3c16972020-06-18 08:37:21 +0430584 {
Behdad Esfahbodbedf4172020-06-18 15:49:01 -0700585 if (alternates.len && alternate_count)
Ebrahim Byagowid3c16972020-06-18 08:37:21 +0430586 {
587 + alternates.sub_array (start_offset, alternate_count)
588 | hb_sink (hb_array (alternate_glyphs, *alternate_count))
589 ;
590 }
591 return alternates.len;
592 }
593
Behdad Esfahbod2dbdec62019-05-31 15:38:11 -0700594 template <typename Iterator,
595 hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330596 bool serialize (hb_serialize_context_t *c,
Behdad Esfahbod2dbdec62019-05-31 15:38:11 -0700597 Iterator alts)
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700598 {
599 TRACE_SERIALIZE (this);
Behdad Esfahbod815cde92019-01-07 18:33:04 -0500600 return_trace (alternates.serialize (c, alts));
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700601 }
602
Behdad Esfahboddc9222b2019-08-28 15:38:46 -0700603 bool subset (hb_subset_context_t *c) const
604 {
605 TRACE_SUBSET (this);
Garret Riegere5835052020-09-29 11:05:08 -0700606 const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
Behdad Esfahboddc9222b2019-08-28 15:38:46 -0700607 const hb_map_t &glyph_map = *c->plan->glyph_map;
608
609 auto it =
610 + hb_iter (alternates)
611 | hb_filter (glyphset)
612 | hb_map (glyph_map)
613 ;
614
615 auto *out = c->serializer->start_embed (*this);
616 return_trace (out->serialize (c->serializer, it) &&
617 out->alternates);
618 }
619
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330620 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700621 {
622 TRACE_SANITIZE (this);
623 return_trace (alternates.sanitize (c));
624 }
625
626 protected:
Behdad Esfahbodc852b862021-09-19 16:30:12 -0400627 Array16Of<HBGlyphID16>
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700628 alternates; /* Array of alternate GlyphIDs--in
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400629 * arbitrary order */
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700630 public:
631 DEFINE_SIZE_ARRAY (2, alternates);
632};
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500633
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400634struct AlternateSubstFormat1
635{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330636 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700637 { return (this+coverage).intersects (glyphs); }
638
Qunxin Liub4fc5932020-12-09 10:44:18 -0800639 bool may_have_non_1to1 () const
640 { return false; }
641
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330642 void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400643 {
Behdad Esfahbod7514a492019-02-14 13:16:33 -0800644 + hb_zip (this+coverage, alternateSet)
Qunxin Liub8a58a02021-01-10 15:50:04 -0800645 | hb_filter (c->parent_active_glyphs (), hb_first)
Behdad Esfahbod7514a492019-02-14 13:16:33 -0800646 | hb_map (hb_second)
Behdad Esfahbod23768672019-05-15 21:57:26 -0700647 | hb_map (hb_add (this))
648 | hb_apply ([c] (const AlternateSet &_) { _.closure (c); })
Behdad Esfahbod7514a492019-02-14 13:16:33 -0800649 ;
Qunxin Liub4fc5932020-12-09 10:44:18 -0800650
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400651 }
652
Qunxin Liu0b39c482019-10-22 16:00:43 -0700653 void closure_lookups (hb_closure_lookups_context_t *c) const {}
654
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330655 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800656 {
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -0700657 if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
Behdad Esfahbod7514a492019-02-14 13:16:33 -0800658 + hb_zip (this+coverage, alternateSet)
659 | hb_map (hb_second)
Behdad Esfahbod23768672019-05-15 21:57:26 -0700660 | hb_map (hb_add (this))
661 | hb_apply ([c] (const AlternateSet &_) { _.collect_glyphs (c); })
Behdad Esfahbod7514a492019-02-14 13:16:33 -0800662 ;
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800663 }
664
Ebrahim Byagowie4120082018-12-17 21:31:01 +0330665 const Coverage &get_coverage () const { return this+coverage; }
Behdad Esfahbod0b994292012-07-28 17:31:01 -0400666
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330667 bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -0700668 { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
Behdad Esfahbod2005fa52012-11-22 14:38:10 -0500669
Ebrahim Byagowid3c16972020-06-18 08:37:21 +0430670 unsigned
Behdad Esfahbodb2a1acc2020-06-18 16:41:31 -0700671 get_glyph_alternates (hb_codepoint_t gid,
672 unsigned start_offset,
673 unsigned *alternate_count /* IN/OUT. May be NULL. */,
674 hb_codepoint_t *alternate_glyphs /* OUT. May be NULL. */) const
675 { return (this+alternateSet[(this+coverage).get_coverage (gid)])
676 .get_alternates (start_offset, alternate_count, alternate_glyphs); }
Ebrahim Byagowi1348a2c2020-06-16 21:05:16 -0400677
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330678 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400679 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500680 TRACE_APPLY (this);
Behdad Esfahbod52886ca2009-04-16 14:19:42 -0400681
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700682 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100683 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -0400684
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700685 return_trace ((this+alternateSet[index]).apply (c));
Behdad Esfahbod52886ca2009-04-16 14:19:42 -0400686 }
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500687
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330688 bool serialize (hb_serialize_context_t *c,
Behdad Esfahbodc852b862021-09-19 16:30:12 -0400689 hb_sorted_array_t<const HBGlyphID16> glyphs,
Behdad Esfahbodf1e95e42018-12-18 16:49:08 -0500690 hb_array_t<const unsigned int> alternate_len_list,
Behdad Esfahbodc852b862021-09-19 16:30:12 -0400691 hb_array_t<const HBGlyphID16> alternate_glyphs_list)
Behdad Esfahbod29416832012-09-03 23:31:14 -0400692 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500693 TRACE_SERIALIZE (this);
Behdad Esfahbodf0a18922021-07-28 17:36:22 -0600694 if (unlikely (!c->extend_min (this))) return_trace (false);
Behdad Esfahbod474a1202018-12-21 18:46:51 -0500695 if (unlikely (!alternateSet.serialize (c, glyphs.length))) return_trace (false);
696 for (unsigned int i = 0; i < glyphs.length; i++)
Behdad Esfahbodf1e95e42018-12-18 16:49:08 -0500697 {
698 unsigned int alternate_len = alternate_len_list[i];
Garret Rieger5ba46ed2021-06-11 13:34:00 -0700699 if (unlikely (!alternateSet[i]
700 .serialize_serialize (c, alternate_glyphs_list.sub_array (0, alternate_len))))
Behdad Esfahbodf1e95e42018-12-18 16:49:08 -0500701 return_trace (false);
702 alternate_glyphs_list += alternate_len;
703 }
Garret Rieger5ba46ed2021-06-11 13:34:00 -0700704 return_trace (coverage.serialize_serialize (c, glyphs));
Behdad Esfahbod29416832012-09-03 23:31:14 -0400705 }
706
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330707 bool subset (hb_subset_context_t *c) const
Behdad Esfahbod339d3602018-09-03 17:33:34 -0700708 {
709 TRACE_SUBSET (this);
Garret Riegere5835052020-09-29 11:05:08 -0700710 const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
Behdad Esfahboddc9222b2019-08-28 15:38:46 -0700711 const hb_map_t &glyph_map = *c->plan->glyph_map;
712
713 auto *out = c->serializer->start_embed (*this);
714 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
715 out->format = format;
716
717 hb_sorted_vector_t<hb_codepoint_t> new_coverage;
718 + hb_zip (this+coverage, alternateSet)
719 | hb_filter (glyphset, hb_first)
ariza188a0a42020-03-07 11:02:36 -0800720 | hb_filter (subset_offset_array (c, out->alternateSet, this), hb_second)
Behdad Esfahboddc9222b2019-08-28 15:38:46 -0700721 | hb_map (hb_first)
722 | hb_map (glyph_map)
Ebrahim Byagowi49902962019-08-29 15:09:39 +0430723 | hb_sink (new_coverage)
Behdad Esfahboddc9222b2019-08-28 15:38:46 -0700724 ;
Garret Rieger5ba46ed2021-06-11 13:34:00 -0700725 out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
Behdad Esfahboddc9222b2019-08-28 15:38:46 -0700726 return_trace (bool (new_coverage));
Behdad Esfahbod339d3602018-09-03 17:33:34 -0700727 }
728
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330729 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300730 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500731 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100732 return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400733 }
734
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400735 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100736 HBUINT16 format; /* Format identifier--format = 1 */
Behdad Esfahbodad28f972021-03-31 12:49:14 -0600737 Offset16To<Coverage>
Behdad Esfahbod238c8552009-05-17 00:22:37 -0400738 coverage; /* Offset to Coverage table--from
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500739 * beginning of Substitution table */
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -0600740 Array16OfOffset16To<AlternateSet>
Behdad Esfahbodc9a7cbe2009-05-17 01:22:51 -0400741 alternateSet; /* Array of AlternateSet tables
742 * ordered by Coverage Index */
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400743 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400744 DEFINE_SIZE_ARRAY (6, alternateSet);
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500745};
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500746
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400747struct AlternateSubst
748{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330749 bool serialize (hb_serialize_context_t *c,
Behdad Esfahbodc852b862021-09-19 16:30:12 -0400750 hb_sorted_array_t<const HBGlyphID16> glyphs,
Behdad Esfahbodf1e95e42018-12-18 16:49:08 -0500751 hb_array_t<const unsigned int> alternate_len_list,
Behdad Esfahbodc852b862021-09-19 16:30:12 -0400752 hb_array_t<const HBGlyphID16> alternate_glyphs_list)
Behdad Esfahbod29416832012-09-03 23:31:14 -0400753 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500754 TRACE_SERIALIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100755 if (unlikely (!c->extend_min (u.format))) return_trace (false);
Behdad Esfahbod29416832012-09-03 23:31:14 -0400756 unsigned int format = 1;
Behdad Esfahbodb986c6a2019-03-29 20:17:46 -0700757 u.format = format;
Behdad Esfahbod29416832012-09-03 23:31:14 -0400758 switch (u.format) {
Behdad Esfahbodf1e95e42018-12-18 16:49:08 -0500759 case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, alternate_glyphs_list));
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100760 default:return_trace (false);
Behdad Esfahbod29416832012-09-03 23:31:14 -0400761 }
762 }
763
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -0700764 template <typename context_t, typename ...Ts>
Behdad Esfahbod83e3eab2019-05-07 20:58:43 -0700765 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
Behdad Esfahbodee5464d2013-03-09 01:59:30 -0500766 {
Behdad Esfahbod00f6a8e2014-12-12 20:36:49 -0800767 TRACE_DISPATCH (this, u.format);
Behdad Esfahbodf396fbb2015-10-09 12:25:55 -0400768 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
Behdad Esfahbodee5464d2013-03-09 01:59:30 -0500769 switch (u.format) {
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -0700770 case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100771 default:return_trace (c->default_return_value ());
Behdad Esfahbodee5464d2013-03-09 01:59:30 -0500772 }
773 }
774
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400775 protected:
Behdad Esfahbod52886ca2009-04-16 14:19:42 -0400776 union {
Behdad Esfahbod6b191782018-01-10 03:07:30 +0100777 HBUINT16 format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -0400778 AlternateSubstFormat1 format1;
Behdad Esfahbod52886ca2009-04-16 14:19:42 -0400779 } u;
780};
Behdad Esfahbod52886ca2009-04-16 14:19:42 -0400781
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400782
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400783struct Ligature
784{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330785 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod23681b62019-08-28 15:30:37 -0700786 { return hb_all (component, glyphs); }
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700787
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330788 void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400789 {
Behdad Esfahbod418e9d02019-03-29 21:57:26 -0700790 if (!intersects (c->glyphs)) return;
Behdad Esfahbodede1a712019-01-09 10:45:53 -0800791 c->output->add (ligGlyph);
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400792 }
793
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330794 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800795 {
Behdad Esfahbodb8c642c2019-08-28 15:06:45 -0700796 c->input->add_array (component.arrayZ, component.get_length ());
Behdad Esfahbod83035932012-12-04 17:08:41 -0500797 c->output->add (ligGlyph);
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800798 }
799
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330800 bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbod36608942012-04-19 22:21:38 -0400801 {
Behdad Esfahbodeffc7ce2018-09-13 20:21:54 +0200802 if (c->len != component.lenP1)
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -0700803 return false;
Behdad Esfahbod472f2292012-08-07 22:25:24 -0400804
805 for (unsigned int i = 1; i < c->len; i++)
806 if (likely (c->glyphs[i] != component[i]))
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -0700807 return false;
Behdad Esfahbod472f2292012-08-07 22:25:24 -0400808
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -0700809 return true;
Behdad Esfahbod36608942012-04-19 22:21:38 -0400810 }
811
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330812 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400813 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500814 TRACE_APPLY (this);
Behdad Esfahbodeffc7ce2018-09-13 20:21:54 +0200815 unsigned int count = component.lenP1;
Behdad Esfahbodaae69452014-06-05 18:54:44 -0400816
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100817 if (unlikely (!count)) return_trace (false);
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500818
Behdad Esfahbodb5be2312014-06-05 19:00:22 -0400819 /* Special-case to make it in-place and not consider this
820 * as a "ligated" substitution. */
821 if (unlikely (count == 1))
822 {
823 c->replace_glyph (ligGlyph);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100824 return_trace (true);
Behdad Esfahbodb5be2312014-06-05 19:00:22 -0400825 }
826
Behdad Esfahbodc779d822012-11-23 14:07:24 -0500827 unsigned int total_component_count = 0;
Behdad Esfahbodbb3899a2009-05-05 13:25:13 -0400828
Behdad Esfahbode714fe62013-10-17 13:49:51 +0200829 unsigned int match_length = 0;
Behdad Esfahbod5ba45042015-11-02 15:43:08 -0800830 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
Behdad Esfahbode714fe62013-10-17 13:49:51 +0200831
Behdad Esfahbod191fa882012-08-28 22:58:55 -0400832 if (likely (!match_input (c, count,
833 &component[1],
834 match_glyph,
Behdad Esfahboddbdbfe32017-10-15 12:11:08 +0200835 nullptr,
Behdad Esfahbode714fe62013-10-17 13:49:51 +0200836 &match_length,
837 match_positions,
Behdad Esfahbod191fa882012-08-28 22:58:55 -0400838 &total_component_count)))
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100839 return_trace (false);
Behdad Esfahbod98370e82010-10-27 17:39:01 -0400840
Behdad Esfahboda177d022012-08-28 23:18:22 -0400841 ligate_input (c,
842 count,
Behdad Esfahbode714fe62013-10-17 13:49:51 +0200843 match_positions,
844 match_length,
Behdad Esfahbod607feb72013-02-14 07:43:13 -0500845 ligGlyph,
Behdad Esfahboda177d022012-08-28 23:18:22 -0400846 total_component_count);
Behdad Esfahbodbb3899a2009-05-05 13:25:13 -0400847
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100848 return_trace (true);
Behdad Esfahbodbb3899a2009-05-05 13:25:13 -0400849 }
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500850
Behdad Esfahbod2dbdec62019-05-31 15:38:11 -0700851 template <typename Iterator,
852 hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330853 bool serialize (hb_serialize_context_t *c,
Behdad Esfahbodbc5ef762019-08-28 14:51:28 -0700854 hb_codepoint_t ligature,
Behdad Esfahbod2dbdec62019-05-31 15:38:11 -0700855 Iterator components /* Starting from second */)
Behdad Esfahboda930c682012-09-04 18:17:57 -0400856 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500857 TRACE_SERIALIZE (this);
Behdad Esfahbodf0a18922021-07-28 17:36:22 -0600858 if (unlikely (!c->extend_min (this))) return_trace (false);
Behdad Esfahbodfabd3112012-09-05 22:19:28 -0400859 ligGlyph = ligature;
Behdad Esfahbodf1e95e42018-12-18 16:49:08 -0500860 if (unlikely (!component.serialize (c, components))) return_trace (false);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100861 return_trace (true);
Behdad Esfahboda930c682012-09-04 18:17:57 -0400862 }
863
Behdad Esfahbodbc5ef762019-08-28 14:51:28 -0700864 bool subset (hb_subset_context_t *c) const
865 {
866 TRACE_SUBSET (this);
Garret Riegere5835052020-09-29 11:05:08 -0700867 const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
Behdad Esfahbodbc5ef762019-08-28 14:51:28 -0700868 const hb_map_t &glyph_map = *c->plan->glyph_map;
869
Behdad Esfahbod23681b62019-08-28 15:30:37 -0700870 if (!intersects (&glyphset) || !glyphset.has (ligGlyph)) return_trace (false);
Behdad Esfahbodbc5ef762019-08-28 14:51:28 -0700871
872 auto it =
873 + hb_iter (component)
874 | hb_map (glyph_map)
875 ;
876
877 auto *out = c->serializer->start_embed (*this);
Behdad Esfahboddc9222b2019-08-28 15:38:46 -0700878 return_trace (out->serialize (c->serializer,
Ebrahim Byagowid0e2add2020-07-18 22:14:52 +0430879 glyph_map[ligGlyph],
880 it));
Behdad Esfahbodbc5ef762019-08-28 14:51:28 -0700881 }
882
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400883 public:
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330884 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300885 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500886 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100887 return_trace (ligGlyph.sanitize (c) && component.sanitize (c));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400888 }
889
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400890 protected:
Behdad Esfahbodc852b862021-09-19 16:30:12 -0400891 HBGlyphID16 ligGlyph; /* GlyphID of ligature to substitute */
892 HeadlessArrayOf<HBGlyphID16>
Behdad Esfahbode8cbaaf2009-05-18 02:03:58 -0400893 component; /* Array of component GlyphIDs--start
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400894 * with the second component--ordered
895 * in writing direction */
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400896 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400897 DEFINE_SIZE_ARRAY (4, component);
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500898};
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400899
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400900struct LigatureSet
901{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330902 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700903 {
Behdad Esfahbod4d282672019-03-29 22:04:15 -0700904 return
905 + hb_iter (ligature)
Behdad Esfahbod23768672019-05-15 21:57:26 -0700906 | hb_map (hb_add (this))
907 | hb_map ([glyphs] (const Ligature &_) { return _.intersects (glyphs); })
Behdad Esfahbod4d282672019-03-29 22:04:15 -0700908 | hb_any
909 ;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -0700910 }
911
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330912 void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400913 {
Behdad Esfahbod4d282672019-03-29 22:04:15 -0700914 + hb_iter (ligature)
Behdad Esfahbod23768672019-05-15 21:57:26 -0700915 | hb_map (hb_add (this))
916 | hb_apply ([c] (const Ligature &_) { _.closure (c); })
Behdad Esfahbod4d282672019-03-29 22:04:15 -0700917 ;
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400918 }
919
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330920 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800921 {
Behdad Esfahbod4d282672019-03-29 22:04:15 -0700922 + hb_iter (ligature)
Behdad Esfahbod23768672019-05-15 21:57:26 -0700923 | hb_map (hb_add (this))
924 | hb_apply ([c] (const Ligature &_) { _.collect_glyphs (c); })
Behdad Esfahbod4d282672019-03-29 22:04:15 -0700925 ;
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -0800926 }
927
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330928 bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbod36608942012-04-19 22:21:38 -0400929 {
Behdad Esfahbod688069b2019-03-29 22:17:31 -0700930 return
931 + hb_iter (ligature)
Behdad Esfahbod23768672019-05-15 21:57:26 -0700932 | hb_map (hb_add (this))
933 | hb_map ([c] (const Ligature &_) { return _.would_apply (c); })
Behdad Esfahbod688069b2019-03-29 22:17:31 -0700934 | hb_any
935 ;
Behdad Esfahbod36608942012-04-19 22:21:38 -0400936 }
937
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330938 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400939 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500940 TRACE_APPLY (this);
Behdad Esfahbodc9a7cbe2009-05-17 01:22:51 -0400941 unsigned int num_ligs = ligature.len;
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400942 for (unsigned int i = 0; i < num_ligs; i++)
943 {
Behdad Esfahbodc9a7cbe2009-05-17 01:22:51 -0400944 const Ligature &lig = this+ligature[i];
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100945 if (lig.apply (c)) return_trace (true);
Behdad Esfahbodbb3899a2009-05-05 13:25:13 -0400946 }
947
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100948 return_trace (false);
Behdad Esfahbodbb3899a2009-05-05 13:25:13 -0400949 }
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400950
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330951 bool serialize (hb_serialize_context_t *c,
Behdad Esfahbodc852b862021-09-19 16:30:12 -0400952 hb_array_t<const HBGlyphID16> ligatures,
Behdad Esfahbodf1e95e42018-12-18 16:49:08 -0500953 hb_array_t<const unsigned int> component_count_list,
Behdad Esfahbodc852b862021-09-19 16:30:12 -0400954 hb_array_t<const HBGlyphID16> &component_list /* Starting from second for each ligature */)
Behdad Esfahboda930c682012-09-04 18:17:57 -0400955 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500956 TRACE_SERIALIZE (this);
Behdad Esfahbodf0a18922021-07-28 17:36:22 -0600957 if (unlikely (!c->extend_min (this))) return_trace (false);
Behdad Esfahbod474a1202018-12-21 18:46:51 -0500958 if (unlikely (!ligature.serialize (c, ligatures.length))) return_trace (false);
959 for (unsigned int i = 0; i < ligatures.length; i++)
Behdad Esfahbodf1e95e42018-12-18 16:49:08 -0500960 {
Behdad Esfahbod41248cc2019-05-07 20:54:31 -0700961 unsigned int component_count = (unsigned) hb_max ((int) component_count_list[i] - 1, 0);
Garret Rieger5ba46ed2021-06-11 13:34:00 -0700962 if (unlikely (!ligature[i].serialize_serialize (c,
963 ligatures[i],
964 component_list.sub_array (0, component_count))))
Behdad Esfahbodf1e95e42018-12-18 16:49:08 -0500965 return_trace (false);
966 component_list += component_count;
967 }
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100968 return_trace (true);
Behdad Esfahboda930c682012-09-04 18:17:57 -0400969 }
970
Behdad Esfahbodbc5ef762019-08-28 14:51:28 -0700971 bool subset (hb_subset_context_t *c) const
972 {
973 TRACE_SUBSET (this);
974 auto *out = c->serializer->start_embed (*this);
975 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
976
977 + hb_iter (ligature)
ariza188a0a42020-03-07 11:02:36 -0800978 | hb_filter (subset_offset_array (c, out->ligature, this))
Ebrahim Byagowi49902962019-08-29 15:09:39 +0430979 | hb_drain
Behdad Esfahbodbc5ef762019-08-28 14:51:28 -0700980 ;
981 return_trace (bool (out->ligature));
982 }
983
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +0330984 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +0300985 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -0500986 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +0100987 return_trace (ligature.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400988 }
989
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400990 protected:
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -0600991 Array16OfOffset16To<Ligature>
Behdad Esfahbodc9a7cbe2009-05-17 01:22:51 -0400992 ligature; /* Array LigatureSet tables
993 * ordered by preference */
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400994 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400995 DEFINE_SIZE_ARRAY (2, ligature);
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400996};
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500997
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400998struct LigatureSubstFormat1
999{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301000 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001001 {
Behdad Esfahbodbcab0982019-03-29 21:49:18 -07001002 return
1003 + hb_zip (this+coverage, ligatureSet)
1004 | hb_filter (*glyphs, hb_first)
1005 | hb_map (hb_second)
Behdad Esfahbodad28f972021-03-31 12:49:14 -06001006 | hb_map ([this, glyphs] (const Offset16To<LigatureSet> &_)
Behdad Esfahbodbcab0982019-03-29 21:49:18 -07001007 { return (this+_).intersects (glyphs); })
1008 | hb_any
1009 ;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001010 }
1011
Qunxin Liub4fc5932020-12-09 10:44:18 -08001012 bool may_have_non_1to1 () const
1013 { return true; }
1014
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301015 void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001016 {
Behdad Esfahbodf4cfd6b2019-02-14 13:45:52 -08001017 + hb_zip (this+coverage, ligatureSet)
Qunxin Liub8a58a02021-01-10 15:50:04 -08001018 | hb_filter (c->parent_active_glyphs (), hb_first)
Behdad Esfahbodf4cfd6b2019-02-14 13:45:52 -08001019 | hb_map (hb_second)
Behdad Esfahbod23768672019-05-15 21:57:26 -07001020 | hb_map (hb_add (this))
1021 | hb_apply ([c] (const LigatureSet &_) { _.closure (c); })
Behdad Esfahbodf4cfd6b2019-02-14 13:45:52 -08001022 ;
Qunxin Liub4fc5932020-12-09 10:44:18 -08001023
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001024 }
1025
Qunxin Liu0b39c482019-10-22 16:00:43 -07001026 void closure_lookups (hb_closure_lookups_context_t *c) const {}
1027
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301028 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -08001029 {
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07001030 if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
Behdad Esfahbodf1dad912019-03-29 21:17:08 -07001031
Behdad Esfahbodf4cfd6b2019-02-14 13:45:52 -08001032 + hb_zip (this+coverage, ligatureSet)
1033 | hb_map (hb_second)
Behdad Esfahbod23768672019-05-15 21:57:26 -07001034 | hb_map (hb_add (this))
1035 | hb_apply ([c] (const LigatureSet &_) { _.collect_glyphs (c); })
Behdad Esfahbodf4cfd6b2019-02-14 13:45:52 -08001036 ;
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -08001037 }
1038
Ebrahim Byagowie4120082018-12-17 21:31:01 +03301039 const Coverage &get_coverage () const { return this+coverage; }
Behdad Esfahbod0b994292012-07-28 17:31:01 -04001040
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301041 bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbod36608942012-04-19 22:21:38 -04001042 {
Behdad Esfahbodb67881b2012-11-24 19:13:55 -05001043 unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07001044 if (likely (index == NOT_COVERED)) return false;
Behdad Esfahbod2005fa52012-11-22 14:38:10 -05001045
1046 const LigatureSet &lig_set = this+ligatureSet[index];
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07001047 return lig_set.would_apply (c);
Behdad Esfahbod36608942012-04-19 22:21:38 -04001048 }
1049
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301050 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001051 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001052 TRACE_APPLY (this);
Behdad Esfahboda84e71a2009-04-16 16:53:40 -04001053
Ebrahim Byagowi07504562020-02-21 13:05:44 +03301054 unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001055 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -04001056
Behdad Esfahbodc9a7cbe2009-05-17 01:22:51 -04001057 const LigatureSet &lig_set = this+ligatureSet[index];
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001058 return_trace (lig_set.apply (c));
Behdad Esfahboda84e71a2009-04-16 16:53:40 -04001059 }
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -05001060
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301061 bool serialize (hb_serialize_context_t *c,
Behdad Esfahbodc852b862021-09-19 16:30:12 -04001062 hb_sorted_array_t<const HBGlyphID16> first_glyphs,
Behdad Esfahbodf1e95e42018-12-18 16:49:08 -05001063 hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
Behdad Esfahbodc852b862021-09-19 16:30:12 -04001064 hb_array_t<const HBGlyphID16> ligatures_list,
Behdad Esfahbodf1e95e42018-12-18 16:49:08 -05001065 hb_array_t<const unsigned int> component_count_list,
Behdad Esfahbodc852b862021-09-19 16:30:12 -04001066 hb_array_t<const HBGlyphID16> component_list /* Starting from second for each ligature */)
Behdad Esfahboda930c682012-09-04 18:17:57 -04001067 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001068 TRACE_SERIALIZE (this);
Behdad Esfahbodf0a18922021-07-28 17:36:22 -06001069 if (unlikely (!c->extend_min (this))) return_trace (false);
Behdad Esfahbod474a1202018-12-21 18:46:51 -05001070 if (unlikely (!ligatureSet.serialize (c, first_glyphs.length))) return_trace (false);
1071 for (unsigned int i = 0; i < first_glyphs.length; i++)
Behdad Esfahbodf1e95e42018-12-18 16:49:08 -05001072 {
1073 unsigned int ligature_count = ligature_per_first_glyph_count_list[i];
Garret Rieger5ba46ed2021-06-11 13:34:00 -07001074 if (unlikely (!ligatureSet[i]
1075 .serialize_serialize (c,
1076 ligatures_list.sub_array (0, ligature_count),
1077 component_count_list.sub_array (0, ligature_count),
1078 component_list))) return_trace (false);
Behdad Esfahbodf1e95e42018-12-18 16:49:08 -05001079 ligatures_list += ligature_count;
1080 component_count_list += ligature_count;
Behdad Esfahbodf1e95e42018-12-18 16:49:08 -05001081 }
Garret Rieger5ba46ed2021-06-11 13:34:00 -07001082 return_trace (coverage.serialize_serialize (c, first_glyphs));
Behdad Esfahboda930c682012-09-04 18:17:57 -04001083 }
1084
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301085 bool subset (hb_subset_context_t *c) const
Behdad Esfahbod339d3602018-09-03 17:33:34 -07001086 {
1087 TRACE_SUBSET (this);
Garret Riegere5835052020-09-29 11:05:08 -07001088 const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
Behdad Esfahbodbc5ef762019-08-28 14:51:28 -07001089 const hb_map_t &glyph_map = *c->plan->glyph_map;
1090
1091 auto *out = c->serializer->start_embed (*this);
1092 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
1093 out->format = format;
1094
1095 hb_sorted_vector_t<hb_codepoint_t> new_coverage;
1096 + hb_zip (this+coverage, ligatureSet)
1097 | hb_filter (glyphset, hb_first)
ariza188a0a42020-03-07 11:02:36 -08001098 | hb_filter (subset_offset_array (c, out->ligatureSet, this), hb_second)
Behdad Esfahbodbc5ef762019-08-28 14:51:28 -07001099 | hb_map (hb_first)
1100 | hb_map (glyph_map)
Ebrahim Byagowi49902962019-08-29 15:09:39 +04301101 | hb_sink (new_coverage)
Behdad Esfahbodbc5ef762019-08-28 14:51:28 -07001102 ;
Garret Rieger5ba46ed2021-06-11 13:34:00 -07001103 out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
Behdad Esfahbodbc5ef762019-08-28 14:51:28 -07001104 return_trace (bool (new_coverage));
Behdad Esfahbod339d3602018-09-03 17:33:34 -07001105 }
1106
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301107 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001108 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001109 TRACE_SANITIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001110 return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001111 }
1112
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001113 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001114 HBUINT16 format; /* Format identifier--format = 1 */
Behdad Esfahbodad28f972021-03-31 12:49:14 -06001115 Offset16To<Coverage>
Behdad Esfahbod238c8552009-05-17 00:22:37 -04001116 coverage; /* Offset to Coverage table--from
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -05001117 * beginning of Substitution table */
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06001118 Array16OfOffset16To<LigatureSet>
Behdad Esfahbodc9a7cbe2009-05-17 01:22:51 -04001119 ligatureSet; /* Array LigatureSet tables
1120 * ordered by Coverage Index */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04001121 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -04001122 DEFINE_SIZE_ARRAY (6, ligatureSet);
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -05001123};
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -05001124
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001125struct LigatureSubst
1126{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301127 bool serialize (hb_serialize_context_t *c,
Behdad Esfahbodc852b862021-09-19 16:30:12 -04001128 hb_sorted_array_t<const HBGlyphID16> first_glyphs,
Behdad Esfahbodf1e95e42018-12-18 16:49:08 -05001129 hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
Behdad Esfahbodc852b862021-09-19 16:30:12 -04001130 hb_array_t<const HBGlyphID16> ligatures_list,
Behdad Esfahbodf1e95e42018-12-18 16:49:08 -05001131 hb_array_t<const unsigned int> component_count_list,
Behdad Esfahbodc852b862021-09-19 16:30:12 -04001132 hb_array_t<const HBGlyphID16> component_list /* Starting from second for each ligature */)
Behdad Esfahboda930c682012-09-04 18:17:57 -04001133 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001134 TRACE_SERIALIZE (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001135 if (unlikely (!c->extend_min (u.format))) return_trace (false);
Behdad Esfahboda930c682012-09-04 18:17:57 -04001136 unsigned int format = 1;
Behdad Esfahbodb986c6a2019-03-29 20:17:46 -07001137 u.format = format;
Behdad Esfahboda930c682012-09-04 18:17:57 -04001138 switch (u.format) {
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001139 case 1: return_trace (u.format1.serialize (c,
1140 first_glyphs,
1141 ligature_per_first_glyph_count_list,
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001142 ligatures_list,
1143 component_count_list,
1144 component_list));
1145 default:return_trace (false);
Behdad Esfahboda930c682012-09-04 18:17:57 -04001146 }
1147 }
1148
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -07001149 template <typename context_t, typename ...Ts>
Behdad Esfahbod83e3eab2019-05-07 20:58:43 -07001150 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
Behdad Esfahbodee5464d2013-03-09 01:59:30 -05001151 {
Behdad Esfahbod00f6a8e2014-12-12 20:36:49 -08001152 TRACE_DISPATCH (this, u.format);
Behdad Esfahbodf396fbb2015-10-09 12:25:55 -04001153 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
Behdad Esfahbodee5464d2013-03-09 01:59:30 -05001154 switch (u.format) {
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -07001155 case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001156 default:return_trace (c->default_return_value ());
Behdad Esfahbodee5464d2013-03-09 01:59:30 -05001157 }
1158 }
1159
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001160 protected:
Behdad Esfahboda84e71a2009-04-16 16:53:40 -04001161 union {
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001162 HBUINT16 format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -04001163 LigatureSubstFormat1 format1;
Behdad Esfahboda84e71a2009-04-16 16:53:40 -04001164 } u;
1165};
Behdad Esfahboda84e71a2009-04-16 16:53:40 -04001166
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -05001167
Behdad Esfahbod08f1eed2012-11-23 16:51:43 -05001168struct ContextSubst : Context {};
Behdad Esfahbodcdb317b2009-05-06 00:12:29 -04001169
Behdad Esfahbod08f1eed2012-11-23 16:51:43 -05001170struct ChainContextSubst : ChainContext {};
Behdad Esfahbod4f27ce72009-04-16 13:40:13 -04001171
Behdad Esfahbod653eeb22012-11-23 16:57:36 -05001172struct ExtensionSubst : Extension<ExtensionSubst>
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001173{
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07001174 typedef struct SubstLookupSubTable SubTable;
Ebrahim Byagowie4120082018-12-17 21:31:01 +03301175 bool is_reverse () const;
Behdad Esfahbod4f27ce72009-04-16 13:40:13 -04001176};
Behdad Esfahbod4f27ce72009-04-16 13:40:13 -04001177
1178
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001179struct ReverseChainSingleSubstFormat1
1180{
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301181 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001182 {
1183 if (!(this+coverage).intersects (glyphs))
1184 return false;
1185
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06001186 const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001187
1188 unsigned int count;
1189
1190 count = backtrack.len;
1191 for (unsigned int i = 0; i < count; i++)
1192 if (!(this+backtrack[i]).intersects (glyphs))
Behdad Esfahbodbcd3ffc2019-05-16 13:22:09 -07001193 return false;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001194
1195 count = lookahead.len;
1196 for (unsigned int i = 0; i < count; i++)
1197 if (!(this+lookahead[i]).intersects (glyphs))
Behdad Esfahbodbcd3ffc2019-05-16 13:22:09 -07001198 return false;
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001199
1200 return true;
1201 }
1202
Qunxin Liub4fc5932020-12-09 10:44:18 -08001203 bool may_have_non_1to1 () const
1204 { return false; }
1205
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301206 void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001207 {
Behdad Esfahbod418e9d02019-03-29 21:57:26 -07001208 if (!intersects (c->glyphs)) return;
1209
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06001210 const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
Behdad Esfahbodc852b862021-09-19 16:30:12 -04001211 const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead);
Behdad Esfahbodf1dad912019-03-29 21:17:08 -07001212
Behdad Esfahbod16cc3132019-02-14 10:40:05 -08001213 + hb_zip (this+coverage, substitute)
Qunxin Liub8a58a02021-01-10 15:50:04 -08001214 | hb_filter (c->parent_active_glyphs (), hb_first)
Behdad Esfahbod16cc3132019-02-14 10:40:05 -08001215 | hb_map (hb_second)
Behdad Esfahbodf8fcfb22019-02-14 11:03:29 -08001216 | hb_sink (c->output)
Behdad Esfahbodbb139cb2019-02-14 10:51:47 -08001217 ;
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001218 }
1219
Qunxin Liu0b39c482019-10-22 16:00:43 -07001220 void closure_lookups (hb_closure_lookups_context_t *c) const {}
1221
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301222 void collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -08001223 {
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07001224 if (unlikely (!(this+coverage).collect_coverage (c->input))) return;
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -08001225
1226 unsigned int count;
1227
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -08001228 count = backtrack.len;
1229 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07001230 if (unlikely (!(this+backtrack[i]).collect_coverage (c->before))) return;
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -08001231
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06001232 const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -08001233 count = lookahead.len;
1234 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07001235 if (unlikely (!(this+lookahead[i]).collect_coverage (c->after))) return;
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -08001236
Behdad Esfahbodc852b862021-09-19 16:30:12 -04001237 const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead);
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -08001238 count = substitute.len;
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07001239 c->output->add_array (substitute.arrayZ, substitute.len);
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -08001240 }
1241
Ebrahim Byagowie4120082018-12-17 21:31:01 +03301242 const Coverage &get_coverage () const { return this+coverage; }
Behdad Esfahbod0b994292012-07-28 17:31:01 -04001243
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301244 bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07001245 { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
Behdad Esfahbod2005fa52012-11-22 14:38:10 -05001246
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301247 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001248 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001249 TRACE_APPLY (this);
Behdad Esfahbod5ba45042015-11-02 15:43:08 -08001250 if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001251 return_trace (false); /* No chaining to this type */
Behdad Esfahbod969afd72009-05-18 05:47:47 -04001252
Ebrahim Byagowi07504562020-02-21 13:05:44 +03301253 unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001254 if (likely (index == NOT_COVERED)) return_trace (false);
Behdad Esfahbod969afd72009-05-18 05:47:47 -04001255
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06001256 const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
Behdad Esfahbodc852b862021-09-19 16:30:12 -04001257 const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead);
Behdad Esfahbod969afd72009-05-18 05:47:47 -04001258
Behdad Esfahbod41ef75f2020-06-17 16:29:09 -07001259 if (unlikely (index >= substitute.len)) return_trace (false);
1260
1261 unsigned int start_index = 0, end_index = 0;
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001262 if (match_backtrack (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07001263 backtrack.len, (HBUINT16 *) backtrack.arrayZ,
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001264 match_coverage, this,
1265 &start_index) &&
Behdad Esfahbodbcd3ffc2019-05-16 13:22:09 -07001266 match_lookahead (c,
Behdad Esfahbod63f57f42018-05-08 16:56:11 -07001267 lookahead.len, (HBUINT16 *) lookahead.arrayZ,
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04001268 match_coverage, this,
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001269 1, &end_index))
Behdad Esfahbod969afd72009-05-18 05:47:47 -04001270 {
Behdad Esfahbod40bd7e92016-05-02 14:47:45 +02001271 c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index);
Behdad Esfahbod7fbbf862012-07-30 18:36:42 -04001272 c->replace_glyph_inplace (substitute[index]);
Behdad Esfahbod49901862013-10-17 19:48:51 +02001273 /* Note: We DON'T decrease buffer->idx. The main loop does it
1274 * for us. This is useful for preventing surprises if someone
1275 * calls us through a Context lookup. */
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001276 return_trace (true);
Behdad Esfahbod969afd72009-05-18 05:47:47 -04001277 }
1278
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001279 return_trace (false);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001280 }
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -05001281
Qunxin Liu95230e22021-03-18 17:41:25 -07001282 template<typename Iterator,
1283 hb_requires (hb_is_iterator (Iterator))>
1284 bool serialize_coverage_offset_array (hb_subset_context_t *c, Iterator it) const
1285 {
1286 TRACE_SERIALIZE (this);
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06001287 auto *out = c->serializer->start_embed<Array16OfOffset16To<Coverage>> ();
Qunxin Liu95230e22021-03-18 17:41:25 -07001288
1289 if (unlikely (!c->serializer->allocate_size<HBUINT16> (HBUINT16::static_size)))
1290 return_trace (false);
1291
1292 for (auto& offset : it) {
1293 auto *o = out->serialize_append (c->serializer);
1294 if (unlikely (!o) || !o->serialize_subset (c, offset, this))
1295 return_trace (false);
1296 }
1297
1298 return_trace (true);
1299 }
1300
1301 template<typename Iterator, typename BacktrackIterator, typename LookaheadIterator,
1302 hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_pair_t)),
1303 hb_requires (hb_is_iterator (BacktrackIterator)),
1304 hb_requires (hb_is_iterator (LookaheadIterator))>
1305 bool serialize (hb_subset_context_t *c,
1306 Iterator coverage_subst_iter,
1307 BacktrackIterator backtrack_iter,
1308 LookaheadIterator lookahead_iter) const
1309 {
1310 TRACE_SERIALIZE (this);
1311
1312 auto *out = c->serializer->start_embed (this);
1313 if (unlikely (!c->serializer->check_success (out))) return_trace (false);
1314 if (unlikely (!c->serializer->embed (this->format))) return_trace (false);
1315 if (unlikely (!c->serializer->embed (this->coverage))) return_trace (false);
1316
1317 if (!serialize_coverage_offset_array (c, backtrack_iter)) return_trace (false);
1318 if (!serialize_coverage_offset_array (c, lookahead_iter)) return_trace (false);
1319
Behdad Esfahbodc852b862021-09-19 16:30:12 -04001320 auto *substitute_out = c->serializer->start_embed<Array16Of<HBGlyphID16>> ();
Qunxin Liu95230e22021-03-18 17:41:25 -07001321 auto substitutes =
1322 + coverage_subst_iter
1323 | hb_map (hb_second)
1324 ;
1325
1326 auto glyphs =
1327 + coverage_subst_iter
1328 | hb_map_retains_sorting (hb_first)
1329 ;
1330 if (unlikely (! c->serializer->check_success (substitute_out->serialize (c->serializer, substitutes))))
1331 return_trace (false);
1332
Garret Rieger5ba46ed2021-06-11 13:34:00 -07001333 if (unlikely (!out->coverage.serialize_serialize (c->serializer, glyphs)))
Qunxin Liu95230e22021-03-18 17:41:25 -07001334 return_trace (false);
1335 return_trace (true);
1336 }
1337
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301338 bool subset (hb_subset_context_t *c) const
Behdad Esfahbod339d3602018-09-03 17:33:34 -07001339 {
1340 TRACE_SUBSET (this);
Qunxin Liu95230e22021-03-18 17:41:25 -07001341 const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
1342 const hb_map_t &glyph_map = *c->plan->glyph_map;
1343
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06001344 const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
Behdad Esfahbodc852b862021-09-19 16:30:12 -04001345 const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead);
Qunxin Liu95230e22021-03-18 17:41:25 -07001346
1347 auto it =
1348 + hb_zip (this+coverage, substitute)
1349 | hb_filter (glyphset, hb_first)
1350 | hb_filter (glyphset, hb_second)
Behdad Esfahbodc852b862021-09-19 16:30:12 -04001351 | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const HBGlyphID16 &> p) -> hb_codepoint_pair_t
Qunxin Liu95230e22021-03-18 17:41:25 -07001352 { return hb_pair (glyph_map[p.first], glyph_map[p.second]); })
1353 ;
1354
1355 return_trace (bool (it) && serialize (c, it, backtrack.iter (), lookahead.iter ()));
Behdad Esfahbod339d3602018-09-03 17:33:34 -07001356 }
1357
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301358 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbodde2118e2015-02-17 17:27:44 +03001359 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001360 TRACE_SANITIZE (this);
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02001361 if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001362 return_trace (false);
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06001363 const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001364 if (!lookahead.sanitize (c, this))
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001365 return_trace (false);
Behdad Esfahbodc852b862021-09-19 16:30:12 -04001366 const Array16Of<HBGlyphID16> &substitute = StructAfter<Array16Of<HBGlyphID16>> (lookahead);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001367 return_trace (substitute.sanitize (c));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001368 }
1369
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001370 protected:
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001371 HBUINT16 format; /* Format identifier--format = 1 */
Behdad Esfahbodad28f972021-03-31 12:49:14 -06001372 Offset16To<Coverage>
Behdad Esfahbod969afd72009-05-18 05:47:47 -04001373 coverage; /* Offset to Coverage table--from
1374 * beginning of table */
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06001375 Array16OfOffset16To<Coverage>
Behdad Esfahbod969afd72009-05-18 05:47:47 -04001376 backtrack; /* Array of coverage tables
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001377 * in backtracking sequence, in glyph
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -05001378 * sequence order */
Behdad Esfahbod6c4e0492021-03-31 15:31:32 -06001379 Array16OfOffset16To<Coverage>
Behdad Esfahbod969afd72009-05-18 05:47:47 -04001380 lookaheadX; /* Array of coverage tables
1381 * in lookahead sequence, in glyph
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -05001382 * sequence order */
Behdad Esfahbodc852b862021-09-19 16:30:12 -04001383 Array16Of<HBGlyphID16>
Behdad Esfahbod969afd72009-05-18 05:47:47 -04001384 substituteX; /* Array of substitute
1385 * GlyphIDs--ordered by Coverage Index */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04001386 public:
Behdad Esfahbodbea34c72010-05-10 17:28:16 -04001387 DEFINE_SIZE_MIN (10);
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -05001388};
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -05001389
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001390struct ReverseChainSingleSubst
1391{
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -07001392 template <typename context_t, typename ...Ts>
Behdad Esfahbod83e3eab2019-05-07 20:58:43 -07001393 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -08001394 {
Behdad Esfahbod00f6a8e2014-12-12 20:36:49 -08001395 TRACE_DISPATCH (this, u.format);
Behdad Esfahbodf396fbb2015-10-09 12:25:55 -04001396 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -08001397 switch (u.format) {
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -07001398 case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001399 default:return_trace (c->default_return_value ());
Behdad Esfahbod0b994292012-07-28 17:31:01 -04001400 }
1401 }
1402
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001403 protected:
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001404 union {
Behdad Esfahbod6b191782018-01-10 03:07:30 +01001405 HBUINT16 format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -04001406 ReverseChainSingleSubstFormat1 format1;
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001407 } u;
1408};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001409
1410
1411
Behdad Esfahbod75860892008-01-23 18:02:28 -05001412/*
Behdad Esfahbod2d15e722009-04-15 19:50:16 -04001413 * SubstLookup
1414 */
1415
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001416struct SubstLookupSubTable
1417{
Behdad Esfahbod7b2ef552018-09-03 17:16:09 -07001418 friend struct Lookup;
Behdad Esfahbod2d15e722009-04-15 19:50:16 -04001419 friend struct SubstLookup;
1420
Behdad Esfahbodc6035cf2012-04-12 13:23:59 -04001421 enum Type {
Behdad Esfahbodff05d252009-05-20 03:53:00 -04001422 Single = 1,
1423 Multiple = 2,
1424 Alternate = 3,
1425 Ligature = 4,
1426 Context = 5,
1427 ChainContext = 6,
1428 Extension = 7,
Behdad Esfahbod8f034d52009-08-18 16:41:59 -04001429 ReverseChainSingle = 8
Behdad Esfahbodff05d252009-05-20 03:53:00 -04001430 };
1431
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -07001432 template <typename context_t, typename ...Ts>
Behdad Esfahbod83e3eab2019-05-07 20:58:43 -07001433 typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type, Ts&&... ds) const
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -08001434 {
Behdad Esfahbod00f6a8e2014-12-12 20:36:49 -08001435 TRACE_DISPATCH (this, lookup_type);
Behdad Esfahbode8cfdd72012-11-16 19:07:06 -08001436 switch (lookup_type) {
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -07001437 case Single: return_trace (u.single.dispatch (c, hb_forward<Ts> (ds)...));
1438 case Multiple: return_trace (u.multiple.dispatch (c, hb_forward<Ts> (ds)...));
1439 case Alternate: return_trace (u.alternate.dispatch (c, hb_forward<Ts> (ds)...));
1440 case Ligature: return_trace (u.ligature.dispatch (c, hb_forward<Ts> (ds)...));
1441 case Context: return_trace (u.context.dispatch (c, hb_forward<Ts> (ds)...));
1442 case ChainContext: return_trace (u.chainContext.dispatch (c, hb_forward<Ts> (ds)...));
1443 case Extension: return_trace (u.extension.dispatch (c, hb_forward<Ts> (ds)...));
1444 case ReverseChainSingle: return_trace (u.reverseChainContextSingle.dispatch (c, hb_forward<Ts> (ds)...));
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001445 default: return_trace (c->default_return_value ());
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001446 }
1447 }
1448
ariza72cbfb92020-01-18 16:35:52 -08001449 bool intersects (const hb_set_t *glyphs, unsigned int lookup_type) const
1450 {
1451 hb_intersects_context_t c (glyphs);
1452 return dispatch (&c, lookup_type);
1453 }
1454
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001455 protected:
Behdad Esfahbod2d15e722009-04-15 19:50:16 -04001456 union {
Behdad Esfahboddacebca2010-05-10 19:45:41 -04001457 SingleSubst single;
1458 MultipleSubst multiple;
1459 AlternateSubst alternate;
1460 LigatureSubst ligature;
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001461 ContextSubst context;
Behdad Esfahboddacebca2010-05-10 19:45:41 -04001462 ChainContextSubst chainContext;
1463 ExtensionSubst extension;
1464 ReverseChainSingleSubst reverseChainContextSingle;
Behdad Esfahbod2d15e722009-04-15 19:50:16 -04001465 } u;
Behdad Esfahboded074222010-05-10 18:08:46 -04001466 public:
Behdad Esfahbod2cc993e2018-12-12 10:07:38 -05001467 DEFINE_SIZE_MIN (0);
Behdad Esfahbod2d15e722009-04-15 19:50:16 -04001468};
1469
Behdad Esfahbod4f27ce72009-04-16 13:40:13 -04001470
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001471struct SubstLookup : Lookup
1472{
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07001473 typedef SubstLookupSubTable SubTable;
1474
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301475 const SubTable& get_subtable (unsigned int i) const
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07001476 { return Lookup::get_subtable<SubTable> (i); }
Behdad Esfahbod2d15e722009-04-15 19:50:16 -04001477
Behdad Esfahboda061e472019-12-10 13:31:50 -06001478 static inline bool lookup_type_is_reverse (unsigned int lookup_type)
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07001479 { return lookup_type == SubTable::ReverseChainSingle; }
Behdad Esfahbod2d15e722009-04-15 19:50:16 -04001480
Ebrahim Byagowie4120082018-12-17 21:31:01 +03301481 bool is_reverse () const
Behdad Esfahboda065f472010-04-22 20:15:11 -04001482 {
1483 unsigned int type = get_type ();
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07001484 if (unlikely (type == SubTable::Extension))
Ebrahim Byagowi07504562020-02-21 13:05:44 +03301485 return reinterpret_cast<const ExtensionSubst &> (get_subtable (0)).is_reverse ();
Behdad Esfahboda065f472010-04-22 20:15:11 -04001486 return lookup_type_is_reverse (type);
1487 }
1488
Qunxin Liub4fc5932020-12-09 10:44:18 -08001489 bool may_have_non_1to1 () const
1490 {
1491 hb_have_non_1to1_context_t c;
1492 return dispatch (&c);
1493 }
1494
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301495 bool apply (hb_ot_apply_context_t *c) const
Behdad Esfahbodbd047d32015-02-19 10:47:18 +03001496 {
1497 TRACE_APPLY (this);
Behdad Esfahbodb4715902015-09-29 14:57:02 +01001498 return_trace (dispatch (c));
Behdad Esfahbodbd047d32015-02-19 10:47:18 +03001499 }
1500
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301501 bool intersects (const hb_set_t *glyphs) const
Behdad Esfahbod7c9cfa22018-09-02 19:47:50 -07001502 {
1503 hb_intersects_context_t c (glyphs);
1504 return dispatch (&c);
1505 }
1506
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301507 hb_closure_context_t::return_t closure (hb_closure_context_t *c, unsigned int this_index) const
Behdad Esfahbod9b346772012-11-23 17:55:40 -05001508 {
Behdad Esfahbodba0ea562018-06-11 23:24:41 -04001509 if (!c->should_visit_lookup (this_index))
Behdad Esfahbod0772c062019-01-18 12:53:06 -05001510 return hb_closure_context_t::default_return_value ();
Garret Rieger45186b92018-06-05 17:14:42 -07001511
1512 c->set_recurse_func (dispatch_closure_recurse_func);
Behdad Esfahbodc38bd402018-07-24 09:43:27 -07001513
1514 hb_closure_context_t::return_t ret = dispatch (c);
1515
1516 c->flush ();
1517
Behdad Esfahbod0772c062019-01-18 12:53:06 -05001518 return ret;
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001519 }
1520
Qunxin Liu0b39c482019-10-22 16:00:43 -07001521 hb_closure_lookups_context_t::return_t closure_lookups (hb_closure_lookups_context_t *c, unsigned this_index) const
1522 {
1523 if (c->is_lookup_visited (this_index))
1524 return hb_closure_lookups_context_t::default_return_value ();
1525
1526 c->set_lookup_visited (this_index);
1527 if (!intersects (c->glyphs))
1528 {
1529 c->set_lookup_inactive (this_index);
1530 return hb_closure_lookups_context_t::default_return_value ();
1531 }
1532
1533 c->set_recurse_func (dispatch_closure_lookups_recurse_func);
1534
1535 hb_closure_lookups_context_t::return_t ret = dispatch (c);
1536 return ret;
1537 }
1538
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301539 hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
Behdad Esfahbod26514d52012-11-23 18:13:48 -05001540 {
Behdad Esfahbod9c5a9ee2013-03-09 01:55:04 -05001541 c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
Behdad Esfahbod89bcfb22019-01-18 14:59:18 -05001542 return dispatch (c);
Behdad Esfahbod9b346772012-11-23 17:55:40 -05001543 }
1544
Behdad Esfahboda878c582012-08-01 21:18:54 -04001545 template <typename set_t>
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07001546 void collect_coverage (set_t *glyphs) const
Behdad Esfahboda878c582012-08-01 21:18:54 -04001547 {
Behdad Esfahbod5cf53c02020-04-23 10:55:41 -07001548 hb_collect_coverage_context_t<set_t> c (glyphs);
Behdad Esfahbod8e36ccf2015-02-17 19:15:34 +03001549 dispatch (&c);
Behdad Esfahboda878c582012-08-01 21:18:54 -04001550 }
1551
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301552 bool would_apply (hb_would_apply_context_t *c,
1553 const hb_ot_layout_lookup_accelerator_t *accel) const
Behdad Esfahbod36608942012-04-19 22:21:38 -04001554 {
Behdad Esfahbod90b60bd2019-03-29 22:12:42 -07001555 if (unlikely (!c->len)) return false;
1556 if (!accel->may_have (c->glyphs[0])) return false;
1557 return dispatch (c);
Behdad Esfahbod36608942012-04-19 22:21:38 -04001558 }
1559
Behdad Esfahboda061e472019-12-10 13:31:50 -06001560 static inline bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index);
Behdad Esfahbod29d86442009-08-04 02:27:37 -04001561
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301562 bool serialize_single (hb_serialize_context_t *c,
1563 uint32_t lookup_props,
Behdad Esfahbodc852b862021-09-19 16:30:12 -04001564 hb_sorted_array_t<const HBGlyphID16> glyphs,
1565 hb_array_t<const HBGlyphID16> substitutes)
Behdad Esfahbodb3b89b62012-09-04 21:13:17 -04001566 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001567 TRACE_SERIALIZE (this);
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07001568 if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false);
Garret Riegercc96c4e2021-06-14 16:43:23 -07001569 if (c->push<SubTable> ()->u.single.serialize (c, hb_zip (glyphs, substitutes)))
1570 {
1571 c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
1572 return_trace (true);
1573 }
1574 c->pop_discard ();
1575 return_trace (false);
Behdad Esfahbodb3b89b62012-09-04 21:13:17 -04001576 }
1577
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301578 bool serialize_multiple (hb_serialize_context_t *c,
1579 uint32_t lookup_props,
Behdad Esfahbodc852b862021-09-19 16:30:12 -04001580 hb_sorted_array_t<const HBGlyphID16> glyphs,
Behdad Esfahbodf1e95e42018-12-18 16:49:08 -05001581 hb_array_t<const unsigned int> substitute_len_list,
Behdad Esfahbodc852b862021-09-19 16:30:12 -04001582 hb_array_t<const HBGlyphID16> substitute_glyphs_list)
Behdad Esfahbodb3b89b62012-09-04 21:13:17 -04001583 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001584 TRACE_SERIALIZE (this);
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07001585 if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false);
Garret Riegercc96c4e2021-06-14 16:43:23 -07001586 if (c->push<SubTable> ()->u.multiple.
1587 serialize (c,
1588 glyphs,
1589 substitute_len_list,
1590 substitute_glyphs_list))
1591 {
1592 c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
1593 return_trace (true);
1594 }
1595 c->pop_discard ();
1596 return_trace (false);
Behdad Esfahbodb3b89b62012-09-04 21:13:17 -04001597 }
1598
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301599 bool serialize_alternate (hb_serialize_context_t *c,
1600 uint32_t lookup_props,
Behdad Esfahbodc852b862021-09-19 16:30:12 -04001601 hb_sorted_array_t<const HBGlyphID16> glyphs,
Behdad Esfahbodf1e95e42018-12-18 16:49:08 -05001602 hb_array_t<const unsigned int> alternate_len_list,
Behdad Esfahbodc852b862021-09-19 16:30:12 -04001603 hb_array_t<const HBGlyphID16> alternate_glyphs_list)
Behdad Esfahbodb3b89b62012-09-04 21:13:17 -04001604 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001605 TRACE_SERIALIZE (this);
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07001606 if (unlikely (!Lookup::serialize (c, SubTable::Alternate, lookup_props, 1))) return_trace (false);
Garret Riegercc96c4e2021-06-14 16:43:23 -07001607
1608 if (c->push<SubTable> ()->u.alternate.
1609 serialize (c,
1610 glyphs,
1611 alternate_len_list,
1612 alternate_glyphs_list))
1613 {
1614 c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
1615 return_trace (true);
1616 }
1617 c->pop_discard ();
1618 return_trace (false);
Behdad Esfahbodb3b89b62012-09-04 21:13:17 -04001619 }
1620
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301621 bool serialize_ligature (hb_serialize_context_t *c,
1622 uint32_t lookup_props,
Behdad Esfahbodc852b862021-09-19 16:30:12 -04001623 hb_sorted_array_t<const HBGlyphID16> first_glyphs,
Behdad Esfahbodf1e95e42018-12-18 16:49:08 -05001624 hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
Behdad Esfahbodc852b862021-09-19 16:30:12 -04001625 hb_array_t<const HBGlyphID16> ligatures_list,
Behdad Esfahbodf1e95e42018-12-18 16:49:08 -05001626 hb_array_t<const unsigned int> component_count_list,
Behdad Esfahbodc852b862021-09-19 16:30:12 -04001627 hb_array_t<const HBGlyphID16> component_list /* Starting from second for each ligature */)
Behdad Esfahbodb3b89b62012-09-04 21:13:17 -04001628 {
Behdad Esfahbodbe218c62012-11-23 15:32:14 -05001629 TRACE_SERIALIZE (this);
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07001630 if (unlikely (!Lookup::serialize (c, SubTable::Ligature, lookup_props, 1))) return_trace (false);
Garret Riegercc96c4e2021-06-14 16:43:23 -07001631 if (c->push<SubTable> ()->u.ligature.
1632 serialize (c,
1633 first_glyphs,
1634 ligature_per_first_glyph_count_list,
1635 ligatures_list,
1636 component_count_list,
1637 component_list))
1638 {
1639 c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
1640 return_trace (true);
1641 }
1642 c->pop_discard ();
1643 return_trace (false);
Behdad Esfahbodb3b89b62012-09-04 21:13:17 -04001644 }
1645
Behdad Esfahbodee5464d2013-03-09 01:59:30 -05001646 template <typename context_t>
Behdad Esfahboda061e472019-12-10 13:31:50 -06001647 static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
Garret Rieger73ed59f2021-03-17 15:53:10 -07001648
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08001649 static inline typename hb_closure_context_t::return_t closure_glyphs_recurse_func (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *covered_seq_indices, unsigned seq_index, unsigned end_index);
Behdad Esfahbodee5464d2013-03-09 01:59:30 -05001650
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08001651 static inline hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *covered_seq_indices, unsigned seq_index, unsigned end_index)
Garret Rieger45186b92018-06-05 17:14:42 -07001652 {
Behdad Esfahbodba0ea562018-06-11 23:24:41 -04001653 if (!c->should_visit_lookup (lookup_index))
Behdad Esfahbod7df3ecf2019-05-10 20:43:26 -07001654 return hb_empty_t ();
Behdad Esfahbodc38bd402018-07-24 09:43:27 -07001655
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08001656 hb_closure_context_t::return_t ret = closure_glyphs_recurse_func (c, lookup_index, covered_seq_indices, seq_index, end_index);
Behdad Esfahbodc38bd402018-07-24 09:43:27 -07001657
Behdad Esfahboda9e0bdc2018-11-22 21:30:04 -05001658 /* While in theory we should flush here, it will cause timeouts because a recursive
1659 * lookup can keep growing the glyph set. Skip, and outer loop will retry up to
1660 * HB_CLOSURE_MAX_STAGES time, which should be enough for every realistic font. */
1661 //c->flush ();
Behdad Esfahbodc38bd402018-07-24 09:43:27 -07001662
1663 return ret;
Garret Rieger45186b92018-06-05 17:14:42 -07001664 }
1665
Qunxin Liu0b39c482019-10-22 16:00:43 -07001666 HB_INTERNAL static hb_closure_lookups_context_t::return_t dispatch_closure_lookups_recurse_func (hb_closure_lookups_context_t *c, unsigned lookup_index);
1667
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -07001668 template <typename context_t, typename ...Ts>
Behdad Esfahbod83e3eab2019-05-07 20:58:43 -07001669 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
Behdad Esfahbod36bb24f2019-05-05 10:14:17 -07001670 { return Lookup::dispatch<SubTable> (c, hb_forward<Ts> (ds)...); }
Behdad Esfahbod9c3747c2018-09-03 16:53:03 -07001671
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301672 bool subset (hb_subset_context_t *c) const
Behdad Esfahbod339d3602018-09-03 17:33:34 -07001673 { return Lookup::subset<SubTable> (c); }
Behdad Esfahbodee5464d2013-03-09 01:59:30 -05001674
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301675 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbod7b2ef552018-09-03 17:16:09 -07001676 { return Lookup::sanitize<SubTable> (c); }
Behdad Esfahbod2d15e722009-04-15 19:50:16 -04001677};
Behdad Esfahbod2d15e722009-04-15 19:50:16 -04001678
1679/*
Ebrahim Byagowia02c3ee2018-04-12 13:38:19 +04301680 * GSUB -- Glyph Substitution
1681 * https://docs.microsoft.com/en-us/typography/opentype/spec/gsub
Behdad Esfahbod75860892008-01-23 18:02:28 -05001682 */
1683
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001684struct GSUB : GSUBGPOS
1685{
Behdad Esfahbodef006542019-01-22 12:08:57 +01001686 static constexpr hb_tag_t tableTag = HB_OT_TAG_GSUB;
Behdad Esfahbod75860892008-01-23 18:02:28 -05001687
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301688 const SubstLookup& get_lookup (unsigned int i) const
Behdad Esfahbod858b6272019-12-10 13:18:32 -06001689 { return static_cast<const SubstLookup &> (GSUBGPOS::get_lookup (i)); }
Behdad Esfahbod2d15e722009-04-15 19:50:16 -04001690
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301691 bool subset (hb_subset_context_t *c) const
Qunxin Liue565d1f2019-11-01 10:21:36 -07001692 {
Qunxin Liu56ca4352021-01-28 15:21:26 -08001693 hb_subset_layout_context_t l (c, tableTag, c->plan->gsub_lookups, c->plan->gsub_langsys, c->plan->gsub_features);
Qunxin Liue565d1f2019-11-01 10:21:36 -07001694 return GSUBGPOS::subset<SubstLookup> (&l);
1695 }
Behdad Esfahbodd1f29902018-08-31 16:31:00 -07001696
Ebrahim Byagowib2ebaa92018-12-16 22:38:10 +03301697 bool sanitize (hb_sanitize_context_t *c) const
Behdad Esfahbod339d3602018-09-03 17:33:34 -07001698 { return GSUBGPOS::sanitize<SubstLookup> (c); }
Behdad Esfahbod963413f2018-08-26 00:47:55 -07001699
Behdad Esfahbod56719472020-06-05 12:57:23 -07001700 HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
Behdad Esfahbod574d8882018-11-25 16:51:22 -05001701 hb_face_t *face) const;
1702
Qunxin Liu973c47f2020-06-11 11:27:57 -07001703 void closure_lookups (hb_face_t *face,
Ebrahim Byagowi5a7cc7f2020-07-29 08:33:32 +04301704 const hb_set_t *glyphs,
1705 hb_set_t *lookup_indexes /* IN/OUT */) const
Qunxin Liu973c47f2020-06-11 11:27:57 -07001706 { GSUBGPOS::closure_lookups<SubstLookup> (face, glyphs, lookup_indexes); }
1707
Behdad Esfahbod963413f2018-08-26 00:47:55 -07001708 typedef GSUBGPOS::accelerator_t<GSUB> accelerator_t;
Behdad Esfahbod75860892008-01-23 18:02:28 -05001709};
Behdad Esfahbodc43562b2009-05-15 18:54:53 -04001710
1711
Behdad Esfahbod33b006c2018-11-05 23:19:04 -05001712struct GSUB_accelerator_t : GSUB::accelerator_t {};
1713
1714
Behdad Esfahbod887c4b42009-05-17 21:06:08 -04001715/* Out-of-class implementation for methods recursing */
Behdad Esfahbodc43562b2009-05-15 18:54:53 -04001716
Behdad Esfahbod7dcf8e12019-06-26 13:44:10 -07001717#ifndef HB_NO_OT_LAYOUT
Ebrahim Byagowie4120082018-12-17 21:31:01 +03301718/*static*/ inline bool ExtensionSubst::is_reverse () const
Behdad Esfahboda065f472010-04-22 20:15:11 -04001719{
Behdad Esfahboddd3972a2019-12-10 13:21:26 -06001720 return SubstLookup::lookup_type_is_reverse (get_type ());
Behdad Esfahboda065f472010-04-22 20:15:11 -04001721}
Behdad Esfahbodc6fb8432012-11-23 18:04:08 -05001722template <typename context_t>
Behdad Esfahboddd3972a2019-12-10 13:21:26 -06001723/*static*/ typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
Behdad Esfahbod9b346772012-11-23 17:55:40 -05001724{
Behdad Esfahbod33b006c2018-11-05 23:19:04 -05001725 const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index);
Behdad Esfahbod9c5a9ee2013-03-09 01:55:04 -05001726 return l.dispatch (c);
Behdad Esfahbod9b346772012-11-23 17:55:40 -05001727}
Qunxin Liu0b39c482019-10-22 16:00:43 -07001728
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08001729/*static*/ typename hb_closure_context_t::return_t SubstLookup::closure_glyphs_recurse_func (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *covered_seq_indices, unsigned seq_index, unsigned end_index)
Qunxin Liub8a58a02021-01-10 15:50:04 -08001730{
1731 const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index);
1732 if (l.may_have_non_1to1 ())
Qunxin Liu0e1c0fa2021-01-12 10:17:14 -08001733 hb_set_add_range (covered_seq_indices, seq_index, end_index);
Qunxin Liub8a58a02021-01-10 15:50:04 -08001734 return l.dispatch (c);
1735}
1736
Qunxin Liu0b39c482019-10-22 16:00:43 -07001737/*static*/ inline hb_closure_lookups_context_t::return_t SubstLookup::dispatch_closure_lookups_recurse_func (hb_closure_lookups_context_t *c, unsigned this_index)
1738{
1739 const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (this_index);
1740 return l.closure_lookups (c, this_index);
1741}
1742
Behdad Esfahboda061e472019-12-10 13:31:50 -06001743/*static*/ bool SubstLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index)
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001744{
Behdad Esfahbod33b006c2018-11-05 23:19:04 -05001745 const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index);
Behdad Esfahbod4c4e8f02012-11-24 01:13:20 -05001746 unsigned int saved_lookup_props = c->lookup_props;
Behdad Esfahbod2c8b3b22015-08-18 14:36:43 +01001747 unsigned int saved_lookup_index = c->lookup_index;
1748 c->set_lookup_index (lookup_index);
1749 c->set_lookup_props (l.get_props ());
Behdad Esfahbod1a232212015-02-19 10:40:23 +03001750 bool ret = l.dispatch (c);
Behdad Esfahbod2c8b3b22015-08-18 14:36:43 +01001751 c->set_lookup_index (saved_lookup_index);
Behdad Esfahbod77889932015-01-28 23:01:12 -08001752 c->set_lookup_props (saved_lookup_props);
Behdad Esfahbod4c4e8f02012-11-24 01:13:20 -05001753 return ret;
Behdad Esfahbodc43562b2009-05-15 18:54:53 -04001754}
Behdad Esfahbod7dcf8e12019-06-26 13:44:10 -07001755#endif
1756
Behdad Esfahbodc43562b2009-05-15 18:54:53 -04001757
Behdad Esfahbod7d52e662012-11-16 18:49:54 -08001758} /* namespace OT */
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -04001759
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04001760
Behdad Esfahbod7a750ac2011-08-17 14:19:59 +02001761#endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */