blob: 4d21f658743fc64b943ce7bb39b5373c83542c2d [file] [log] [blame]
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -05001/*
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -04002 * Copyright (C) 2007,2008,2009 Red Hat, Inc.
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -05003 *
4 * This is part of HarfBuzz, an OpenType Layout engine library.
5 *
6 * Permission is hereby granted, without written agreement and without
7 * license or royalty fees, to use, copy, modify, and distribute this
8 * software and its documentation for any purpose, provided that the
9 * above copyright notice and the following two paragraphs appear in
10 * all copies of this software.
11 *
12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16 * DAMAGE.
17 *
18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23 *
24 * Red Hat Author(s): Behdad Esfahbod
25 */
26
Behdad Esfahbod5f5b24f2009-08-02 20:03:12 -040027#ifndef HB_OT_LAYOUT_GSUB_PRIVATE_HH
28#define HB_OT_LAYOUT_GSUB_PRIVATE_HH
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -050029
Behdad Esfahbod5f5b24f2009-08-02 20:03:12 -040030#include "hb-ot-layout-gsubgpos-private.hh"
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -050031
Behdad Esfahbod6f20f722009-05-17 20:28:01 -040032
Behdad Esfahbod4c44d832009-05-19 23:42:30 -040033struct SingleSubstFormat1
34{
Behdad Esfahbod2d15e722009-04-15 19:50:16 -040035 friend struct SingleSubst;
36
37 private:
Behdad Esfahbod70de50c2009-08-04 00:58:28 -040038
Behdad Esfahbod4c44d832009-05-19 23:42:30 -040039 inline bool apply (APPLY_ARG_DEF) const
40 {
41 hb_codepoint_t glyph_id = IN_CURGLYPH ();
Behdad Esfahbod238c8552009-05-17 00:22:37 -040042 unsigned int index = (this+coverage) (glyph_id);
Behdad Esfahbod4acaffd2009-05-18 05:29:29 -040043 if (HB_LIKELY (index == NOT_COVERED))
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -040044 return false;
45
46 glyph_id += deltaGlyphID;
Behdad Esfahbod4c44d832009-05-19 23:42:30 -040047 _hb_buffer_replace_glyph (buffer, glyph_id);
48
Behdad Esfahbod4189b922009-05-26 17:31:56 -040049 /* We inherit the old glyph class to the substituted glyph */
Behdad Esfahbod23c86aa2009-08-03 21:40:20 -040050 if (_hb_ot_layout_has_new_glyph_classes (context->face))
51 _hb_ot_layout_set_glyph_property (context->face, glyph_id, property);
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -040052
53 return true;
54 }
55
Behdad Esfahbod70de50c2009-08-04 00:58:28 -040056 inline bool sanitize (SANITIZE_ARG_DEF) {
57 return SANITIZE_THIS (coverage) && SANITIZE (deltaGlyphID);
58 }
59
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -040060 private:
Behdad Esfahbodf45107f2009-05-17 20:13:02 -040061 USHORT format; /* Format identifier--format = 1 */
Behdad Esfahbod238c8552009-05-17 00:22:37 -040062 OffsetTo<Coverage>
63 coverage; /* Offset to Coverage table--from
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -040064 * beginning of Substitution table */
65 SHORT deltaGlyphID; /* Add to original GlyphID to get
66 * substitute GlyphID */
67};
68ASSERT_SIZE (SingleSubstFormat1, 6);
69
Behdad Esfahbod4c44d832009-05-19 23:42:30 -040070struct SingleSubstFormat2
71{
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -040072 friend struct SingleSubst;
73
74 private:
Behdad Esfahbod70de50c2009-08-04 00:58:28 -040075
Behdad Esfahbod4c44d832009-05-19 23:42:30 -040076 inline bool apply (APPLY_ARG_DEF) const
77 {
78 hb_codepoint_t glyph_id = IN_CURGLYPH ();
Behdad Esfahbod238c8552009-05-17 00:22:37 -040079 unsigned int index = (this+coverage) (glyph_id);
Behdad Esfahbod4acaffd2009-05-18 05:29:29 -040080 if (HB_LIKELY (index == NOT_COVERED))
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -040081 return false;
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -040082
Behdad Esfahbod4acaffd2009-05-18 05:29:29 -040083 if (HB_UNLIKELY (index >= substitute.len))
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -040084 return false;
85
86 glyph_id = substitute[index];
Behdad Esfahbod4c44d832009-05-19 23:42:30 -040087 _hb_buffer_replace_glyph (buffer, glyph_id);
88
Behdad Esfahbod4189b922009-05-26 17:31:56 -040089 /* We inherit the old glyph class to the substituted glyph */
Behdad Esfahbod23c86aa2009-08-03 21:40:20 -040090 if (_hb_ot_layout_has_new_glyph_classes (context->face))
91 _hb_ot_layout_set_glyph_property (context->face, glyph_id, property);
Behdad Esfahbod4c44d832009-05-19 23:42:30 -040092
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -040093 return true;
94 }
95
Behdad Esfahbod70de50c2009-08-04 00:58:28 -040096 inline bool sanitize (SANITIZE_ARG_DEF) {
97 return SANITIZE_THIS (coverage) && SANITIZE (substitute);
98 }
99
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400100 private:
Behdad Esfahbodf45107f2009-05-17 20:13:02 -0400101 USHORT format; /* Format identifier--format = 2 */
Behdad Esfahbod238c8552009-05-17 00:22:37 -0400102 OffsetTo<Coverage>
103 coverage; /* Offset to Coverage table--from
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400104 * beginning of Substitution table */
Behdad Esfahbodc9a7cbe2009-05-17 01:22:51 -0400105 ArrayOf<GlyphID>
106 substitute; /* Array of substitute
107 * GlyphIDs--ordered by Coverage Index */
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400108};
109ASSERT_SIZE (SingleSubstFormat2, 6);
110
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400111struct SingleSubst
112{
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400113 friend struct SubstLookupSubTable;
114
Behdad Esfahbod4f27ce72009-04-16 13:40:13 -0400115 private:
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400116
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400117 inline bool apply (APPLY_ARG_DEF) const
118 {
Behdad Esfahbodf8dc67b2009-05-17 19:47:54 -0400119 switch (u.format) {
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400120 case 1: return u.format1->apply (APPLY_ARG);
121 case 2: return u.format2->apply (APPLY_ARG);
Behdad Esfahbod38b011a2009-05-04 20:21:57 -0400122 default:return false;
123 }
124 }
125
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400126 inline bool sanitize (SANITIZE_ARG_DEF) {
127 if (!SANITIZE (u.format)) return false;
128 switch (u.format) {
129 case 1: return u.format1->sanitize (SANITIZE_ARG);
130 case 2: return u.format2->sanitize (SANITIZE_ARG);
131 default:return true;
132 }
133 }
134
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400135 private:
136 union {
Behdad Esfahbodf8dc67b2009-05-17 19:47:54 -0400137 USHORT format; /* Format identifier */
138 SingleSubstFormat1 format1[];
139 SingleSubstFormat2 format2[];
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400140 } u;
141};
Behdad Esfahbodf8dc67b2009-05-17 19:47:54 -0400142ASSERT_SIZE (SingleSubst, 2);
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400143
144
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400145struct Sequence
146{
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400147 friend struct MultipleSubstFormat1;
148
149 private:
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400150 inline bool apply (APPLY_ARG_DEF) const
151 {
Behdad Esfahbodc9a7cbe2009-05-17 01:22:51 -0400152 if (HB_UNLIKELY (!substitute.len))
Behdad Esfahbodc9c6a782009-05-05 16:22:02 -0400153 return false;
154
Behdad Esfahbod88a5f5a2009-05-25 03:39:11 -0400155 _hb_buffer_add_output_glyphs (buffer, 1,
156 substitute.len, (const uint16_t *) substitute.array,
157 0xFFFF, 0xFFFF);
Behdad Esfahbodc9c6a782009-05-05 16:22:02 -0400158
Behdad Esfahbod4189b922009-05-26 17:31:56 -0400159 /* This is a guess only ... */
Behdad Esfahbod23c86aa2009-08-03 21:40:20 -0400160 if (_hb_ot_layout_has_new_glyph_classes (context->face))
Behdad Esfahbodc9c6a782009-05-05 16:22:02 -0400161 {
Behdad Esfahbod4189b922009-05-26 17:31:56 -0400162 if (property == HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE)
Behdad Esfahbodc9c6a782009-05-05 16:22:02 -0400163 property = HB_OT_LAYOUT_GLYPH_CLASS_BASE_GLYPH;
164
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -0400165 unsigned int count = substitute.len;
166 for (unsigned int n = 0; n < count; n++)
Behdad Esfahbod23c86aa2009-08-03 21:40:20 -0400167 _hb_ot_layout_set_glyph_property (context->face, substitute[n], property);
Behdad Esfahbodc9c6a782009-05-05 16:22:02 -0400168 }
169
170 return true;
171 }
172
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400173 public:
174 inline bool sanitize (SANITIZE_ARG_DEF) {
175 return SANITIZE (substitute);
176 }
177
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400178 private:
Behdad Esfahbodc9a7cbe2009-05-17 01:22:51 -0400179 ArrayOf<GlyphID>
180 substitute; /* String of GlyphIDs to substitute */
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400181};
Behdad Esfahbod8b835802009-05-16 22:48:14 -0400182ASSERT_SIZE (Sequence, 2);
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400183
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400184struct MultipleSubstFormat1
185{
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400186 friend struct MultipleSubst;
187
188 private:
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400189
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400190 inline bool apply (APPLY_ARG_DEF) const
191 {
Behdad Esfahbod30bd7632009-04-15 22:56:15 -0400192
Behdad Esfahbodc9a7cbe2009-05-17 01:22:51 -0400193 unsigned int index = (this+coverage) (IN_CURGLYPH ());
Behdad Esfahbod4acaffd2009-05-18 05:29:29 -0400194 if (HB_LIKELY (index == NOT_COVERED))
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -0400195 return false;
196
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -0400197 return (this+sequence[index]).apply (APPLY_ARG);
Behdad Esfahbod2d15e722009-04-15 19:50:16 -0400198 }
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500199
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400200 inline bool sanitize (SANITIZE_ARG_DEF) {
201 return SANITIZE_THIS2 (coverage, sequence);
202 }
203
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500204 private:
Behdad Esfahbodf45107f2009-05-17 20:13:02 -0400205 USHORT format; /* Format identifier--format = 1 */
Behdad Esfahbod238c8552009-05-17 00:22:37 -0400206 OffsetTo<Coverage>
207 coverage; /* Offset to Coverage table--from
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500208 * beginning of Substitution table */
Behdad Esfahbodc9a7cbe2009-05-17 01:22:51 -0400209 OffsetArrayOf<Sequence>
210 sequence; /* Array of Sequence tables
211 * ordered by Coverage Index */
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500212};
213ASSERT_SIZE (MultipleSubstFormat1, 6);
214
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400215struct MultipleSubst
216{
Behdad Esfahbod4f27ce72009-04-16 13:40:13 -0400217 friend struct SubstLookupSubTable;
218
219 private:
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400220
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400221 inline bool apply (APPLY_ARG_DEF) const
222 {
Behdad Esfahbodf8dc67b2009-05-17 19:47:54 -0400223 switch (u.format) {
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -0400224 case 1: return u.format1->apply (APPLY_ARG);
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400225 default:return false;
226 }
227 }
228
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400229 inline bool sanitize (SANITIZE_ARG_DEF) {
230 if (!SANITIZE (u.format)) return false;
231 switch (u.format) {
232 case 1: return u.format1->sanitize (SANITIZE_ARG);
233 default:return true;
234 }
235 }
236
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400237 private:
238 union {
Behdad Esfahbodf8dc67b2009-05-17 19:47:54 -0400239 USHORT format; /* Format identifier */
240 MultipleSubstFormat1 format1[];
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400241 } u;
242};
Behdad Esfahbodf8dc67b2009-05-17 19:47:54 -0400243ASSERT_SIZE (MultipleSubst, 2);
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400244
245
Behdad Esfahbodc9a7cbe2009-05-17 01:22:51 -0400246typedef ArrayOf<GlyphID> AlternateSet; /* Array of alternate GlyphIDs--in
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400247 * arbitrary order */
Behdad Esfahbod8b835802009-05-16 22:48:14 -0400248ASSERT_SIZE (AlternateSet, 2);
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500249
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400250struct AlternateSubstFormat1
251{
Behdad Esfahbod52886ca2009-04-16 14:19:42 -0400252 friend struct AlternateSubst;
253
254 private:
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400255
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400256 inline bool apply (APPLY_ARG_DEF) const
257 {
Behdad Esfahboda84e71a2009-04-16 16:53:40 -0400258 hb_codepoint_t glyph_id = IN_CURGLYPH ();
Behdad Esfahbod52886ca2009-04-16 14:19:42 -0400259
Behdad Esfahbod238c8552009-05-17 00:22:37 -0400260 unsigned int index = (this+coverage) (glyph_id);
Behdad Esfahbod4acaffd2009-05-18 05:29:29 -0400261 if (HB_LIKELY (index == NOT_COVERED))
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -0400262 return false;
263
Behdad Esfahbodc9a7cbe2009-05-17 01:22:51 -0400264 const AlternateSet &alt_set = this+alternateSet[index];
Behdad Esfahbod52886ca2009-04-16 14:19:42 -0400265
Behdad Esfahbodc9a7cbe2009-05-17 01:22:51 -0400266 if (HB_UNLIKELY (!alt_set.len))
Behdad Esfahbod52886ca2009-04-16 14:19:42 -0400267 return false;
268
269 unsigned int alt_index = 0;
270
271 /* XXX callback to user to choose alternate
Behdad Esfahbod23c86aa2009-08-03 21:40:20 -0400272 if (context->face->altfunc)
273 alt_index = (context->face->altfunc)(context->layout, buffer,
Behdad Esfahbodd6aae5f2009-05-18 04:25:22 -0400274 buffer->out_pos, glyph_id,
275 alt_set.len, alt_set.array);
Behdad Esfahbod52886ca2009-04-16 14:19:42 -0400276 */
277
Behdad Esfahbodc9a7cbe2009-05-17 01:22:51 -0400278 if (HB_UNLIKELY (alt_index >= alt_set.len))
Behdad Esfahbod52886ca2009-04-16 14:19:42 -0400279 return false;
280
281 glyph_id = alt_set[alt_index];
282
Behdad Esfahbod15c3e752009-05-17 06:03:42 -0400283 _hb_buffer_replace_glyph (buffer, glyph_id);
Behdad Esfahbod52886ca2009-04-16 14:19:42 -0400284
Behdad Esfahbod4189b922009-05-26 17:31:56 -0400285 /* We inherit the old glyph class to the substituted glyph */
Behdad Esfahbod23c86aa2009-08-03 21:40:20 -0400286 if (_hb_ot_layout_has_new_glyph_classes (context->face))
287 _hb_ot_layout_set_glyph_property (context->face, glyph_id, property);
Behdad Esfahbod52886ca2009-04-16 14:19:42 -0400288
289 return true;
290 }
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500291
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400292 inline bool sanitize (SANITIZE_ARG_DEF) {
293 return SANITIZE_THIS2 (coverage, alternateSet);
294 }
295
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500296 private:
Behdad Esfahbodf45107f2009-05-17 20:13:02 -0400297 USHORT format; /* Format identifier--format = 1 */
Behdad Esfahbod238c8552009-05-17 00:22:37 -0400298 OffsetTo<Coverage>
299 coverage; /* Offset to Coverage table--from
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500300 * beginning of Substitution table */
Behdad Esfahbodc9a7cbe2009-05-17 01:22:51 -0400301 OffsetArrayOf<AlternateSet>
302 alternateSet; /* Array of AlternateSet tables
303 * ordered by Coverage Index */
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500304};
305ASSERT_SIZE (AlternateSubstFormat1, 6);
306
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400307struct AlternateSubst
308{
Behdad Esfahbod52886ca2009-04-16 14:19:42 -0400309 friend struct SubstLookupSubTable;
310
311 private:
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400312
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400313 inline bool apply (APPLY_ARG_DEF) const
314 {
Behdad Esfahbodf8dc67b2009-05-17 19:47:54 -0400315 switch (u.format) {
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -0400316 case 1: return u.format1->apply (APPLY_ARG);
Behdad Esfahbod52886ca2009-04-16 14:19:42 -0400317 default:return false;
318 }
319 }
320
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400321 inline bool sanitize (SANITIZE_ARG_DEF) {
322 if (!SANITIZE (u.format)) return false;
323 switch (u.format) {
324 case 1: return u.format1->sanitize (SANITIZE_ARG);
325 default:return true;
326 }
327 }
328
Behdad Esfahbod52886ca2009-04-16 14:19:42 -0400329 private:
330 union {
Behdad Esfahbodf8dc67b2009-05-17 19:47:54 -0400331 USHORT format; /* Format identifier */
332 AlternateSubstFormat1 format1[];
Behdad Esfahbod52886ca2009-04-16 14:19:42 -0400333 } u;
334};
Behdad Esfahbodf8dc67b2009-05-17 19:47:54 -0400335ASSERT_SIZE (AlternateSubst, 2);
Behdad Esfahbod52886ca2009-04-16 14:19:42 -0400336
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400337
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400338struct Ligature
339{
Behdad Esfahbodbb3899a2009-05-05 13:25:13 -0400340 friend struct LigatureSet;
341
342 private:
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400343 inline bool apply (APPLY_ARG_DEF, bool is_mark) const
344 {
Behdad Esfahbodbb3899a2009-05-05 13:25:13 -0400345 unsigned int i, j;
Behdad Esfahbode8cbaaf2009-05-18 02:03:58 -0400346 unsigned int count = component.len;
Behdad Esfahbod122f21f2009-05-18 04:21:53 -0400347 unsigned int end = MIN (buffer->in_length, buffer->in_pos + context_length);
348 if (HB_UNLIKELY (buffer->in_pos + count > end))
349 return false;
Behdad Esfahbodbb3899a2009-05-05 13:25:13 -0400350
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400351 for (i = 1, j = buffer->in_pos + 1; i < count; i++, j++)
352 {
Behdad Esfahbod23c86aa2009-08-03 21:40:20 -0400353 while (_hb_ot_layout_skip_mark (context->face, IN_INFO (j), lookup_flag, &property))
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400354 {
Behdad Esfahbod122f21f2009-05-18 04:21:53 -0400355 if (HB_UNLIKELY (j + count - i == end))
Behdad Esfahbodbb3899a2009-05-05 13:25:13 -0400356 return false;
357 j++;
358 }
359
Behdad Esfahbod5130c352009-05-26 15:45:41 -0400360 if (!(property & HB_OT_LAYOUT_GLYPH_CLASS_MARK))
Behdad Esfahbodbb3899a2009-05-05 13:25:13 -0400361 is_mark = FALSE;
362
Behdad Esfahbod4189b922009-05-26 17:31:56 -0400363 if (HB_LIKELY (IN_GLYPH (j) != component[i]))
Behdad Esfahbodbb3899a2009-05-05 13:25:13 -0400364 return false;
365 }
Behdad Esfahbod4189b922009-05-26 17:31:56 -0400366 /* This is just a guess ... */
Behdad Esfahbod23c86aa2009-08-03 21:40:20 -0400367 if (_hb_ot_layout_has_new_glyph_classes (context->face))
368 _hb_ot_layout_set_glyph_class (context->face, ligGlyph,
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400369 is_mark ? HB_OT_LAYOUT_GLYPH_CLASS_MARK
370 : HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE);
Behdad Esfahbodbb3899a2009-05-05 13:25:13 -0400371
372 if (j == buffer->in_pos + i) /* No input glyphs skipped */
373 /* We don't use a new ligature ID if there are no skipped
374 glyphs and the ligature already has an ID. */
Behdad Esfahbod88a5f5a2009-05-25 03:39:11 -0400375 _hb_buffer_add_output_glyphs (buffer, i,
376 1, (const uint16_t *) &ligGlyph,
377 0xFFFF,
378 IN_LIGID (buffer->in_pos) ?
Behdad Esfahbodc968fc22009-05-25 04:04:24 -0400379 0xFFFF : _hb_buffer_allocate_lig_id (buffer));
Behdad Esfahbodbb3899a2009-05-05 13:25:13 -0400380 else
381 {
Behdad Esfahbodc968fc22009-05-25 04:04:24 -0400382 unsigned int lig_id = _hb_buffer_allocate_lig_id (buffer);
Behdad Esfahbodbb3899a2009-05-05 13:25:13 -0400383 _hb_buffer_add_output_glyph (buffer, ligGlyph, 0xFFFF, lig_id);
384
385 /* Now we must do a second loop to copy the skipped glyphs to
386 `out' and assign component values to it. We start with the
387 glyph after the first component. Glyphs between component
388 i and i+1 belong to component i. Together with the lig_id
389 value it is later possible to check whether a specific
390 component value really belongs to a given ligature. */
391
Behdad Esfahbod19fc24f2009-05-17 09:45:32 -0400392 for ( i = 1; i < count; i++ )
Behdad Esfahbodbb3899a2009-05-05 13:25:13 -0400393 {
Behdad Esfahbod23c86aa2009-08-03 21:40:20 -0400394 while (_hb_ot_layout_skip_mark (context->face, IN_CURINFO (), lookup_flag, NULL))
Behdad Esfahbod4189b922009-05-26 17:31:56 -0400395 _hb_buffer_add_output_glyph (buffer, IN_CURGLYPH (), i - 1, lig_id);
Behdad Esfahbodbb3899a2009-05-05 13:25:13 -0400396
397 (buffer->in_pos)++;
398 }
399
Behdad Esfahbodd6aae5f2009-05-18 04:25:22 -0400400 /* TODO We should possibly reassign lig_id and component for any
Behdad Esfahbodbb3899a2009-05-05 13:25:13 -0400401 * components of a previous ligature that s now being removed as part of
402 * this ligature. */
403 }
404
405 return true;
406 }
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500407
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400408 public:
409 inline bool sanitize (SANITIZE_ARG_DEF) {
410 return SANITIZE2 (ligGlyph, component);
411 }
412
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500413 private:
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400414 GlyphID ligGlyph; /* GlyphID of ligature to substitute */
Behdad Esfahbode8cbaaf2009-05-18 02:03:58 -0400415 HeadlessArrayOf<GlyphID>
416 component; /* Array of component GlyphIDs--start
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400417 * with the second component--ordered
418 * in writing direction */
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500419};
Behdad Esfahbod8b835802009-05-16 22:48:14 -0400420ASSERT_SIZE (Ligature, 4);
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400421
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400422struct LigatureSet
423{
Behdad Esfahbodbb3899a2009-05-05 13:25:13 -0400424 friend struct LigatureSubstFormat1;
425
426 private:
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400427 inline bool apply (APPLY_ARG_DEF, bool is_mark) const
428 {
Behdad Esfahbodc9a7cbe2009-05-17 01:22:51 -0400429 unsigned int num_ligs = ligature.len;
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400430 for (unsigned int i = 0; i < num_ligs; i++)
431 {
Behdad Esfahbodc9a7cbe2009-05-17 01:22:51 -0400432 const Ligature &lig = this+ligature[i];
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -0400433 if (lig.apply (APPLY_ARG, is_mark))
Behdad Esfahbodbb3899a2009-05-05 13:25:13 -0400434 return true;
435 }
436
437 return false;
438 }
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400439
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400440 public:
441 inline bool sanitize (SANITIZE_ARG_DEF) {
442 return SANITIZE_THIS (ligature);
443 }
444
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400445 private:
Behdad Esfahbodc9a7cbe2009-05-17 01:22:51 -0400446 OffsetArrayOf<Ligature>
447 ligature; /* Array LigatureSet tables
448 * ordered by preference */
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400449};
Behdad Esfahbod8b835802009-05-16 22:48:14 -0400450ASSERT_SIZE (LigatureSet, 2);
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500451
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400452struct LigatureSubstFormat1
453{
Behdad Esfahboda84e71a2009-04-16 16:53:40 -0400454 friend struct LigatureSubst;
455
456 private:
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400457 inline bool apply (APPLY_ARG_DEF) const
458 {
Behdad Esfahboda84e71a2009-04-16 16:53:40 -0400459 hb_codepoint_t glyph_id = IN_CURGLYPH ();
460
Behdad Esfahbod5130c352009-05-26 15:45:41 -0400461 bool first_is_mark = !!(property & HB_OT_LAYOUT_GLYPH_CLASS_MARK);
Behdad Esfahboda84e71a2009-04-16 16:53:40 -0400462
Behdad Esfahbodc9a7cbe2009-05-17 01:22:51 -0400463 unsigned int index = (this+coverage) (glyph_id);
Behdad Esfahbod4acaffd2009-05-18 05:29:29 -0400464 if (HB_LIKELY (index == NOT_COVERED))
Behdad Esfahbodaa3d7ad2009-05-17 23:17:56 -0400465 return false;
466
Behdad Esfahbodc9a7cbe2009-05-17 01:22:51 -0400467 const LigatureSet &lig_set = this+ligatureSet[index];
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -0400468 return lig_set.apply (APPLY_ARG, first_is_mark);
Behdad Esfahboda84e71a2009-04-16 16:53:40 -0400469 }
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500470
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400471 inline bool sanitize (SANITIZE_ARG_DEF) {
472 return SANITIZE_THIS2 (coverage, ligatureSet);
473 }
474
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500475 private:
Behdad Esfahbodf45107f2009-05-17 20:13:02 -0400476 USHORT format; /* Format identifier--format = 1 */
Behdad Esfahbod238c8552009-05-17 00:22:37 -0400477 OffsetTo<Coverage>
478 coverage; /* Offset to Coverage table--from
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500479 * beginning of Substitution table */
Behdad Esfahbodd79cae02009-05-18 13:50:15 -0400480 OffsetArrayOf<LigatureSet>
Behdad Esfahbodc9a7cbe2009-05-17 01:22:51 -0400481 ligatureSet; /* Array LigatureSet tables
482 * ordered by Coverage Index */
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500483};
484ASSERT_SIZE (LigatureSubstFormat1, 6);
485
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400486struct LigatureSubst
487{
Behdad Esfahboda84e71a2009-04-16 16:53:40 -0400488 friend struct SubstLookupSubTable;
489
490 private:
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400491 inline bool apply (APPLY_ARG_DEF) const
492 {
Behdad Esfahbodf8dc67b2009-05-17 19:47:54 -0400493 switch (u.format) {
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -0400494 case 1: return u.format1->apply (APPLY_ARG);
Behdad Esfahboda84e71a2009-04-16 16:53:40 -0400495 default:return false;
496 }
497 }
498
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400499 inline bool sanitize (SANITIZE_ARG_DEF) {
500 if (!SANITIZE (u.format)) return false;
501 switch (u.format) {
502 case 1: return u.format1->sanitize (SANITIZE_ARG);
503 default:return true;
504 }
505 }
506
Behdad Esfahboda84e71a2009-04-16 16:53:40 -0400507 private:
508 union {
Behdad Esfahbodf8dc67b2009-05-17 19:47:54 -0400509 USHORT format; /* Format identifier */
510 LigatureSubstFormat1 format1[];
Behdad Esfahboda84e71a2009-04-16 16:53:40 -0400511 } u;
512};
Behdad Esfahbodf8dc67b2009-05-17 19:47:54 -0400513ASSERT_SIZE (LigatureSubst, 2);
Behdad Esfahboda84e71a2009-04-16 16:53:40 -0400514
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500515
Behdad Esfahbodc43562b2009-05-15 18:54:53 -0400516
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -0400517static inline bool substitute_lookup (APPLY_ARG_DEF, unsigned int lookup_index);
Behdad Esfahboda1625522009-05-17 07:52:11 -0400518
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400519struct ContextSubst : Context
520{
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -0400521 friend struct SubstLookupSubTable;
522
523 private:
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400524 inline bool apply (APPLY_ARG_DEF) const
Behdad Esfahbod79420ad2009-05-26 12:24:16 -0400525 { return Context::apply (APPLY_ARG, substitute_lookup); }
Behdad Esfahbodcdb317b2009-05-06 00:12:29 -0400526};
Behdad Esfahbodf8dc67b2009-05-17 19:47:54 -0400527ASSERT_SIZE (ContextSubst, 2);
Behdad Esfahbodcdb317b2009-05-06 00:12:29 -0400528
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400529struct ChainContextSubst : ChainContext
530{
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -0400531 friend struct SubstLookupSubTable;
532
533 private:
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400534 inline bool apply (APPLY_ARG_DEF) const
Behdad Esfahbod79420ad2009-05-26 12:24:16 -0400535 { return ChainContext::apply (APPLY_ARG, substitute_lookup); }
Behdad Esfahbod9f721cf2009-05-16 19:59:15 -0400536};
Behdad Esfahbodf8dc67b2009-05-17 19:47:54 -0400537ASSERT_SIZE (ChainContextSubst, 2);
Behdad Esfahbod9f721cf2009-05-16 19:59:15 -0400538
Behdad Esfahbod4f27ce72009-04-16 13:40:13 -0400539
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -0400540struct ExtensionSubst : Extension
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400541{
Behdad Esfahbod4f27ce72009-04-16 13:40:13 -0400542 friend struct SubstLookupSubTable;
543
544 private:
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400545 inline const struct SubstLookupSubTable& get_subtable (void) const
Behdad Esfahbod2b5a59c2009-08-04 11:38:50 -0400546 { return CONST_CAST (SubstLookupSubTable, Extension::get_subtable (), 0); }
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400547
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -0400548 inline bool apply (APPLY_ARG_DEF) const;
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400549
550 inline bool sanitize (SANITIZE_ARG_DEF);
Behdad Esfahbod4f27ce72009-04-16 13:40:13 -0400551};
Behdad Esfahbodf8dc67b2009-05-17 19:47:54 -0400552ASSERT_SIZE (ExtensionSubst, 2);
Behdad Esfahbod4f27ce72009-04-16 13:40:13 -0400553
554
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400555struct ReverseChainSingleSubstFormat1
556{
Behdad Esfahbod969afd72009-05-18 05:47:47 -0400557 friend struct ReverseChainSingleSubst;
558
559 private:
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400560 inline bool apply (APPLY_ARG_DEF) const
561 {
Behdad Esfahbod969afd72009-05-18 05:47:47 -0400562 if (HB_UNLIKELY (context_length != NO_CONTEXT))
563 return false; /* No chaining to this type */
564
565 unsigned int index = (this+coverage) (IN_CURGLYPH ());
566 if (HB_LIKELY (index == NOT_COVERED))
567 return false;
568
Behdad Esfahbod2b5a59c2009-08-04 11:38:50 -0400569 const OffsetArrayOf<Coverage> &lookahead = CONST_CAST (OffsetArrayOf<Coverage>, backtrack, backtrack.get_size ());
570 const ArrayOf<GlyphID> &substitute = CONST_CAST (ArrayOf<GlyphID>, lookahead, lookahead.get_size ());
Behdad Esfahbod969afd72009-05-18 05:47:47 -0400571
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -0400572 if (match_backtrack (APPLY_ARG,
Behdad Esfahbod969afd72009-05-18 05:47:47 -0400573 backtrack.len, (USHORT *) backtrack.array,
Behdad Esfahbod2b5a59c2009-08-04 11:38:50 -0400574 match_coverage, DECONST_CHARP(this)) &&
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -0400575 match_lookahead (APPLY_ARG,
Behdad Esfahbod969afd72009-05-18 05:47:47 -0400576 lookahead.len, (USHORT *) lookahead.array,
Behdad Esfahbod2b5a59c2009-08-04 11:38:50 -0400577 match_coverage, DECONST_CHARP(this),
Behdad Esfahbod969afd72009-05-18 05:47:47 -0400578 1))
579 {
Behdad Esfahbod4189b922009-05-26 17:31:56 -0400580 IN_CURGLYPH () = substitute[index];
Behdad Esfahbod969afd72009-05-18 05:47:47 -0400581 buffer->in_pos--; /* Reverse! */
582 return true;
583 }
584
Behdad Esfahbodca5290f2009-05-17 20:48:27 -0400585 return false;
586 }
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500587
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400588 inline bool sanitize (SANITIZE_ARG_DEF) {
589 if (!SANITIZE_THIS2 (coverage, backtrack))
590 return false;
Behdad Esfahbod2b5a59c2009-08-04 11:38:50 -0400591 OffsetArrayOf<Coverage> &lookahead = CAST (OffsetArrayOf<Coverage>, backtrack, backtrack.get_size ());
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400592 if (!SANITIZE_THIS (lookahead))
593 return false;
Behdad Esfahbod2b5a59c2009-08-04 11:38:50 -0400594 ArrayOf<GlyphID> &substitute = CAST (ArrayOf<GlyphID>, lookahead, lookahead.get_size ());
Behdad Esfahbod9bd629c2009-08-04 21:42:23 -0400595 return SANITIZE (substitute);
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400596 }
597
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500598 private:
Behdad Esfahbodf45107f2009-05-17 20:13:02 -0400599 USHORT format; /* Format identifier--format = 1 */
Behdad Esfahbod969afd72009-05-18 05:47:47 -0400600 OffsetTo<Coverage>
601 coverage; /* Offset to Coverage table--from
602 * beginning of table */
603 OffsetArrayOf<Coverage>
604 backtrack; /* Array of coverage tables
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500605 * in backtracking sequence, in glyph
606 * sequence order */
Behdad Esfahbod969afd72009-05-18 05:47:47 -0400607 OffsetArrayOf<Coverage>
608 lookaheadX; /* Array of coverage tables
609 * in lookahead sequence, in glyph
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500610 * sequence order */
Behdad Esfahbod969afd72009-05-18 05:47:47 -0400611 ArrayOf<GlyphID>
612 substituteX; /* Array of substitute
613 * GlyphIDs--ordered by Coverage Index */
Behdad Esfahboda16ecbf2008-01-23 17:01:55 -0500614};
615ASSERT_SIZE (ReverseChainSingleSubstFormat1, 10);
616
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400617struct ReverseChainSingleSubst
618{
Behdad Esfahbodca5290f2009-05-17 20:48:27 -0400619 friend struct SubstLookupSubTable;
620
621 private:
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400622 inline bool apply (APPLY_ARG_DEF) const
623 {
Behdad Esfahbodca5290f2009-05-17 20:48:27 -0400624 switch (u.format) {
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -0400625 case 1: return u.format1->apply (APPLY_ARG);
Behdad Esfahbodca5290f2009-05-17 20:48:27 -0400626 default:return false;
627 }
628 }
629
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400630 inline bool sanitize (SANITIZE_ARG_DEF) {
631 if (!SANITIZE (u.format)) return false;
632 switch (u.format) {
633 case 1: return u.format1->sanitize (SANITIZE_ARG);
634 default:return true;
635 }
636 }
637
Behdad Esfahbodca5290f2009-05-17 20:48:27 -0400638 private:
639 union {
640 USHORT format; /* Format identifier */
641 ReverseChainSingleSubstFormat1 format1[];
642 } u;
643};
644ASSERT_SIZE (ReverseChainSingleSubst, 2);
645
646
647
Behdad Esfahbod75860892008-01-23 18:02:28 -0500648/*
Behdad Esfahbod2d15e722009-04-15 19:50:16 -0400649 * SubstLookup
650 */
651
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400652struct SubstLookupSubTable
653{
Behdad Esfahbod2d15e722009-04-15 19:50:16 -0400654 friend struct SubstLookup;
655
Behdad Esfahbodff05d252009-05-20 03:53:00 -0400656 enum {
657 Single = 1,
658 Multiple = 2,
659 Alternate = 3,
660 Ligature = 4,
661 Context = 5,
662 ChainContext = 6,
663 Extension = 7,
664 ReverseChainSingle = 8,
665 };
666
Behdad Esfahbod923923f2009-05-22 17:58:09 -0400667 bool apply (APPLY_ARG_DEF, unsigned int lookup_type) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400668 {
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400669 switch (lookup_type) {
Behdad Esfahbodff05d252009-05-20 03:53:00 -0400670 case Single: return u.single->apply (APPLY_ARG);
671 case Multiple: return u.multiple->apply (APPLY_ARG);
672 case Alternate: return u.alternate->apply (APPLY_ARG);
673 case Ligature: return u.ligature->apply (APPLY_ARG);
674 case Context: return u.context->apply (APPLY_ARG);
675 case ChainContext: return u.chainContext->apply (APPLY_ARG);
676 case Extension: return u.extension->apply (APPLY_ARG);
677 case ReverseChainSingle: return u.reverseChainContextSingle->apply (APPLY_ARG);
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400678 default:return false;
679 }
Behdad Esfahbod2d15e722009-04-15 19:50:16 -0400680 }
681
Behdad Esfahboddc9c4d92009-08-04 12:26:26 -0400682 bool sanitize (SANITIZE_ARG_DEF) {
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400683 if (!SANITIZE (u.format)) return false;
684 switch (u.format) {
685 case Single: return u.single->sanitize (SANITIZE_ARG);
686 case Multiple: return u.multiple->sanitize (SANITIZE_ARG);
687 case Alternate: return u.alternate->sanitize (SANITIZE_ARG);
688 case Ligature: return u.ligature->sanitize (SANITIZE_ARG);
689 case Context: return u.context->sanitize (SANITIZE_ARG);
690 case ChainContext: return u.chainContext->sanitize (SANITIZE_ARG);
691 case Extension: return u.extension->sanitize (SANITIZE_ARG);
692 case ReverseChainSingle: return u.reverseChainContextSingle->sanitize (SANITIZE_ARG);
693 default:return true;
694 }
695 }
696
Behdad Esfahbod2d15e722009-04-15 19:50:16 -0400697 private:
698 union {
Behdad Esfahbodca5290f2009-05-17 20:48:27 -0400699 USHORT format;
700 SingleSubst single[];
701 MultipleSubst multiple[];
702 AlternateSubst alternate[];
703 LigatureSubst ligature[];
704 ContextSubst context[];
Behdad Esfahbod64e67f72009-05-18 15:32:40 -0400705 ChainContextSubst chainContext[];
Behdad Esfahbodca5290f2009-05-17 20:48:27 -0400706 ExtensionSubst extension[];
707 ReverseChainSingleSubst reverseChainContextSingle[];
Behdad Esfahbod2d15e722009-04-15 19:50:16 -0400708 } u;
709};
Behdad Esfahbodf45107f2009-05-17 20:13:02 -0400710ASSERT_SIZE (SubstLookupSubTable, 2);
Behdad Esfahbod2d15e722009-04-15 19:50:16 -0400711
Behdad Esfahbod4f27ce72009-04-16 13:40:13 -0400712
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400713struct SubstLookup : Lookup
714{
715 inline const SubstLookupSubTable& get_subtable (unsigned int i) const
Behdad Esfahbod2b5a59c2009-08-04 11:38:50 -0400716 { return CONST_CAST (SubstLookupSubTable, Lookup::get_subtable (i), 0); }
Behdad Esfahbod2d15e722009-04-15 19:50:16 -0400717
718 /* Like get_type(), but looks through extension lookups.
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400719 * Never returns Extension */
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400720 inline unsigned int get_effective_type (void) const
721 {
Behdad Esfahbod2d15e722009-04-15 19:50:16 -0400722 unsigned int type = get_type ();
723
Behdad Esfahbodff05d252009-05-20 03:53:00 -0400724 if (HB_UNLIKELY (type == SubstLookupSubTable::Extension))
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400725 {
Behdad Esfahbod8533bb92009-05-18 06:00:12 -0400726 unsigned int count = get_subtable_count ();
Behdad Esfahbodf45107f2009-05-17 20:13:02 -0400727 type = get_subtable(0).u.extension->get_type ();
Behdad Esfahbod8533bb92009-05-18 06:00:12 -0400728 /* The spec says all subtables should have the same type.
729 * This is specially important if one has a reverse type! */
730 for (unsigned int i = 1; i < count; i++)
731 if (get_subtable(i).u.extension->get_type () != type)
732 return 0;
Behdad Esfahbod2d15e722009-04-15 19:50:16 -0400733 }
734
735 return type;
736 }
737
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400738 inline bool is_reverse (void) const
Behdad Esfahbod79420ad2009-05-26 12:24:16 -0400739 { return HB_UNLIKELY (get_effective_type () == SubstLookupSubTable::ReverseChainSingle); }
Behdad Esfahbod2d15e722009-04-15 19:50:16 -0400740
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400741 inline bool apply_once (hb_ot_layout_context_t *context,
Behdad Esfahbod923923f2009-05-22 17:58:09 -0400742 hb_buffer_t *buffer,
743 unsigned int context_length,
744 unsigned int nesting_level_left) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400745 {
Behdad Esfahbod2d15e722009-04-15 19:50:16 -0400746 unsigned int lookup_type = get_type ();
Behdad Esfahbod30bd7632009-04-15 22:56:15 -0400747 unsigned int lookup_flag = get_flag ();
Behdad Esfahbod923923f2009-05-22 17:58:09 -0400748 unsigned int property;
749
Behdad Esfahbod23c86aa2009-08-03 21:40:20 -0400750 if (!_hb_ot_layout_check_glyph_property (context->face, IN_CURINFO (), lookup_flag, &property))
Behdad Esfahbod923923f2009-05-22 17:58:09 -0400751 return false;
Behdad Esfahbod2d15e722009-04-15 19:50:16 -0400752
Behdad Esfahbod29d86442009-08-04 02:27:37 -0400753 unsigned int count = get_subtable_count ();
754 for (unsigned int i = 0; i < count; i++)
Behdad Esfahbodeb0dfc82009-05-18 18:22:44 -0400755 if (get_subtable (i).apply (APPLY_ARG, lookup_type))
Behdad Esfahbodecf17e82009-05-17 09:34:41 -0400756 return true;
757
758 return false;
759 }
760
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400761 bool apply_string (hb_ot_layout_context_t *context,
Behdad Esfahbod2a8e6ac2009-05-18 18:21:44 -0400762 hb_buffer_t *buffer,
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400763 hb_ot_layout_feature_mask_t mask) const
764 {
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400765 bool ret = false;
766
Behdad Esfahbod19fc24f2009-05-17 09:45:32 -0400767 if (HB_UNLIKELY (!buffer->in_length))
768 return false;
769
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400770 if (HB_LIKELY (!is_reverse ()))
771 {
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400772 /* in/out forward substitution */
773 _hb_buffer_clear_output (buffer);
774 buffer->in_pos = 0;
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400775 while (buffer->in_pos < buffer->in_length)
776 {
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400777 if ((~IN_PROPERTIES (buffer->in_pos) & mask) &&
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400778 apply_once (context, buffer, NO_CONTEXT, MAX_NESTING_LEVEL))
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400779 ret = true;
780 else
Behdad Esfahbod15c3e752009-05-17 06:03:42 -0400781 _hb_buffer_next_glyph (buffer);
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400782
783 }
784 if (ret)
785 _hb_buffer_swap (buffer);
786
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400787 }
788 else
789 {
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400790
791 /* in-place backward substitution */
792 buffer->in_pos = buffer->in_length - 1;
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400793 do
794 {
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400795 if ((~IN_PROPERTIES (buffer->in_pos) & mask) &&
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400796 apply_once (context, buffer, NO_CONTEXT, MAX_NESTING_LEVEL))
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400797 ret = true;
798 else
799 buffer->in_pos--;
800
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400801 }
802 while ((int) buffer->in_pos >= 0);
Behdad Esfahbod5a0b7912009-04-16 04:45:30 -0400803 }
804
805 return ret;
806 }
Behdad Esfahbod29d86442009-08-04 02:27:37 -0400807
808 inline bool sanitize (SANITIZE_ARG_DEF) {
809 if (Lookup::sanitize (SANITIZE_ARG)) return false;
810 OffsetArrayOf<SubstLookupSubTable> &list = (OffsetArrayOf<SubstLookupSubTable> &) subTable;
811 return SANITIZE_THIS (list);
812 }
Behdad Esfahbod2d15e722009-04-15 19:50:16 -0400813};
Behdad Esfahbodf45107f2009-05-17 20:13:02 -0400814ASSERT_SIZE (SubstLookup, 6);
Behdad Esfahbod2d15e722009-04-15 19:50:16 -0400815
Behdad Esfahbod29d86442009-08-04 02:27:37 -0400816typedef OffsetListOf<SubstLookup> SubstLookupList;
817ASSERT_SIZE (SubstLookupList, 2);
Behdad Esfahbodc43562b2009-05-15 18:54:53 -0400818
Behdad Esfahbod2d15e722009-04-15 19:50:16 -0400819/*
Behdad Esfahbod75860892008-01-23 18:02:28 -0500820 * GSUB
821 */
822
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400823struct GSUB : GSUBGPOS
824{
Behdad Esfahboda328d662009-08-04 20:27:05 -0400825 static const hb_tag_t Tag = HB_OT_TAG_GSUB;
Behdad Esfahbod75860892008-01-23 18:02:28 -0500826
Behdad Esfahbod5876bf12009-05-24 00:53:28 -0400827 static inline const GSUB& get_for_data (const char *data)
Behdad Esfahbod79420ad2009-05-26 12:24:16 -0400828 { return (const GSUB&) GSUBGPOS::get_for_data (data); }
Behdad Esfahbod2d15e722009-04-15 19:50:16 -0400829
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400830 inline const SubstLookup& get_lookup (unsigned int i) const
Behdad Esfahbod79420ad2009-05-26 12:24:16 -0400831 { return (const SubstLookup&) GSUBGPOS::get_lookup (i); }
Behdad Esfahbod2d15e722009-04-15 19:50:16 -0400832
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400833 inline bool substitute_lookup (hb_ot_layout_context_t *context,
Behdad Esfahbodfc36d942009-05-15 20:11:10 -0400834 hb_buffer_t *buffer,
835 unsigned int lookup_index,
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400836 hb_ot_layout_feature_mask_t mask) const
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400837 { return get_lookup (lookup_index).apply_string (context, buffer, mask); }
Behdad Esfahbod2d15e722009-04-15 19:50:16 -0400838
Behdad Esfahbod29d86442009-08-04 02:27:37 -0400839
Behdad Esfahbode49a84c2009-08-04 14:33:23 -0400840 bool sanitize (SANITIZE_ARG_DEF) {
Behdad Esfahbod29d86442009-08-04 02:27:37 -0400841 if (GSUBGPOS::sanitize (SANITIZE_ARG)) return false;
Behdad Esfahbodad3a3cd2009-08-04 12:13:52 -0400842 OffsetTo<SubstLookupList> &list = CAST(OffsetTo<SubstLookupList>, lookupList, 0);
Behdad Esfahbod29d86442009-08-04 02:27:37 -0400843 return SANITIZE_THIS (list);
844 }
Behdad Esfahbod75860892008-01-23 18:02:28 -0500845};
Behdad Esfahbodf45107f2009-05-17 20:13:02 -0400846ASSERT_SIZE (GSUB, 10);
Behdad Esfahbodc43562b2009-05-15 18:54:53 -0400847
848
Behdad Esfahbod887c4b42009-05-17 21:06:08 -0400849/* Out-of-class implementation for methods recursing */
Behdad Esfahbodc43562b2009-05-15 18:54:53 -0400850
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -0400851inline bool ExtensionSubst::apply (APPLY_ARG_DEF) const
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400852{
Behdad Esfahbod6cf2a522009-05-17 21:11:49 -0400853 unsigned int lookup_type = get_type ();
854
Behdad Esfahbodd468f9a2009-05-21 22:31:33 -0400855 if (HB_UNLIKELY (lookup_type == SubstLookupSubTable::Extension))
Behdad Esfahbod6cf2a522009-05-17 21:11:49 -0400856 return false;
857
Behdad Esfahbod70de50c2009-08-04 00:58:28 -0400858 return get_subtable ().apply (APPLY_ARG, lookup_type);
859}
860
861inline bool ExtensionSubst::sanitize (SANITIZE_ARG_DEF)
862{
Behdad Esfahbod2b5a59c2009-08-04 11:38:50 -0400863 return Extension::sanitize (SANITIZE_ARG) &&
Behdad Esfahbod18939482009-08-04 14:27:56 -0400864 (&(Extension::get_subtable ()) == &Null(LookupSubTable) ||
Behdad Esfahbod5ff4e132009-08-04 21:35:32 -0400865 get_type () == SubstLookupSubTable::Extension ||
Behdad Esfahbod18939482009-08-04 14:27:56 -0400866 DECONST_CAST (SubstLookupSubTable, get_subtable (), 0).sanitize (SANITIZE_ARG));
Behdad Esfahbodc43562b2009-05-15 18:54:53 -0400867}
868
Behdad Esfahbod4c44d832009-05-19 23:42:30 -0400869static inline bool substitute_lookup (APPLY_ARG_DEF, unsigned int lookup_index)
870{
Behdad Esfahbod23c86aa2009-08-03 21:40:20 -0400871 const GSUB &gsub = *(context->face->ot_layout.gsub);
Behdad Esfahboda1625522009-05-17 07:52:11 -0400872 const SubstLookup &l = gsub.get_lookup (lookup_index);
Behdad Esfahbodc43562b2009-05-15 18:54:53 -0400873
Behdad Esfahbodeca8e332009-05-17 09:07:27 -0400874 if (HB_UNLIKELY (nesting_level_left == 0))
875 return false;
876 nesting_level_left--;
877
878 if (HB_UNLIKELY (context_length < 1))
879 return false;
880
Behdad Esfahbod0ead4812009-08-02 17:41:36 -0400881 return l.apply_once (context, buffer, context_length, nesting_level_left);
Behdad Esfahbodc43562b2009-05-15 18:54:53 -0400882}
883
884
Behdad Esfahbod5f5b24f2009-08-02 20:03:12 -0400885#endif /* HB_OT_LAYOUT_GSUB_PRIVATE_HH */