blob: 05b18cc3ea6e3924b7cd7d8efdde87269a45cdd4 [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 Esfahbod5b93e8d2012-04-23 22:26:13 -04003 * Copyright © 2010,2012 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 Esfahbod5f5b24f2009-08-02 20:03:12 -040032#include "hb-ot-layout-gsubgpos-private.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
Behdad Esfahbod6f20f722009-05-17 20:28:01 -040037
Behdad Esfahbod4c44d832009-05-19 23:42:30 -040038struct SingleSubstFormat1
39{
Behdad Esfahbod2d15e722009-04-15 19:50:16 -040040 friend struct SingleSubst;
41
42 private:
Behdad Esfahbod70de50c2009-08-04 00:58:28 -040043
Behdad Esfahbod5caece62012-04-23 23:03:12 -040044 inline void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -040045 {
46 TRACE_CLOSURE ();
Behdad Esfahbodc64ddab2012-04-23 15:28:35 -040047 Coverage::Iter iter;
48 for (iter.init (this+coverage); iter.more (); iter.next ()) {
49 hb_codepoint_t glyph_id = iter.get_glyph ();
50 if (c->glyphs->has (glyph_id))
Behdad Esfahbod5caece62012-04-23 23:03:12 -040051 c->glyphs->add ((glyph_id + deltaGlyphID) & 0xFFFF);
Behdad Esfahbodc64ddab2012-04-23 15:28:35 -040052 }
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -040053 }
54
Behdad Esfahbod0b994292012-07-28 17:31:01 -040055 inline const Coverage &get_coverage (void) const
56 {
57 return this+coverage;
58 }
59
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -040060 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -040061 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -040062 TRACE_APPLY ();
Behdad Esfahbod99c26952012-05-13 15:45:18 +020063 hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
Behdad Esfahbod238c8552009-05-17 00:22:37 -040064 unsigned int index = (this+coverage) (glyph_id);
Behdad Esfahbodacea1832012-05-11 02:33:11 +020065 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -040066
Behdad Esfahbod52ebdff2011-09-27 12:38:16 -040067 /* According to the Adobe Annotated OpenType Suite, result is always
68 * limited to 16bit. */
69 glyph_id = (glyph_id + deltaGlyphID) & 0xFFFF;
Behdad Esfahbod98370e82010-10-27 17:39:01 -040070 c->replace_glyph (glyph_id);
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -040071
Behdad Esfahbodacea1832012-05-11 02:33:11 +020072 return TRACE_RETURN (true);
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -040073 }
74
Behdad Esfahbodbc5be242012-09-01 20:48:22 -040075 inline bool serialize (hb_serialize_context_t *c,
Behdad Esfahboda930c682012-09-04 18:17:57 -040076 Supplier<GlyphID> &glyphs,
Behdad Esfahbodbc5be242012-09-01 20:48:22 -040077 unsigned int num_glyphs,
Behdad Esfahbod1b38b4e2012-09-04 18:17:21 -040078 int delta)
Behdad Esfahbodbc5be242012-09-01 20:48:22 -040079 {
80 TRACE_SERIALIZE ();
81 if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
Behdad Esfahbodabcc5ac2012-09-01 21:30:17 -040082 if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
Behdad Esfahbod49120302012-09-03 20:58:03 -040083 deltaGlyphID.set (delta); /* TODO(serilaize) overflow? */
Behdad Esfahbodbc5be242012-09-01 20:48:22 -040084 return TRACE_RETURN (true);
85 }
86
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -040087 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -040088 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +020089 return TRACE_RETURN (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -040090 }
91
Behdad Esfahbodec8d2492012-07-24 15:40:37 -040092 protected:
Behdad Esfahbodf45107f2009-05-17 20:13:02 -040093 USHORT format; /* Format identifier--format = 1 */
Behdad Esfahbod238c8552009-05-17 00:22:37 -040094 OffsetTo<Coverage>
95 coverage; /* Offset to Coverage table--from
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -040096 * beginning of Substitution table */
97 SHORT deltaGlyphID; /* Add to original GlyphID to get
98 * substitute GlyphID */
Behdad Esfahbodb3651232010-05-10 16:57:29 -040099 public:
100 DEFINE_SIZE_STATIC (6);
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400101};
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400102
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400103struct SingleSubstFormat2
104{
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400105 friend struct SingleSubst;
106
107 private:
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400108
Behdad Esfahbod5caece62012-04-23 23:03:12 -0400109 inline void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400110 {
111 TRACE_CLOSURE ();
Behdad Esfahbodc64ddab2012-04-23 15:28:35 -0400112 Coverage::Iter iter;
113 for (iter.init (this+coverage); iter.more (); iter.next ()) {
114 if (c->glyphs->has (iter.get_glyph ()))
Behdad Esfahbod5caece62012-04-23 23:03:12 -0400115 c->glyphs->add (substitute[iter.get_coverage ()]);
Behdad Esfahbodc64ddab2012-04-23 15:28:35 -0400116 }
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400117 }
118
Behdad Esfahbod0b994292012-07-28 17:31:01 -0400119 inline const Coverage &get_coverage (void) const
120 {
121 return this+coverage;
122 }
123
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400124 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400125 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400126 TRACE_APPLY ();
Behdad Esfahbod99c26952012-05-13 15:45:18 +0200127 hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
Behdad Esfahbod238c8552009-05-17 00:22:37 -0400128 unsigned int index = (this+coverage) (glyph_id);
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200129 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400130
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200131 if (unlikely (index >= substitute.len)) return TRACE_RETURN (false);
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400132
133 glyph_id = substitute[index];
Behdad Esfahbod98370e82010-10-27 17:39:01 -0400134 c->replace_glyph (glyph_id);
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400135
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200136 return TRACE_RETURN (true);
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400137 }
138
Behdad Esfahbodc61be032012-09-01 21:43:38 -0400139 inline bool serialize (hb_serialize_context_t *c,
Behdad Esfahboda930c682012-09-04 18:17:57 -0400140 Supplier<GlyphID> &glyphs,
141 Supplier<GlyphID> &substitutes,
Behdad Esfahbodc61be032012-09-01 21:43:38 -0400142 unsigned int num_glyphs)
143 {
144 TRACE_SERIALIZE ();
145 if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
Behdad Esfahbodc61be032012-09-01 21:43:38 -0400146 if (unlikely (!substitute.serialize (c, substitutes, num_glyphs))) return TRACE_RETURN (false);
Behdad Esfahbodfabd3112012-09-05 22:19:28 -0400147 if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
Behdad Esfahbodc61be032012-09-01 21:43:38 -0400148 return TRACE_RETURN (true);
149 }
150
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400151 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400152 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200153 return TRACE_RETURN (coverage.sanitize (c, this) && substitute.sanitize (c));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400154 }
155
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400156 protected:
Behdad Esfahbodf45107f2009-05-17 20:13:02 -0400157 USHORT format; /* Format identifier--format = 2 */
Behdad Esfahbod238c8552009-05-17 00:22:37 -0400158 OffsetTo<Coverage>
159 coverage; /* Offset to Coverage table--from
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400160 * beginning of Substitution table */
Behdad Esfahbodc9a7cbe2009-05-17 01:22:51 -0400161 ArrayOf<GlyphID>
162 substitute; /* Array of substitute
163 * GlyphIDs--ordered by Coverage Index */
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400164 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400165 DEFINE_SIZE_ARRAY (6, substitute);
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400166};
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400167
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400168struct SingleSubst
169{
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400170 friend struct SubstLookupSubTable;
Behdad Esfahbodb3b89b62012-09-04 21:13:17 -0400171 friend struct SubstLookup;
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400172
Behdad Esfahbod4f27ce72009-04-16 13:40:13 -0400173 private:
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400174
Behdad Esfahbod5caece62012-04-23 23:03:12 -0400175 inline void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400176 {
177 TRACE_CLOSURE ();
178 switch (u.format) {
Behdad Esfahbod5caece62012-04-23 23:03:12 -0400179 case 1: u.format1.closure (c); break;
180 case 2: u.format2.closure (c); break;
181 default: break;
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400182 }
183 }
184
Behdad Esfahbod0b994292012-07-28 17:31:01 -0400185 inline const Coverage &get_coverage (void) const
186 {
187 switch (u.format) {
188 case 1: return u.format1.get_coverage ();
189 case 2: return u.format2.get_coverage ();
190 default:return Null(Coverage);
191 }
192 }
193
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400194 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400195 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400196 TRACE_APPLY ();
Behdad Esfahbodf8dc67b2009-05-17 19:47:54 -0400197 switch (u.format) {
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200198 case 1: return TRACE_RETURN (u.format1.apply (c));
199 case 2: return TRACE_RETURN (u.format2.apply (c));
200 default:return TRACE_RETURN (false);
Behdad Esfahbod38b011a2009-05-04 20:21:57 -0400201 }
202 }
203
Behdad Esfahbodc61be032012-09-01 21:43:38 -0400204 inline bool serialize (hb_serialize_context_t *c,
Behdad Esfahboda930c682012-09-04 18:17:57 -0400205 Supplier<GlyphID> &glyphs,
206 Supplier<GlyphID> &substitutes,
Behdad Esfahbodc61be032012-09-01 21:43:38 -0400207 unsigned int num_glyphs)
208 {
209 TRACE_SERIALIZE ();
210 if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
211 unsigned int format = 2;
Behdad Esfahbod1b38b4e2012-09-04 18:17:21 -0400212 int delta;
Behdad Esfahbodc61be032012-09-01 21:43:38 -0400213 if (num_glyphs) {
214 format = 1;
Behdad Esfahbod49120302012-09-03 20:58:03 -0400215 /* TODO(serialize) check for wrap-around */
Behdad Esfahbodc61be032012-09-01 21:43:38 -0400216 delta = substitutes[0] - glyphs[0];
217 for (unsigned int i = 1; i < num_glyphs; i++)
218 if (delta != substitutes[i] - glyphs[i]) {
219 format = 2;
220 break;
221 }
222 }
223 u.format.set (format);
224 switch (u.format) {
225 case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, num_glyphs, delta));
226 case 2: return TRACE_RETURN (u.format2.serialize (c, glyphs, substitutes, num_glyphs));
227 default:return TRACE_RETURN (false);
228 }
229 }
230
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400231 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400232 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200233 if (!u.format.sanitize (c)) return TRACE_RETURN (false);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400234 switch (u.format) {
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200235 case 1: return TRACE_RETURN (u.format1.sanitize (c));
236 case 2: return TRACE_RETURN (u.format2.sanitize (c));
237 default:return TRACE_RETURN (true);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400238 }
239 }
240
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400241 protected:
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400242 union {
Behdad Esfahbodf8dc67b2009-05-17 19:47:54 -0400243 USHORT format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -0400244 SingleSubstFormat1 format1;
245 SingleSubstFormat2 format2;
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400246 } u;
247};
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400248
249
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400250struct Sequence
251{
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400252 friend struct MultipleSubstFormat1;
253
254 private:
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400255
Behdad Esfahbod5caece62012-04-23 23:03:12 -0400256 inline void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400257 {
258 TRACE_CLOSURE ();
Behdad Esfahbodc64ddab2012-04-23 15:28:35 -0400259 unsigned int count = substitute.len;
Behdad Esfahbodc64ddab2012-04-23 15:28:35 -0400260 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod5caece62012-04-23 23:03:12 -0400261 c->glyphs->add (substitute[i]);
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400262 }
263
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400264 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400265 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400266 TRACE_APPLY ();
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200267 if (unlikely (!substitute.len)) return TRACE_RETURN (false);
Behdad Esfahbodc9c6a782009-05-05 16:22:02 -0400268
Behdad Esfahboded2f1362012-05-22 22:12:22 -0400269 unsigned int klass = c->property & HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE ? HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH : 0;
Behdad Esfahbod3ec77d62012-06-08 21:44:06 -0400270 unsigned int count = substitute.len;
Behdad Esfahbodec57e0c2012-06-08 21:47:23 -0400271 for (unsigned int i = 0; i < count; i++) {
Behdad Esfahbod2ec3ba42012-07-29 22:02:24 -0400272 set_lig_props_for_component (c->buffer->cur(), i);
Behdad Esfahbod3ec77d62012-06-08 21:44:06 -0400273 c->output_glyph (substitute.array[i], klass);
Behdad Esfahbodec57e0c2012-06-08 21:47:23 -0400274 }
Behdad Esfahbod3ec77d62012-06-08 21:44:06 -0400275 c->buffer->skip_glyph ();
Behdad Esfahbodc9c6a782009-05-05 16:22:02 -0400276
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200277 return TRACE_RETURN (true);
Behdad Esfahbodc9c6a782009-05-05 16:22:02 -0400278 }
279
Behdad Esfahbod1f07e332012-09-03 23:28:34 -0400280 inline bool serialize (hb_serialize_context_t *c,
Behdad Esfahboda930c682012-09-04 18:17:57 -0400281 Supplier<GlyphID> &glyphs,
Behdad Esfahbod1f07e332012-09-03 23:28:34 -0400282 unsigned int num_glyphs)
283 {
284 TRACE_SERIALIZE ();
285 if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
286 if (unlikely (!substitute.serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
287 return TRACE_RETURN (true);
288 }
289
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400290 public:
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400291 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400292 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200293 return TRACE_RETURN (substitute.sanitize (c));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400294 }
295
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400296 protected:
Behdad Esfahbodc9a7cbe2009-05-17 01:22:51 -0400297 ArrayOf<GlyphID>
298 substitute; /* String of GlyphIDs to substitute */
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400299 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400300 DEFINE_SIZE_ARRAY (2, substitute);
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400301};
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400302
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400303struct MultipleSubstFormat1
304{
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400305 friend struct MultipleSubst;
306
307 private:
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400308
Behdad Esfahbod5caece62012-04-23 23:03:12 -0400309 inline void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400310 {
311 TRACE_CLOSURE ();
Behdad Esfahbodc64ddab2012-04-23 15:28:35 -0400312 Coverage::Iter iter;
313 for (iter.init (this+coverage); iter.more (); iter.next ()) {
314 if (c->glyphs->has (iter.get_glyph ()))
Behdad Esfahbod5caece62012-04-23 23:03:12 -0400315 (this+sequence[iter.get_coverage ()]).closure (c);
Behdad Esfahbodc64ddab2012-04-23 15:28:35 -0400316 }
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400317 }
318
Behdad Esfahbod0b994292012-07-28 17:31:01 -0400319 inline const Coverage &get_coverage (void) const
320 {
321 return this+coverage;
322 }
323
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400324 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400325 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400326 TRACE_APPLY ();
Behdad Esfahbod30bd7632009-04-15 22:56:15 -0400327
Behdad Esfahbod99c26952012-05-13 15:45:18 +0200328 unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200329 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -0400330
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200331 return TRACE_RETURN ((this+sequence[index]).apply (c));
Behdad Esfahbod2d15e722009-04-15 19:50:16 -0400332 }
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500333
Behdad Esfahbod1f07e332012-09-03 23:28:34 -0400334 inline bool serialize (hb_serialize_context_t *c,
Behdad Esfahboda930c682012-09-04 18:17:57 -0400335 Supplier<GlyphID> &glyphs,
336 Supplier<unsigned int> &substitute_len_list,
Behdad Esfahbod1f07e332012-09-03 23:28:34 -0400337 unsigned int num_glyphs,
Behdad Esfahboda930c682012-09-04 18:17:57 -0400338 Supplier<GlyphID> &substitute_glyphs_list)
Behdad Esfahbod1f07e332012-09-03 23:28:34 -0400339 {
340 TRACE_SERIALIZE ();
341 if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
Behdad Esfahbod1f07e332012-09-03 23:28:34 -0400342 if (unlikely (!sequence.serialize (c, num_glyphs))) return TRACE_RETURN (false);
Behdad Esfahboda930c682012-09-04 18:17:57 -0400343 for (unsigned int i = 0; i < num_glyphs; i++)
344 if (unlikely (!sequence[i].serialize (c, this).serialize (c,
345 substitute_glyphs_list,
346 substitute_len_list[i]))) return TRACE_RETURN (false);
347 substitute_len_list.advance (num_glyphs);
Behdad Esfahbodfabd3112012-09-05 22:19:28 -0400348 if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
Behdad Esfahbod1f07e332012-09-03 23:28:34 -0400349 return TRACE_RETURN (true);
350 }
351
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400352 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400353 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200354 return TRACE_RETURN (coverage.sanitize (c, this) && sequence.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400355 }
356
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400357 protected:
Behdad Esfahbodf45107f2009-05-17 20:13:02 -0400358 USHORT format; /* Format identifier--format = 1 */
Behdad Esfahbod238c8552009-05-17 00:22:37 -0400359 OffsetTo<Coverage>
360 coverage; /* Offset to Coverage table--from
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500361 * beginning of Substitution table */
Behdad Esfahbodc9a7cbe2009-05-17 01:22:51 -0400362 OffsetArrayOf<Sequence>
363 sequence; /* Array of Sequence tables
364 * ordered by Coverage Index */
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400365 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400366 DEFINE_SIZE_ARRAY (6, sequence);
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500367};
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500368
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400369struct MultipleSubst
370{
Behdad Esfahbod4f27ce72009-04-16 13:40:13 -0400371 friend struct SubstLookupSubTable;
Behdad Esfahbodb3b89b62012-09-04 21:13:17 -0400372 friend struct SubstLookup;
Behdad Esfahbod4f27ce72009-04-16 13:40:13 -0400373
374 private:
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400375
Behdad Esfahbod5caece62012-04-23 23:03:12 -0400376 inline void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400377 {
378 TRACE_CLOSURE ();
379 switch (u.format) {
Behdad Esfahbod5caece62012-04-23 23:03:12 -0400380 case 1: u.format1.closure (c); break;
381 default: break;
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400382 }
383 }
384
Behdad Esfahbod0b994292012-07-28 17:31:01 -0400385 inline const Coverage &get_coverage (void) const
386 {
387 switch (u.format) {
388 case 1: return u.format1.get_coverage ();
389 default:return Null(Coverage);
390 }
391 }
392
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400393 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400394 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400395 TRACE_APPLY ();
Behdad Esfahbodf8dc67b2009-05-17 19:47:54 -0400396 switch (u.format) {
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200397 case 1: return TRACE_RETURN (u.format1.apply (c));
398 default:return TRACE_RETURN (false);
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400399 }
400 }
401
Behdad Esfahbod1f07e332012-09-03 23:28:34 -0400402 inline bool serialize (hb_serialize_context_t *c,
Behdad Esfahboda930c682012-09-04 18:17:57 -0400403 Supplier<GlyphID> &glyphs,
404 Supplier<unsigned int> &substitute_len_list,
Behdad Esfahbod1f07e332012-09-03 23:28:34 -0400405 unsigned int num_glyphs,
Behdad Esfahboda930c682012-09-04 18:17:57 -0400406 Supplier<GlyphID> &substitute_glyphs_list)
Behdad Esfahbod1f07e332012-09-03 23:28:34 -0400407 {
408 TRACE_SERIALIZE ();
409 if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
410 unsigned int format = 1;
411 u.format.set (format);
412 switch (u.format) {
413 case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, substitute_len_list, num_glyphs, substitute_glyphs_list));
414 default:return TRACE_RETURN (false);
415 }
416 }
417
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400418 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400419 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200420 if (!u.format.sanitize (c)) return TRACE_RETURN (false);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400421 switch (u.format) {
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200422 case 1: return TRACE_RETURN (u.format1.sanitize (c));
423 default:return TRACE_RETURN (true);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400424 }
425 }
426
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400427 protected:
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400428 union {
Behdad Esfahbodf8dc67b2009-05-17 19:47:54 -0400429 USHORT format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -0400430 MultipleSubstFormat1 format1;
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400431 } u;
432};
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400433
434
Behdad Esfahbodc9a7cbe2009-05-17 01:22:51 -0400435typedef ArrayOf<GlyphID> AlternateSet; /* Array of alternate GlyphIDs--in
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400436 * arbitrary order */
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500437
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400438struct AlternateSubstFormat1
439{
Behdad Esfahbod52886ca2009-04-16 14:19:42 -0400440 friend struct AlternateSubst;
441
442 private:
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400443
Behdad Esfahbod5caece62012-04-23 23:03:12 -0400444 inline void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400445 {
446 TRACE_CLOSURE ();
Behdad Esfahbodc64ddab2012-04-23 15:28:35 -0400447 Coverage::Iter iter;
448 for (iter.init (this+coverage); iter.more (); iter.next ()) {
449 if (c->glyphs->has (iter.get_glyph ())) {
450 const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
451 unsigned int count = alt_set.len;
452 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod5caece62012-04-23 23:03:12 -0400453 c->glyphs->add (alt_set[i]);
Behdad Esfahbodc64ddab2012-04-23 15:28:35 -0400454 }
455 }
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400456 }
457
Behdad Esfahbod0b994292012-07-28 17:31:01 -0400458 inline const Coverage &get_coverage (void) const
459 {
460 return this+coverage;
461 }
462
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400463 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400464 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400465 TRACE_APPLY ();
Behdad Esfahbod99c26952012-05-13 15:45:18 +0200466 hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
Behdad Esfahbod52886ca2009-04-16 14:19:42 -0400467
Behdad Esfahbod238c8552009-05-17 00:22:37 -0400468 unsigned int index = (this+coverage) (glyph_id);
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200469 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -0400470
Behdad Esfahbodc9a7cbe2009-05-17 01:22:51 -0400471 const AlternateSet &alt_set = this+alternateSet[index];
Behdad Esfahbod52886ca2009-04-16 14:19:42 -0400472
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200473 if (unlikely (!alt_set.len)) return TRACE_RETURN (false);
Behdad Esfahbod52886ca2009-04-16 14:19:42 -0400474
Behdad Esfahbod99c26952012-05-13 15:45:18 +0200475 hb_mask_t glyph_mask = c->buffer->cur().mask;
Behdad Esfahbod36608942012-04-19 22:21:38 -0400476 hb_mask_t lookup_mask = c->lookup_mask;
477
Behdad Esfahboddd22a8f2010-05-21 16:43:17 +0100478 /* Note: This breaks badly if two features enabled this lookup together. */
Behdad Esfahbodf7acd8d2010-05-20 17:26:35 +0100479 unsigned int shift = _hb_ctz (lookup_mask);
Behdad Esfahbod1cdbfd92010-05-20 17:47:28 +0100480 unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
Behdad Esfahbod52886ca2009-04-16 14:19:42 -0400481
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200482 if (unlikely (alt_index > alt_set.len || alt_index == 0)) return TRACE_RETURN (false);
Behdad Esfahbod52886ca2009-04-16 14:19:42 -0400483
Behdad Esfahbod1cdbfd92010-05-20 17:47:28 +0100484 glyph_id = alt_set[alt_index - 1];
Behdad Esfahbod52886ca2009-04-16 14:19:42 -0400485
Behdad Esfahbod98370e82010-10-27 17:39:01 -0400486 c->replace_glyph (glyph_id);
Behdad Esfahbod52886ca2009-04-16 14:19:42 -0400487
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200488 return TRACE_RETURN (true);
Behdad Esfahbod52886ca2009-04-16 14:19:42 -0400489 }
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500490
Behdad Esfahbod29416832012-09-03 23:31:14 -0400491 inline bool serialize (hb_serialize_context_t *c,
Behdad Esfahboda930c682012-09-04 18:17:57 -0400492 Supplier<GlyphID> &glyphs,
493 Supplier<unsigned int> &alternate_len_list,
Behdad Esfahbod29416832012-09-03 23:31:14 -0400494 unsigned int num_glyphs,
Behdad Esfahboda930c682012-09-04 18:17:57 -0400495 Supplier<GlyphID> &alternate_glyphs_list)
Behdad Esfahbod29416832012-09-03 23:31:14 -0400496 {
497 TRACE_SERIALIZE ();
498 if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
Behdad Esfahbod29416832012-09-03 23:31:14 -0400499 if (unlikely (!alternateSet.serialize (c, num_glyphs))) return TRACE_RETURN (false);
Behdad Esfahboda930c682012-09-04 18:17:57 -0400500 for (unsigned int i = 0; i < num_glyphs; i++)
501 if (unlikely (!alternateSet[i].serialize (c, this).serialize (c,
502 alternate_glyphs_list,
503 alternate_len_list[i]))) return TRACE_RETURN (false);
504 alternate_len_list.advance (num_glyphs);
Behdad Esfahbodfabd3112012-09-05 22:19:28 -0400505 if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
Behdad Esfahbod29416832012-09-03 23:31:14 -0400506 return TRACE_RETURN (true);
507 }
508
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400509 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400510 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200511 return TRACE_RETURN (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400512 }
513
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400514 protected:
Behdad Esfahbodf45107f2009-05-17 20:13:02 -0400515 USHORT format; /* Format identifier--format = 1 */
Behdad Esfahbod238c8552009-05-17 00:22:37 -0400516 OffsetTo<Coverage>
517 coverage; /* Offset to Coverage table--from
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500518 * beginning of Substitution table */
Behdad Esfahbodc9a7cbe2009-05-17 01:22:51 -0400519 OffsetArrayOf<AlternateSet>
520 alternateSet; /* Array of AlternateSet tables
521 * ordered by Coverage Index */
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400522 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400523 DEFINE_SIZE_ARRAY (6, alternateSet);
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500524};
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500525
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400526struct AlternateSubst
527{
Behdad Esfahbod52886ca2009-04-16 14:19:42 -0400528 friend struct SubstLookupSubTable;
Behdad Esfahbodb3b89b62012-09-04 21:13:17 -0400529 friend struct SubstLookup;
Behdad Esfahbod52886ca2009-04-16 14:19:42 -0400530
531 private:
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400532
Behdad Esfahbod5caece62012-04-23 23:03:12 -0400533 inline void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400534 {
535 TRACE_CLOSURE ();
536 switch (u.format) {
Behdad Esfahbod5caece62012-04-23 23:03:12 -0400537 case 1: u.format1.closure (c); break;
538 default: break;
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400539 }
540 }
541
Behdad Esfahbod0b994292012-07-28 17:31:01 -0400542 inline const Coverage &get_coverage (void) const
543 {
544 switch (u.format) {
545 case 1: return u.format1.get_coverage ();
546 default:return Null(Coverage);
547 }
548 }
549
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400550 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400551 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400552 TRACE_APPLY ();
Behdad Esfahbodf8dc67b2009-05-17 19:47:54 -0400553 switch (u.format) {
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200554 case 1: return TRACE_RETURN (u.format1.apply (c));
555 default:return TRACE_RETURN (false);
Behdad Esfahbod52886ca2009-04-16 14:19:42 -0400556 }
557 }
558
Behdad Esfahbod29416832012-09-03 23:31:14 -0400559 inline bool serialize (hb_serialize_context_t *c,
Behdad Esfahboda930c682012-09-04 18:17:57 -0400560 Supplier<GlyphID> &glyphs,
561 Supplier<unsigned int> &alternate_len_list,
Behdad Esfahbod29416832012-09-03 23:31:14 -0400562 unsigned int num_glyphs,
Behdad Esfahboda930c682012-09-04 18:17:57 -0400563 Supplier<GlyphID> &alternate_glyphs_list)
Behdad Esfahbod29416832012-09-03 23:31:14 -0400564 {
565 TRACE_SERIALIZE ();
566 if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
567 unsigned int format = 1;
568 u.format.set (format);
569 switch (u.format) {
570 case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, alternate_len_list, num_glyphs, alternate_glyphs_list));
571 default:return TRACE_RETURN (false);
572 }
573 }
574
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400575 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400576 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200577 if (!u.format.sanitize (c)) return TRACE_RETURN (false);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400578 switch (u.format) {
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200579 case 1: return TRACE_RETURN (u.format1.sanitize (c));
580 default:return TRACE_RETURN (true);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400581 }
582 }
583
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400584 protected:
Behdad Esfahbod52886ca2009-04-16 14:19:42 -0400585 union {
Behdad Esfahbodf8dc67b2009-05-17 19:47:54 -0400586 USHORT format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -0400587 AlternateSubstFormat1 format1;
Behdad Esfahbod52886ca2009-04-16 14:19:42 -0400588 } u;
589};
Behdad Esfahbod52886ca2009-04-16 14:19:42 -0400590
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400591
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400592struct Ligature
593{
Behdad Esfahbodbb3899a2009-05-05 13:25:13 -0400594 friend struct LigatureSet;
595
596 private:
Behdad Esfahbod36608942012-04-19 22:21:38 -0400597
Behdad Esfahbod5caece62012-04-23 23:03:12 -0400598 inline void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400599 {
600 TRACE_CLOSURE ();
Behdad Esfahbodc64ddab2012-04-23 15:28:35 -0400601 unsigned int count = component.len;
602 for (unsigned int i = 1; i < count; i++)
603 if (!c->glyphs->has (component[i]))
Behdad Esfahbod5caece62012-04-23 23:03:12 -0400604 return;
605 c->glyphs->add (ligGlyph);
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400606 }
607
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400608 inline bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbod36608942012-04-19 22:21:38 -0400609 {
Behdad Esfahbod472f2292012-08-07 22:25:24 -0400610 if (c->len != component.len)
611 return false;
612
613 for (unsigned int i = 1; i < c->len; i++)
614 if (likely (c->glyphs[i] != component[i]))
615 return false;
616
617 return true;
Behdad Esfahbod36608942012-04-19 22:21:38 -0400618 }
619
Behdad Esfahbod98370e82010-10-27 17:39:01 -0400620 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400621 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400622 TRACE_APPLY ();
Behdad Esfahbode8cbaaf2009-05-18 02:03:58 -0400623 unsigned int count = component.len;
Behdad Esfahbod1feb8342012-07-16 13:23:40 -0400624 if (unlikely (count < 1)) return TRACE_RETURN (false);
Behdad Esfahbod4ab97312012-01-16 22:05:08 -0500625
Behdad Esfahbod191fa882012-08-28 22:58:55 -0400626 unsigned int end_offset;
627 bool is_mark_ligature;
628 unsigned int total_component_count;
Behdad Esfahbodbb3899a2009-05-05 13:25:13 -0400629
Behdad Esfahbod191fa882012-08-28 22:58:55 -0400630 if (likely (!match_input (c, count,
631 &component[1],
632 match_glyph,
633 NULL,
634 &end_offset,
635 &is_mark_ligature,
636 &total_component_count)))
637 return TRACE_RETURN (false);
Behdad Esfahbod98370e82010-10-27 17:39:01 -0400638
Behdad Esfahbodfe20c0f2012-07-30 00:00:59 -0400639 /* Deal, we are forming the ligature. */
Behdad Esfahbod191fa882012-08-28 22:58:55 -0400640 c->buffer->merge_clusters (c->buffer->idx, c->buffer->idx + end_offset);
Behdad Esfahbodcb3d3402012-07-29 20:37:38 -0400641
Behdad Esfahboda177d022012-08-28 23:18:22 -0400642 ligate_input (c,
643 count,
644 &component[1],
645 ligGlyph,
646 match_glyph,
647 NULL,
Behdad Esfahboda177d022012-08-28 23:18:22 -0400648 is_mark_ligature,
649 total_component_count);
Behdad Esfahbodbb3899a2009-05-05 13:25:13 -0400650
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200651 return TRACE_RETURN (true);
Behdad Esfahbodbb3899a2009-05-05 13:25:13 -0400652 }
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500653
Behdad Esfahboda930c682012-09-04 18:17:57 -0400654 inline bool serialize (hb_serialize_context_t *c,
655 GlyphID ligature,
656 Supplier<GlyphID> &components, /* Starting from second */
657 unsigned int num_components /* Including first component */)
658 {
659 TRACE_SERIALIZE ();
660 if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
Behdad Esfahbodfabd3112012-09-05 22:19:28 -0400661 ligGlyph = ligature;
Behdad Esfahboda930c682012-09-04 18:17:57 -0400662 if (unlikely (!component.serialize (c, components, num_components))) return TRACE_RETURN (false);
663 return TRACE_RETURN (true);
664 }
665
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400666 public:
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400667 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400668 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200669 return TRACE_RETURN (ligGlyph.sanitize (c) && component.sanitize (c));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400670 }
671
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400672 protected:
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400673 GlyphID ligGlyph; /* GlyphID of ligature to substitute */
Behdad Esfahbode8cbaaf2009-05-18 02:03:58 -0400674 HeadlessArrayOf<GlyphID>
675 component; /* Array of component GlyphIDs--start
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400676 * with the second component--ordered
677 * in writing direction */
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400678 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400679 DEFINE_SIZE_ARRAY (4, component);
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500680};
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400681
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400682struct LigatureSet
683{
Behdad Esfahbodbb3899a2009-05-05 13:25:13 -0400684 friend struct LigatureSubstFormat1;
685
686 private:
Behdad Esfahbod36608942012-04-19 22:21:38 -0400687
Behdad Esfahbod5caece62012-04-23 23:03:12 -0400688 inline void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400689 {
690 TRACE_CLOSURE ();
Behdad Esfahbodc64ddab2012-04-23 15:28:35 -0400691 unsigned int num_ligs = ligature.len;
692 for (unsigned int i = 0; i < num_ligs; i++)
Behdad Esfahbod5caece62012-04-23 23:03:12 -0400693 (this+ligature[i]).closure (c);
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400694 }
695
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400696 inline bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbod36608942012-04-19 22:21:38 -0400697 {
698 unsigned int num_ligs = ligature.len;
699 for (unsigned int i = 0; i < num_ligs; i++)
700 {
701 const Ligature &lig = this+ligature[i];
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400702 if (lig.would_apply (c))
Behdad Esfahbod36608942012-04-19 22:21:38 -0400703 return true;
704 }
705 return false;
706 }
707
Behdad Esfahbod98370e82010-10-27 17:39:01 -0400708 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400709 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400710 TRACE_APPLY ();
Behdad Esfahbodc9a7cbe2009-05-17 01:22:51 -0400711 unsigned int num_ligs = ligature.len;
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400712 for (unsigned int i = 0; i < num_ligs; i++)
713 {
Behdad Esfahbodc9a7cbe2009-05-17 01:22:51 -0400714 const Ligature &lig = this+ligature[i];
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200715 if (lig.apply (c)) return TRACE_RETURN (true);
Behdad Esfahbodbb3899a2009-05-05 13:25:13 -0400716 }
717
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200718 return TRACE_RETURN (false);
Behdad Esfahbodbb3899a2009-05-05 13:25:13 -0400719 }
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400720
Behdad Esfahboda930c682012-09-04 18:17:57 -0400721 inline bool serialize (hb_serialize_context_t *c,
722 Supplier<GlyphID> &ligatures,
723 Supplier<unsigned int> &component_count_list,
724 unsigned int num_ligatures,
725 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
726 {
727 TRACE_SERIALIZE ();
728 if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
729 if (unlikely (!ligature.serialize (c, num_ligatures))) return TRACE_RETURN (false);
730 for (unsigned int i = 0; i < num_ligatures; i++)
731 if (unlikely (!ligature[i].serialize (c, this).serialize (c,
732 ligatures[i],
733 component_list,
734 component_count_list[i]))) return TRACE_RETURN (false);
Behdad Esfahbodfabd3112012-09-05 22:19:28 -0400735 ligatures.advance (num_ligatures);
Behdad Esfahboda930c682012-09-04 18:17:57 -0400736 component_count_list.advance (num_ligatures);
737 return TRACE_RETURN (true);
738 }
739
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400740 public:
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400741 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400742 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200743 return TRACE_RETURN (ligature.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400744 }
745
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400746 protected:
Behdad Esfahbodc9a7cbe2009-05-17 01:22:51 -0400747 OffsetArrayOf<Ligature>
748 ligature; /* Array LigatureSet tables
749 * ordered by preference */
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400750 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400751 DEFINE_SIZE_ARRAY (2, ligature);
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400752};
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500753
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400754struct LigatureSubstFormat1
755{
Behdad Esfahboda84e71a2009-04-16 16:53:40 -0400756 friend struct LigatureSubst;
757
758 private:
Behdad Esfahbod36608942012-04-19 22:21:38 -0400759
Behdad Esfahbod5caece62012-04-23 23:03:12 -0400760 inline void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400761 {
762 TRACE_CLOSURE ();
Behdad Esfahbodc64ddab2012-04-23 15:28:35 -0400763 Coverage::Iter iter;
764 for (iter.init (this+coverage); iter.more (); iter.next ()) {
765 if (c->glyphs->has (iter.get_glyph ()))
Behdad Esfahbod5caece62012-04-23 23:03:12 -0400766 (this+ligatureSet[iter.get_coverage ()]).closure (c);
Behdad Esfahbodc64ddab2012-04-23 15:28:35 -0400767 }
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400768 }
769
Behdad Esfahbod0b994292012-07-28 17:31:01 -0400770 inline const Coverage &get_coverage (void) const
771 {
772 return this+coverage;
773 }
774
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400775 inline bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbod36608942012-04-19 22:21:38 -0400776 {
Behdad Esfahbod472f2292012-08-07 22:25:24 -0400777 return (this+ligatureSet[(this+coverage) (c->glyphs[0])]).would_apply (c);
Behdad Esfahbod36608942012-04-19 22:21:38 -0400778 }
779
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400780 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400781 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400782 TRACE_APPLY ();
Behdad Esfahbod99c26952012-05-13 15:45:18 +0200783 hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
Behdad Esfahboda84e71a2009-04-16 16:53:40 -0400784
Behdad Esfahbodc9a7cbe2009-05-17 01:22:51 -0400785 unsigned int index = (this+coverage) (glyph_id);
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200786 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -0400787
Behdad Esfahbodc9a7cbe2009-05-17 01:22:51 -0400788 const LigatureSet &lig_set = this+ligatureSet[index];
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200789 return TRACE_RETURN (lig_set.apply (c));
Behdad Esfahboda84e71a2009-04-16 16:53:40 -0400790 }
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500791
Behdad Esfahboda930c682012-09-04 18:17:57 -0400792 inline bool serialize (hb_serialize_context_t *c,
793 Supplier<GlyphID> &first_glyphs,
794 Supplier<unsigned int> &ligature_per_first_glyph_count_list,
795 unsigned int num_first_glyphs,
796 Supplier<GlyphID> &ligatures_list,
797 Supplier<unsigned int> &component_count_list,
798 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
799 {
800 TRACE_SERIALIZE ();
801 if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
Behdad Esfahboda930c682012-09-04 18:17:57 -0400802 if (unlikely (!ligatureSet.serialize (c, num_first_glyphs))) return TRACE_RETURN (false);
803 for (unsigned int i = 0; i < num_first_glyphs; i++)
804 if (unlikely (!ligatureSet[i].serialize (c, this).serialize (c,
805 ligatures_list,
806 component_count_list,
807 ligature_per_first_glyph_count_list[i],
808 component_list))) return TRACE_RETURN (false);
809 ligature_per_first_glyph_count_list.advance (num_first_glyphs);
Behdad Esfahbodfabd3112012-09-05 22:19:28 -0400810 if (unlikely (!coverage.serialize (c, this).serialize (c, first_glyphs, num_first_glyphs))) return TRACE_RETURN (false);
Behdad Esfahboda930c682012-09-04 18:17:57 -0400811 return TRACE_RETURN (true);
812 }
813
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400814 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400815 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200816 return TRACE_RETURN (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400817 }
818
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400819 protected:
Behdad Esfahbodf45107f2009-05-17 20:13:02 -0400820 USHORT format; /* Format identifier--format = 1 */
Behdad Esfahbod238c8552009-05-17 00:22:37 -0400821 OffsetTo<Coverage>
822 coverage; /* Offset to Coverage table--from
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500823 * beginning of Substitution table */
Behdad Esfahbodd79cae02009-05-18 13:50:15 -0400824 OffsetArrayOf<LigatureSet>
Behdad Esfahbodc9a7cbe2009-05-17 01:22:51 -0400825 ligatureSet; /* Array LigatureSet tables
826 * ordered by Coverage Index */
Behdad Esfahbodb3651232010-05-10 16:57:29 -0400827 public:
Behdad Esfahbod0eb9fc62010-05-10 19:01:17 -0400828 DEFINE_SIZE_ARRAY (6, ligatureSet);
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500829};
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500830
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400831struct LigatureSubst
832{
Behdad Esfahboda84e71a2009-04-16 16:53:40 -0400833 friend struct SubstLookupSubTable;
Behdad Esfahbodb3b89b62012-09-04 21:13:17 -0400834 friend struct SubstLookup;
Behdad Esfahboda84e71a2009-04-16 16:53:40 -0400835
836 private:
Behdad Esfahbod36608942012-04-19 22:21:38 -0400837
Behdad Esfahbod5caece62012-04-23 23:03:12 -0400838 inline void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400839 {
840 TRACE_CLOSURE ();
841 switch (u.format) {
Behdad Esfahbod5caece62012-04-23 23:03:12 -0400842 case 1: u.format1.closure (c); break;
843 default: break;
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400844 }
845 }
846
Behdad Esfahbod0b994292012-07-28 17:31:01 -0400847 inline const Coverage &get_coverage (void) const
848 {
849 switch (u.format) {
850 case 1: return u.format1.get_coverage ();
851 default:return Null(Coverage);
852 }
853 }
854
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400855 inline bool would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbod36608942012-04-19 22:21:38 -0400856 {
857 switch (u.format) {
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400858 case 1: return u.format1.would_apply (c);
Behdad Esfahbod36608942012-04-19 22:21:38 -0400859 default:return false;
860 }
861 }
862
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400863 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400864 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400865 TRACE_APPLY ();
Behdad Esfahbodf8dc67b2009-05-17 19:47:54 -0400866 switch (u.format) {
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200867 case 1: return TRACE_RETURN (u.format1.apply (c));
868 default:return TRACE_RETURN (false);
Behdad Esfahboda84e71a2009-04-16 16:53:40 -0400869 }
870 }
871
Behdad Esfahboda930c682012-09-04 18:17:57 -0400872 inline bool serialize (hb_serialize_context_t *c,
873 Supplier<GlyphID> &first_glyphs,
874 Supplier<unsigned int> &ligature_per_first_glyph_count_list,
875 unsigned int num_first_glyphs,
876 Supplier<GlyphID> &ligatures_list,
877 Supplier<unsigned int> &component_count_list,
878 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
879 {
880 TRACE_SERIALIZE ();
881 if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
882 unsigned int format = 1;
883 u.format.set (format);
884 switch (u.format) {
885 case 1: return TRACE_RETURN (u.format1.serialize (c, first_glyphs, ligature_per_first_glyph_count_list, num_first_glyphs,
886 ligatures_list, component_count_list, component_list));
887 default:return TRACE_RETURN (false);
888 }
889 }
890
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400891 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400892 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200893 if (!u.format.sanitize (c)) return TRACE_RETURN (false);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400894 switch (u.format) {
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +0200895 case 1: return TRACE_RETURN (u.format1.sanitize (c));
896 default:return TRACE_RETURN (true);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400897 }
898 }
899
Behdad Esfahbodec8d2492012-07-24 15:40:37 -0400900 protected:
Behdad Esfahboda84e71a2009-04-16 16:53:40 -0400901 union {
Behdad Esfahbodf8dc67b2009-05-17 19:47:54 -0400902 USHORT format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -0400903 LigatureSubstFormat1 format1;
Behdad Esfahboda84e71a2009-04-16 16:53:40 -0400904 } u;
905};
Behdad Esfahboda84e71a2009-04-16 16:53:40 -0400906
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500907
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400908static inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index);
Behdad Esfahbod5caece62012-04-23 23:03:12 -0400909static inline void closure_lookup (hb_closure_context_t *c, unsigned int lookup_index);
Behdad Esfahboda1625522009-05-17 07:52:11 -0400910
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400911struct ContextSubst : Context
912{
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -0400913 friend struct SubstLookupSubTable;
914
915 private:
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400916
Behdad Esfahbod5caece62012-04-23 23:03:12 -0400917 inline void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400918 {
919 TRACE_CLOSURE ();
920 return Context::closure (c, closure_lookup);
921 }
922
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400923 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod0535b502009-08-28 17:14:33 -0400924 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400925 TRACE_APPLY ();
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200926 return TRACE_RETURN (Context::apply (c, substitute_lookup));
Behdad Esfahbod0535b502009-08-28 17:14:33 -0400927 }
Behdad Esfahbodcdb317b2009-05-06 00:12:29 -0400928};
Behdad Esfahbodcdb317b2009-05-06 00:12:29 -0400929
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400930struct ChainContextSubst : ChainContext
931{
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -0400932 friend struct SubstLookupSubTable;
933
934 private:
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400935
Behdad Esfahbod5caece62012-04-23 23:03:12 -0400936 inline void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400937 {
938 TRACE_CLOSURE ();
939 return ChainContext::closure (c, closure_lookup);
940 }
941
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400942 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod0535b502009-08-28 17:14:33 -0400943 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -0400944 TRACE_APPLY ();
Behdad Esfahbodacea1832012-05-11 02:33:11 +0200945 return TRACE_RETURN (ChainContext::apply (c, substitute_lookup));
Behdad Esfahbod0535b502009-08-28 17:14:33 -0400946 }
Behdad Esfahbod9f721cf2009-05-16 19:59:15 -0400947};
Behdad Esfahbod9f721cf2009-05-16 19:59:15 -0400948
Behdad Esfahbod4f27ce72009-04-16 13:40:13 -0400949
Behdad Esfahbod6d08c7f2012-07-11 18:01:27 -0400950struct ExtensionSubst : Extension
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400951{
Behdad Esfahbod4f27ce72009-04-16 13:40:13 -0400952 friend struct SubstLookupSubTable;
Behdad Esfahboda065f472010-04-22 20:15:11 -0400953 friend struct SubstLookup;
Behdad Esfahbod4f27ce72009-04-16 13:40:13 -0400954
955 private:
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400956 inline const struct SubstLookupSubTable& get_subtable (void) const
Behdad Esfahbod3b2c2df2010-04-22 16:51:42 -0400957 {
958 unsigned int offset = get_offset ();
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -0400959 if (unlikely (!offset)) return Null(SubstLookupSubTable);
Behdad Esfahbod09766b12010-05-10 17:36:03 -0400960 return StructAtOffset<SubstLookupSubTable> (this, offset);
Behdad Esfahbod3b2c2df2010-04-22 16:51:42 -0400961 }
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400962
Behdad Esfahbod5caece62012-04-23 23:03:12 -0400963 inline void closure (hb_closure_context_t *c) const;
Behdad Esfahbod0b994292012-07-28 17:31:01 -0400964
965 inline const Coverage &get_coverage (void) const;
966
Behdad Esfahbode72b3602012-07-19 14:35:23 -0400967 inline bool would_apply (hb_would_apply_context_t *c) const;
Behdad Esfahbod36608942012-04-19 22:21:38 -0400968
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400969 inline bool apply (hb_apply_context_t *c) const;
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400970
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -0400971 inline bool sanitize (hb_sanitize_context_t *c);
Behdad Esfahboda065f472010-04-22 20:15:11 -0400972
973 inline bool is_reverse (void) const;
Behdad Esfahbod4f27ce72009-04-16 13:40:13 -0400974};
Behdad Esfahbod4f27ce72009-04-16 13:40:13 -0400975
976
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400977struct ReverseChainSingleSubstFormat1
978{
Behdad Esfahbod969afd72009-05-18 05:47:47 -0400979 friend struct ReverseChainSingleSubst;
980
981 private:
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400982
Behdad Esfahbod5caece62012-04-23 23:03:12 -0400983 inline void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -0400984 {
985 TRACE_CLOSURE ();
Behdad Esfahbodc64ddab2012-04-23 15:28:35 -0400986 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
987
988 unsigned int count;
989
990 count = backtrack.len;
991 for (unsigned int i = 0; i < count; i++)
992 if (!(this+backtrack[i]).intersects (c->glyphs))
Behdad Esfahbod5caece62012-04-23 23:03:12 -0400993 return;
Behdad Esfahbodc64ddab2012-04-23 15:28:35 -0400994
995 count = lookahead.len;
996 for (unsigned int i = 0; i < count; i++)
997 if (!(this+lookahead[i]).intersects (c->glyphs))
Behdad Esfahbod5caece62012-04-23 23:03:12 -0400998 return;
Behdad Esfahbodc64ddab2012-04-23 15:28:35 -0400999
1000 const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
Behdad Esfahbodc64ddab2012-04-23 15:28:35 -04001001 Coverage::Iter iter;
1002 for (iter.init (this+coverage); iter.more (); iter.next ()) {
1003 if (c->glyphs->has (iter.get_glyph ()))
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001004 c->glyphs->add (substitute[iter.get_coverage ()]);
Behdad Esfahbodc64ddab2012-04-23 15:28:35 -04001005 }
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001006 }
1007
Behdad Esfahbod0b994292012-07-28 17:31:01 -04001008 inline const Coverage &get_coverage (void) const
1009 {
1010 return this+coverage;
1011 }
1012
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001013 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001014 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001015 TRACE_APPLY ();
Behdad Esfahbod5df809b2012-05-13 15:17:51 +02001016 if (unlikely (c->nesting_level_left != MAX_NESTING_LEVEL))
1017 return TRACE_RETURN (false); /* No chaining to this type */
Behdad Esfahbod969afd72009-05-18 05:47:47 -04001018
Behdad Esfahbod99c26952012-05-13 15:45:18 +02001019 unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
Behdad Esfahbodacea1832012-05-11 02:33:11 +02001020 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
Behdad Esfahbod969afd72009-05-18 05:47:47 -04001021
Behdad Esfahbode961c862010-04-21 15:56:11 -04001022 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1023 const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
Behdad Esfahbod969afd72009-05-18 05:47:47 -04001024
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001025 if (match_backtrack (c,
Behdad Esfahbodb9615182010-05-10 18:20:54 -04001026 backtrack.len, (USHORT *) backtrack.array,
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04001027 match_coverage, this) &&
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001028 match_lookahead (c,
Behdad Esfahbodb9615182010-05-10 18:20:54 -04001029 lookahead.len, (USHORT *) lookahead.array,
Behdad Esfahbod40cbefe2010-05-10 17:47:22 -04001030 match_coverage, this,
Behdad Esfahbod969afd72009-05-18 05:47:47 -04001031 1))
1032 {
Behdad Esfahbod7fbbf862012-07-30 18:36:42 -04001033 c->replace_glyph_inplace (substitute[index]);
Behdad Esfahbod468e9cb2011-07-22 11:28:07 -04001034 c->buffer->idx--; /* Reverse! */
Behdad Esfahbodacea1832012-05-11 02:33:11 +02001035 return TRACE_RETURN (true);
Behdad Esfahbod969afd72009-05-18 05:47:47 -04001036 }
1037
Behdad Esfahbodacea1832012-05-11 02:33:11 +02001038 return TRACE_RETURN (false);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001039 }
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -05001040
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001041 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001042 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02001043 if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
1044 return TRACE_RETURN (false);
Behdad Esfahbode961c862010-04-21 15:56:11 -04001045 OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001046 if (!lookahead.sanitize (c, this))
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02001047 return TRACE_RETURN (false);
Behdad Esfahbode961c862010-04-21 15:56:11 -04001048 ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02001049 return TRACE_RETURN (substitute.sanitize (c));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001050 }
1051
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001052 protected:
Behdad Esfahbodf45107f2009-05-17 20:13:02 -04001053 USHORT format; /* Format identifier--format = 1 */
Behdad Esfahbod969afd72009-05-18 05:47:47 -04001054 OffsetTo<Coverage>
1055 coverage; /* Offset to Coverage table--from
1056 * beginning of table */
1057 OffsetArrayOf<Coverage>
1058 backtrack; /* Array of coverage tables
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -05001059 * in backtracking sequence, in glyph
1060 * sequence order */
Behdad Esfahbod969afd72009-05-18 05:47:47 -04001061 OffsetArrayOf<Coverage>
1062 lookaheadX; /* Array of coverage tables
1063 * in lookahead sequence, in glyph
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -05001064 * sequence order */
Behdad Esfahbod969afd72009-05-18 05:47:47 -04001065 ArrayOf<GlyphID>
1066 substituteX; /* Array of substitute
1067 * GlyphIDs--ordered by Coverage Index */
Behdad Esfahbodb3651232010-05-10 16:57:29 -04001068 public:
Behdad Esfahbodbea34c72010-05-10 17:28:16 -04001069 DEFINE_SIZE_MIN (10);
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -05001070};
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -05001071
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001072struct ReverseChainSingleSubst
1073{
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001074 friend struct SubstLookupSubTable;
1075
1076 private:
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001077
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001078 inline void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001079 {
1080 TRACE_CLOSURE ();
1081 switch (u.format) {
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001082 case 1: u.format1.closure (c); break;
1083 default: break;
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001084 }
1085 }
1086
Behdad Esfahbod0b994292012-07-28 17:31:01 -04001087 inline const Coverage &get_coverage (void) const
1088 {
1089 switch (u.format) {
1090 case 1: return u.format1.get_coverage ();
1091 default:return Null(Coverage);
1092 }
1093 }
1094
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001095 inline bool apply (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001096 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001097 TRACE_APPLY ();
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001098 switch (u.format) {
Behdad Esfahbodacea1832012-05-11 02:33:11 +02001099 case 1: return TRACE_RETURN (u.format1.apply (c));
1100 default:return TRACE_RETURN (false);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001101 }
1102 }
1103
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001104 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001105 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02001106 if (!u.format.sanitize (c)) return TRACE_RETURN (false);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001107 switch (u.format) {
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02001108 case 1: return TRACE_RETURN (u.format1.sanitize (c));
1109 default:return TRACE_RETURN (true);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001110 }
1111 }
1112
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001113 protected:
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001114 union {
1115 USHORT format; /* Format identifier */
Behdad Esfahboddacebca2010-05-10 19:45:41 -04001116 ReverseChainSingleSubstFormat1 format1;
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001117 } u;
1118};
Behdad Esfahbodca5290f2009-05-17 20:48:27 -04001119
1120
1121
Behdad Esfahbod75860892008-01-23 18:02:28 -05001122/*
Behdad Esfahbod2d15e722009-04-15 19:50:16 -04001123 * SubstLookup
1124 */
1125
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001126struct SubstLookupSubTable
1127{
Behdad Esfahbod2d15e722009-04-15 19:50:16 -04001128 friend struct SubstLookup;
1129
Behdad Esfahbodc6035cf2012-04-12 13:23:59 -04001130 enum Type {
Behdad Esfahbodff05d252009-05-20 03:53:00 -04001131 Single = 1,
1132 Multiple = 2,
1133 Alternate = 3,
1134 Ligature = 4,
1135 Context = 5,
1136 ChainContext = 6,
1137 Extension = 7,
Behdad Esfahbod8f034d52009-08-18 16:41:59 -04001138 ReverseChainSingle = 8
Behdad Esfahbodff05d252009-05-20 03:53:00 -04001139 };
1140
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001141 inline void closure (hb_closure_context_t *c,
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001142 unsigned int lookup_type) const
1143 {
1144 TRACE_CLOSURE ();
1145 switch (lookup_type) {
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001146 case Single: u.single.closure (c); break;
1147 case Multiple: u.multiple.closure (c); break;
1148 case Alternate: u.alternate.closure (c); break;
1149 case Ligature: u.ligature.closure (c); break;
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001150 case Context: u.context.closure (c); break;
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001151 case ChainContext: u.chainContext.closure (c); break;
1152 case Extension: u.extension.closure (c); break;
1153 case ReverseChainSingle: u.reverseChainContextSingle.closure (c); break;
1154 default: break;
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001155 }
1156 }
1157
Behdad Esfahbod0b994292012-07-28 17:31:01 -04001158 inline const Coverage &get_coverage (unsigned int lookup_type) const
Behdad Esfahbodfaf0f202012-06-09 03:02:36 -04001159 {
Behdad Esfahbod0b994292012-07-28 17:31:01 -04001160 switch (lookup_type) {
1161 case Single: return u.single.get_coverage ();
1162 case Multiple: return u.multiple.get_coverage ();
1163 case Alternate: return u.alternate.get_coverage ();
1164 case Ligature: return u.ligature.get_coverage ();
1165 case Context: return u.context.get_coverage ();
1166 case ChainContext: return u.chainContext.get_coverage ();
1167 case Extension: return u.extension.get_coverage ();
1168 case ReverseChainSingle: return u.reverseChainContextSingle.get_coverage ();
1169 default: return Null(Coverage);
1170 }
Behdad Esfahbodfaf0f202012-06-09 03:02:36 -04001171 }
1172
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001173 inline bool would_apply (hb_would_apply_context_t *c,
1174 unsigned int lookup_type) const
1175 {
1176 TRACE_WOULD_APPLY ();
Behdad Esfahbod472f2292012-08-07 22:25:24 -04001177 if (get_coverage (lookup_type).get_coverage (c->glyphs[0]) == NOT_COVERED) return false;
1178 if (c->len == 1) {
1179 switch (lookup_type) {
1180 case Single:
1181 case Multiple:
1182 case Alternate:
1183 case ReverseChainSingle:
1184 return true;
1185 }
1186 }
Behdad Esfahbode6f74792012-07-28 18:34:58 -04001187
1188 /* Only need to look further for lookups that support substitutions
1189 * of input longer than 1. */
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001190 switch (lookup_type) {
Behdad Esfahbod74d1d882012-07-19 16:14:23 -04001191 case Ligature: return u.ligature.would_apply (c);
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001192 case Context: return u.context.would_apply (c);
1193 case ChainContext: return u.chainContext.would_apply (c);
1194 case Extension: return u.extension.would_apply (c);
1195 default: return false;
1196 }
1197 }
1198
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001199 inline bool apply (hb_apply_context_t *c, unsigned int lookup_type) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001200 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001201 TRACE_APPLY ();
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -04001202 switch (lookup_type) {
Behdad Esfahbodacea1832012-05-11 02:33:11 +02001203 case Single: return TRACE_RETURN (u.single.apply (c));
1204 case Multiple: return TRACE_RETURN (u.multiple.apply (c));
1205 case Alternate: return TRACE_RETURN (u.alternate.apply (c));
1206 case Ligature: return TRACE_RETURN (u.ligature.apply (c));
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001207 case Context: return TRACE_RETURN (u.context.apply (c));
Behdad Esfahbodacea1832012-05-11 02:33:11 +02001208 case ChainContext: return TRACE_RETURN (u.chainContext.apply (c));
1209 case Extension: return TRACE_RETURN (u.extension.apply (c));
1210 case ReverseChainSingle: return TRACE_RETURN (u.reverseChainContextSingle.apply (c));
1211 default: return TRACE_RETURN (false);
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -04001212 }
Behdad Esfahbod2d15e722009-04-15 19:50:16 -04001213 }
1214
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001215 inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001216 TRACE_SANITIZE ();
Behdad Esfahbod0b994292012-07-28 17:31:01 -04001217 if (!u.header.sub_format.sanitize (c))
Behdad Esfahbodfaf0f202012-06-09 03:02:36 -04001218 return TRACE_RETURN (false);
Behdad Esfahbodfe9bc072010-05-10 21:39:24 -04001219 switch (lookup_type) {
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02001220 case Single: return TRACE_RETURN (u.single.sanitize (c));
1221 case Multiple: return TRACE_RETURN (u.multiple.sanitize (c));
1222 case Alternate: return TRACE_RETURN (u.alternate.sanitize (c));
1223 case Ligature: return TRACE_RETURN (u.ligature.sanitize (c));
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001224 case Context: return TRACE_RETURN (u.context.sanitize (c));
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02001225 case ChainContext: return TRACE_RETURN (u.chainContext.sanitize (c));
1226 case Extension: return TRACE_RETURN (u.extension.sanitize (c));
1227 case ReverseChainSingle: return TRACE_RETURN (u.reverseChainContextSingle.sanitize (c));
1228 default: return TRACE_RETURN (true);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001229 }
1230 }
1231
Behdad Esfahbodec8d2492012-07-24 15:40:37 -04001232 protected:
Behdad Esfahbod2d15e722009-04-15 19:50:16 -04001233 union {
Behdad Esfahbod993c5192012-06-09 02:48:16 -04001234 struct {
1235 USHORT sub_format;
Behdad Esfahbod993c5192012-06-09 02:48:16 -04001236 } header;
Behdad Esfahboddacebca2010-05-10 19:45:41 -04001237 SingleSubst single;
1238 MultipleSubst multiple;
1239 AlternateSubst alternate;
1240 LigatureSubst ligature;
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001241 ContextSubst context;
Behdad Esfahboddacebca2010-05-10 19:45:41 -04001242 ChainContextSubst chainContext;
1243 ExtensionSubst extension;
1244 ReverseChainSingleSubst reverseChainContextSingle;
Behdad Esfahbod2d15e722009-04-15 19:50:16 -04001245 } u;
Behdad Esfahboded074222010-05-10 18:08:46 -04001246 public:
Behdad Esfahbod993c5192012-06-09 02:48:16 -04001247 DEFINE_SIZE_UNION (2, header.sub_format);
Behdad Esfahbod2d15e722009-04-15 19:50:16 -04001248};
1249
Behdad Esfahbod4f27ce72009-04-16 13:40:13 -04001250
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001251struct SubstLookup : Lookup
1252{
Behdad Esfahbod6d08c7f2012-07-11 18:01:27 -04001253 inline const SubstLookupSubTable& get_subtable (unsigned int i) const
1254 { return this+CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable)[i]; }
Behdad Esfahbod2d15e722009-04-15 19:50:16 -04001255
Behdad Esfahboda065f472010-04-22 20:15:11 -04001256 inline static bool lookup_type_is_reverse (unsigned int lookup_type)
Behdad Esfahbod6d08c7f2012-07-11 18:01:27 -04001257 { return lookup_type == SubstLookupSubTable::ReverseChainSingle; }
Behdad Esfahbod2d15e722009-04-15 19:50:16 -04001258
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001259 inline bool is_reverse (void) const
Behdad Esfahboda065f472010-04-22 20:15:11 -04001260 {
1261 unsigned int type = get_type ();
Behdad Esfahbod6d08c7f2012-07-11 18:01:27 -04001262 if (unlikely (type == SubstLookupSubTable::Extension))
Behdad Esfahbod187454c2010-04-23 16:35:01 -04001263 return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
Behdad Esfahboda065f472010-04-22 20:15:11 -04001264 return lookup_type_is_reverse (type);
1265 }
1266
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001267 inline void closure (hb_closure_context_t *c) const
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001268 {
1269 unsigned int lookup_type = get_type ();
Behdad Esfahbodc64ddab2012-04-23 15:28:35 -04001270 unsigned int count = get_subtable_count ();
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001271 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001272 get_subtable (i).closure (c, lookup_type);
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001273 }
Behdad Esfahbod2d15e722009-04-15 19:50:16 -04001274
Behdad Esfahboda878c582012-08-01 21:18:54 -04001275 template <typename set_t>
1276 inline void add_coverage (set_t *glyphs) const
1277 {
1278 const Coverage *last = NULL;
1279 unsigned int count = get_subtable_count ();
1280 for (unsigned int i = 0; i < count; i++) {
1281 const Coverage *c = &get_subtable (i).get_coverage (get_type ());
1282 if (c != last) {
1283 c->add_coverage (glyphs);
1284 last = c;
1285 }
1286 }
1287 }
1288
Behdad Esfahbod2bd9fe32012-09-04 15:15:19 -04001289 inline bool would_apply (hb_would_apply_context_t *c, const hb_set_digest_t *digest) const
Behdad Esfahbod36608942012-04-19 22:21:38 -04001290 {
Behdad Esfahbod472f2292012-08-07 22:25:24 -04001291 if (unlikely (!c->len)) return false;
Behdad Esfahbod2bd9fe32012-09-04 15:15:19 -04001292 if (!digest->may_have (c->glyphs[0])) return false;
Behdad Esfahbod36608942012-04-19 22:21:38 -04001293 unsigned int lookup_type = get_type ();
1294 unsigned int count = get_subtable_count ();
1295 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001296 if (get_subtable (i).would_apply (c, lookup_type))
Behdad Esfahbod36608942012-04-19 22:21:38 -04001297 return true;
1298 return false;
1299 }
1300
Behdad Esfahbod41ae6742012-04-11 17:11:05 -04001301 inline bool apply_once (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001302 {
Behdad Esfahbod2d15e722009-04-15 19:50:16 -04001303 unsigned int lookup_type = get_type ();
Behdad Esfahbod1376fb72010-04-29 02:19:21 -04001304
Behdad Esfahbod03f67bc2012-07-30 19:47:53 -04001305 if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props, &c->property))
Behdad Esfahbod923923f2009-05-22 17:58:09 -04001306 return false;
Behdad Esfahbod2d15e722009-04-15 19:50:16 -04001307
Behdad Esfahbod29d86442009-08-04 02:27:37 -04001308 unsigned int count = get_subtable_count ();
1309 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001310 if (get_subtable (i).apply (c, lookup_type))
Behdad Esfahbodecf17e82009-05-17 09:34:41 -04001311 return true;
1312
1313 return false;
1314 }
1315
Behdad Esfahbod2bd9fe32012-09-04 15:15:19 -04001316 inline bool apply_string (hb_apply_context_t *c, const hb_set_digest_t *digest) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001317 {
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -04001318 bool ret = false;
1319
Behdad Esfahbod1d3947a2012-09-04 22:42:17 -04001320 if (unlikely (!c->buffer->len || !c->lookup_mask))
Behdad Esfahbod19fc24f2009-05-17 09:45:32 -04001321 return false;
1322
Behdad Esfahbod650ac002012-04-23 13:17:09 -04001323 c->set_lookup (*this);
Behdad Esfahbod41ae6742012-04-11 17:11:05 -04001324
Behdad Esfahbod64d3fc82010-05-03 22:51:19 -04001325 if (likely (!is_reverse ()))
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001326 {
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -04001327 /* in/out forward substitution */
Behdad Esfahbod650ac002012-04-23 13:17:09 -04001328 c->buffer->clear_output ();
1329 c->buffer->idx = 0;
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -04001330
Behdad Esfahbod1336ecd2012-08-01 21:46:36 -04001331 while (c->buffer->idx < c->buffer->len)
1332 {
1333 if ((c->buffer->cur().mask & c->lookup_mask) &&
Behdad Esfahbod2bd9fe32012-09-04 15:15:19 -04001334 digest->may_have (c->buffer->cur().codepoint) &&
Behdad Esfahbod1336ecd2012-08-01 21:46:36 -04001335 apply_once (c))
1336 ret = true;
1337 else
1338 c->buffer->next_glyph ();
1339 }
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -04001340 if (ret)
Behdad Esfahbod650ac002012-04-23 13:17:09 -04001341 c->buffer->swap_buffers ();
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001342 }
1343 else
1344 {
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -04001345 /* in-place backward substitution */
Behdad Esfahbod0bc7a382012-10-29 22:02:45 -07001346 c->buffer->remove_output ();
Behdad Esfahbod650ac002012-04-23 13:17:09 -04001347 c->buffer->idx = c->buffer->len - 1;
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001348 do
1349 {
Behdad Esfahbod1336ecd2012-08-01 21:46:36 -04001350 if ((c->buffer->cur().mask & c->lookup_mask) &&
Behdad Esfahbod2bd9fe32012-09-04 15:15:19 -04001351 digest->may_have (c->buffer->cur().codepoint) &&
Behdad Esfahbod1336ecd2012-08-01 21:46:36 -04001352 apply_once (c))
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -04001353 ret = true;
1354 else
Behdad Esfahbod650ac002012-04-23 13:17:09 -04001355 c->buffer->idx--;
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -04001356
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001357 }
Behdad Esfahbod650ac002012-04-23 13:17:09 -04001358 while ((int) c->buffer->idx >= 0);
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -04001359 }
1360
1361 return ret;
1362 }
Behdad Esfahbod29d86442009-08-04 02:27:37 -04001363
Behdad Esfahbodb3b89b62012-09-04 21:13:17 -04001364 private:
1365 inline SubstLookupSubTable& serialize_subtable (hb_serialize_context_t *c,
1366 unsigned int i)
1367 { return CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable)[i].serialize (c, this); }
1368 public:
1369
1370 inline bool serialize_single (hb_serialize_context_t *c,
1371 uint32_t lookup_props,
1372 Supplier<GlyphID> &glyphs,
1373 Supplier<GlyphID> &substitutes,
1374 unsigned int num_glyphs)
1375 {
1376 TRACE_SERIALIZE ();
1377 if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Single, lookup_props, 1))) return TRACE_RETURN (false);
1378 return TRACE_RETURN (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes, num_glyphs));
1379 }
1380
1381 inline bool serialize_multiple (hb_serialize_context_t *c,
1382 uint32_t lookup_props,
1383 Supplier<GlyphID> &glyphs,
1384 Supplier<unsigned int> &substitute_len_list,
1385 unsigned int num_glyphs,
1386 Supplier<GlyphID> &substitute_glyphs_list)
1387 {
1388 TRACE_SERIALIZE ();
1389 if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Multiple, lookup_props, 1))) return TRACE_RETURN (false);
1390 return TRACE_RETURN (serialize_subtable (c, 0).u.multiple.serialize (c, glyphs, substitute_len_list, num_glyphs,
1391 substitute_glyphs_list));
1392 }
1393
1394 inline bool serialize_alternate (hb_serialize_context_t *c,
1395 uint32_t lookup_props,
1396 Supplier<GlyphID> &glyphs,
1397 Supplier<unsigned int> &alternate_len_list,
1398 unsigned int num_glyphs,
1399 Supplier<GlyphID> &alternate_glyphs_list)
1400 {
1401 TRACE_SERIALIZE ();
1402 if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Alternate, lookup_props, 1))) return TRACE_RETURN (false);
1403 return TRACE_RETURN (serialize_subtable (c, 0).u.alternate.serialize (c, glyphs, alternate_len_list, num_glyphs,
1404 alternate_glyphs_list));
1405 }
1406
1407 inline bool serialize_ligature (hb_serialize_context_t *c,
1408 uint32_t lookup_props,
1409 Supplier<GlyphID> &first_glyphs,
1410 Supplier<unsigned int> &ligature_per_first_glyph_count_list,
1411 unsigned int num_first_glyphs,
1412 Supplier<GlyphID> &ligatures_list,
1413 Supplier<unsigned int> &component_count_list,
1414 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
1415 {
1416 TRACE_SERIALIZE ();
1417 if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Ligature, lookup_props, 1))) return TRACE_RETURN (false);
1418 return TRACE_RETURN (serialize_subtable (c, 0).u.ligature.serialize (c, first_glyphs, ligature_per_first_glyph_count_list, num_first_glyphs,
1419 ligatures_list, component_count_list, component_list));
1420 }
1421
1422 inline bool sanitize (hb_sanitize_context_t *c)
1423 {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001424 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02001425 if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false);
Behdad Esfahbod6d08c7f2012-07-11 18:01:27 -04001426 OffsetArrayOf<SubstLookupSubTable> &list = CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable);
Behdad Esfahbod338fe662012-07-28 18:53:01 -04001427 if (unlikely (!list.sanitize (c, this, get_type ()))) return TRACE_RETURN (false);
1428
1429 if (unlikely (get_type () == SubstLookupSubTable::Extension))
1430 {
1431 /* The spec says all subtables of an Extension lookup should
1432 * have the same type. This is specially important if one has
1433 * a reverse type!
1434 *
1435 * We just check that they are all either forward, or reverse. */
1436 unsigned int type = get_subtable (0).u.extension.get_type ();
1437 unsigned int count = get_subtable_count ();
1438 for (unsigned int i = 1; i < count; i++)
1439 if (get_subtable (i).u.extension.get_type () != type)
1440 return TRACE_RETURN (false);
1441 }
1442 return TRACE_RETURN (true);
Behdad Esfahbod29d86442009-08-04 02:27:37 -04001443 }
Behdad Esfahbod2d15e722009-04-15 19:50:16 -04001444};
Behdad Esfahbod2d15e722009-04-15 19:50:16 -04001445
Behdad Esfahbod29d86442009-08-04 02:27:37 -04001446typedef OffsetListOf<SubstLookup> SubstLookupList;
Behdad Esfahbodc43562b2009-05-15 18:54:53 -04001447
Behdad Esfahbod2d15e722009-04-15 19:50:16 -04001448/*
Behdad Esfahbodae9877d2011-08-17 14:43:45 +02001449 * GSUB -- The Glyph Substitution Table
Behdad Esfahbod75860892008-01-23 18:02:28 -05001450 */
1451
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001452struct GSUB : GSUBGPOS
1453{
Behdad Esfahboda328d662009-08-04 20:27:05 -04001454 static const hb_tag_t Tag = HB_OT_TAG_GSUB;
Behdad Esfahbod75860892008-01-23 18:02:28 -05001455
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001456 inline const SubstLookup& get_lookup (unsigned int i) const
Behdad Esfahbod187454c2010-04-23 16:35:01 -04001457 { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
Behdad Esfahbod2d15e722009-04-15 19:50:16 -04001458
Behdad Esfahboda878c582012-08-01 21:18:54 -04001459 template <typename set_t>
1460 inline void add_coverage (set_t *glyphs, unsigned int lookup_index) const
1461 { get_lookup (lookup_index).add_coverage (glyphs); }
1462
Behdad Esfahbodafbcc242012-08-02 08:36:40 -04001463 static inline void substitute_start (hb_font_t *font, hb_buffer_t *buffer);
1464 static inline void substitute_finish (hb_font_t *font, hb_buffer_t *buffer);
Behdad Esfahboda9ad3d32011-07-28 15:42:18 -04001465
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001466 inline void closure_lookup (hb_closure_context_t *c,
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001467 unsigned int lookup_index) const
1468 { return get_lookup (lookup_index).closure (c); }
1469
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001470 inline bool sanitize (hb_sanitize_context_t *c) {
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001471 TRACE_SANITIZE ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02001472 if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false);
Behdad Esfahbod187454c2010-04-23 16:35:01 -04001473 OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02001474 return TRACE_RETURN (list.sanitize (c, this));
Behdad Esfahbod29d86442009-08-04 02:27:37 -04001475 }
Behdad Esfahbodb3651232010-05-10 16:57:29 -04001476 public:
1477 DEFINE_SIZE_STATIC (10);
Behdad Esfahbod75860892008-01-23 18:02:28 -05001478};
Behdad Esfahbodc43562b2009-05-15 18:54:53 -04001479
1480
Behdad Esfahboda9ad3d32011-07-28 15:42:18 -04001481void
Behdad Esfahbodafbcc242012-08-02 08:36:40 -04001482GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer)
Behdad Esfahboda9ad3d32011-07-28 15:42:18 -04001483{
Behdad Esfahbodc2e42c32012-07-30 19:54:50 -04001484 HB_BUFFER_ALLOCATE_VAR (buffer, glyph_props);
Behdad Esfahboda9844d42012-05-09 17:53:13 +02001485 HB_BUFFER_ALLOCATE_VAR (buffer, lig_props);
Behdad Esfahbodcee71872012-05-11 11:41:39 +02001486 HB_BUFFER_ALLOCATE_VAR (buffer, syllable);
Behdad Esfahbodb65c0602011-07-28 16:48:43 -04001487
Behdad Esfahbodafbcc242012-08-02 08:36:40 -04001488 const GDEF &gdef = *hb_ot_layout_from_face (font->face)->gdef;
Behdad Esfahboda9ad3d32011-07-28 15:42:18 -04001489 unsigned int count = buffer->len;
Behdad Esfahbod05bd1b62012-07-30 19:30:01 -04001490 for (unsigned int i = 0; i < count; i++) {
1491 buffer->info[i].lig_props() = buffer->info[i].syllable() = 0;
Behdad Esfahbodc2e42c32012-07-30 19:54:50 -04001492 buffer->info[i].glyph_props() = gdef.get_glyph_props (buffer->info[i].codepoint);
Behdad Esfahbod05bd1b62012-07-30 19:30:01 -04001493 }
Behdad Esfahboda9ad3d32011-07-28 15:42:18 -04001494}
1495
1496void
Behdad Esfahbodafbcc242012-08-02 08:36:40 -04001497GSUB::substitute_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSED)
Behdad Esfahboda9ad3d32011-07-28 15:42:18 -04001498{
1499}
1500
1501
Behdad Esfahbod887c4b42009-05-17 21:06:08 -04001502/* Out-of-class implementation for methods recursing */
Behdad Esfahbodc43562b2009-05-15 18:54:53 -04001503
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001504inline void ExtensionSubst::closure (hb_closure_context_t *c) const
Behdad Esfahbodc64ddab2012-04-23 15:28:35 -04001505{
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001506 get_subtable ().closure (c, get_type ());
Behdad Esfahbodc64ddab2012-04-23 15:28:35 -04001507}
1508
Behdad Esfahbod0b994292012-07-28 17:31:01 -04001509inline const Coverage & ExtensionSubst::get_coverage (void) const
1510{
1511 return get_subtable ().get_coverage (get_type ());
1512}
1513
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001514inline bool ExtensionSubst::would_apply (hb_would_apply_context_t *c) const
Behdad Esfahbod36608942012-04-19 22:21:38 -04001515{
Behdad Esfahbode72b3602012-07-19 14:35:23 -04001516 return get_subtable ().would_apply (c, get_type ());
Behdad Esfahbod36608942012-04-19 22:21:38 -04001517}
1518
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001519inline bool ExtensionSubst::apply (hb_apply_context_t *c) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001520{
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001521 TRACE_APPLY ();
Behdad Esfahbodacea1832012-05-11 02:33:11 +02001522 return TRACE_RETURN (get_subtable ().apply (c, get_type ()));
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001523}
1524
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001525inline bool ExtensionSubst::sanitize (hb_sanitize_context_t *c)
Behdad Esfahbod70de50c2009-08-04 00:58:28 -04001526{
Behdad Esfahbod3e2401f2009-08-28 17:17:11 -04001527 TRACE_SANITIZE ();
Behdad Esfahbod6d08c7f2012-07-11 18:01:27 -04001528 if (unlikely (!Extension::sanitize (c))) return TRACE_RETURN (false);
Behdad Esfahbod3b2c2df2010-04-22 16:51:42 -04001529 unsigned int offset = get_offset ();
Behdad Esfahbod0ab8c862012-05-11 01:25:34 +02001530 if (unlikely (!offset)) return TRACE_RETURN (true);
Behdad Esfahbod6d08c7f2012-07-11 18:01:27 -04001531 return TRACE_RETURN (StructAtOffset<SubstLookupSubTable> (this, offset).sanitize (c, get_type ()));
Behdad Esfahbodc43562b2009-05-15 18:54:53 -04001532}
1533
Behdad Esfahboda065f472010-04-22 20:15:11 -04001534inline bool ExtensionSubst::is_reverse (void) const
1535{
1536 unsigned int type = get_type ();
Behdad Esfahbod6d08c7f2012-07-11 18:01:27 -04001537 if (unlikely (type == SubstLookupSubTable::Extension))
Behdad Esfahbod187454c2010-04-23 16:35:01 -04001538 return CastR<ExtensionSubst> (get_subtable()).is_reverse ();
Behdad Esfahboda065f472010-04-22 20:15:11 -04001539 return SubstLookup::lookup_type_is_reverse (type);
1540}
1541
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001542static inline void closure_lookup (hb_closure_context_t *c, unsigned int lookup_index)
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001543{
Behdad Esfahbodea278d32012-07-27 02:12:28 -04001544 const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001545 const SubstLookup &l = gsub.get_lookup (lookup_index);
1546
1547 if (unlikely (c->nesting_level_left == 0))
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001548 return;
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001549
1550 c->nesting_level_left--;
Behdad Esfahbod5caece62012-04-23 23:03:12 -04001551 l.closure (c);
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001552 c->nesting_level_left++;
Behdad Esfahbodf94b0aa2012-04-23 13:04:38 -04001553}
1554
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001555static inline bool substitute_lookup (hb_apply_context_t *c, unsigned int lookup_index)
Behdad Esfahbod4c44d832009-05-19 23:42:30 -04001556{
Behdad Esfahbodea278d32012-07-27 02:12:28 -04001557 const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
Behdad Esfahboda1625522009-05-17 07:52:11 -04001558 const SubstLookup &l = gsub.get_lookup (lookup_index);
Behdad Esfahbodc43562b2009-05-15 18:54:53 -04001559
Behdad Esfahbodd7cfb3b2010-05-13 14:18:49 -04001560 if (unlikely (c->nesting_level_left == 0))
Behdad Esfahbodeca8e332009-05-17 09:07:27 -04001561 return false;
Behdad Esfahbodeca8e332009-05-17 09:07:27 -04001562
Behdad Esfahbod650ac002012-04-23 13:17:09 -04001563 hb_apply_context_t new_c (*c);
1564 new_c.nesting_level_left--;
1565 new_c.set_lookup (l);
Behdad Esfahbod41ae6742012-04-11 17:11:05 -04001566 return l.apply_once (&new_c);
Behdad Esfahbodc43562b2009-05-15 18:54:53 -04001567}
1568
1569
Behdad Esfahbod7c8e8442012-08-28 17:57:49 -04001570} // namespace OT
1571
Behdad Esfahbodacdba3f2010-07-23 15:11:18 -04001572
Behdad Esfahbod7a750ac2011-08-17 14:19:59 +02001573#endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */