hb-ot-layout-gsub-table.hh 43.8 KB
Newer Older
B
Behdad Esfahbod 已提交
1
/*
B
Behdad Esfahbod 已提交
2
 * Copyright © 2007,2008,2009,2010  Red Hat, Inc.
3
 * Copyright © 2010,2012,2013  Google, Inc.
B
Behdad Esfahbod 已提交
4
 *
B
Behdad Esfahbod 已提交
5
 *  This is part of HarfBuzz, a text shaping library.
B
Behdad Esfahbod 已提交
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 *
 * Permission is hereby granted, without written agreement and without
 * license or royalty fees, to use, copy, modify, and distribute this
 * software and its documentation for any purpose, provided that the
 * above copyright notice and the following two paragraphs appear in
 * all copies of this software.
 *
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 *
 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 *
 * Red Hat Author(s): Behdad Esfahbod
26
 * Google Author(s): Behdad Esfahbod
B
Behdad Esfahbod 已提交
27 28
 */

29 30
#ifndef HB_OT_LAYOUT_GSUB_TABLE_HH
#define HB_OT_LAYOUT_GSUB_TABLE_HH
B
Behdad Esfahbod 已提交
31

32
#include "hb-ot-layout-gsubgpos-private.hh"
B
Behdad Esfahbod 已提交
33

B
Behdad Esfahbod 已提交
34

35 36
namespace OT {

37

B
Behdad Esfahbod 已提交
38 39
struct SingleSubstFormat1
{
40 41 42 43 44 45
  inline bool is_inplace (hb_is_inplace_context_t *c) const
  {
    TRACE_IS_INPLACE (this);
    return TRACE_RETURN (true);
  }

B
Behdad Esfahbod 已提交
46
  inline void closure (hb_closure_context_t *c) const
47
  {
B
Behdad Esfahbod 已提交
48
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
49 50 51 52
    Coverage::Iter iter;
    for (iter.init (this+coverage); iter.more (); iter.next ()) {
      hb_codepoint_t glyph_id = iter.get_glyph ();
      if (c->glyphs->has (glyph_id))
B
Behdad Esfahbod 已提交
53
	c->glyphs->add ((glyph_id + deltaGlyphID) & 0xFFFF);
B
Behdad Esfahbod 已提交
54
    }
55 56
  }

57 58
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
59
    TRACE_COLLECT_GLYPHS (this);
60 61 62
    Coverage::Iter iter;
    for (iter.init (this+coverage); iter.more (); iter.next ()) {
      hb_codepoint_t glyph_id = iter.get_glyph ();
B
Minor  
Behdad Esfahbod 已提交
63 64
      c->input->add (glyph_id);
      c->output->add ((glyph_id + deltaGlyphID) & 0xFFFF);
65 66 67
    }
  }

68 69 70 71 72
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

73 74
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
75
    TRACE_WOULD_APPLY (this);
76
    return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
77 78
  }

B
Behdad Esfahbod 已提交
79
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
80
  {
B
Behdad Esfahbod 已提交
81
    TRACE_APPLY (this);
82
    hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
83
    unsigned int index = (this+coverage).get_coverage (glyph_id);
84
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
85

86 87 88
    /* According to the Adobe Annotated OpenType Suite, result is always
     * limited to 16bit. */
    glyph_id = (glyph_id + deltaGlyphID) & 0xFFFF;
89
    c->replace_glyph (glyph_id);
B
Behdad Esfahbod 已提交
90

91
    return TRACE_RETURN (true);
92
  }
B
Behdad Esfahbod 已提交
93

94
  inline bool serialize (hb_serialize_context_t *c,
95
			 Supplier<GlyphID> &glyphs,
96
			 unsigned int num_glyphs,
B
Minor  
Behdad Esfahbod 已提交
97
			 int delta)
98
  {
B
Behdad Esfahbod 已提交
99
    TRACE_SERIALIZE (this);
100
    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
101
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
B
Minor  
Behdad Esfahbod 已提交
102
    deltaGlyphID.set (delta); /* TODO(serilaize) overflow? */
103 104 105
    return TRACE_RETURN (true);
  }

B
Behdad Esfahbod 已提交
106
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
107
    TRACE_SANITIZE (this);
108
    return TRACE_RETURN (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
B
Behdad Esfahbod 已提交
109 110
  }

111
  protected:
B
Behdad Esfahbod 已提交
112
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
113 114
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
115 116 117
					 * beginning of Substitution table */
  SHORT		deltaGlyphID;		/* Add to original GlyphID to get
					 * substitute GlyphID */
118 119
  public:
  DEFINE_SIZE_STATIC (6);
B
Behdad Esfahbod 已提交
120 121
};

B
Behdad Esfahbod 已提交
122 123
struct SingleSubstFormat2
{
124 125 126 127 128 129
  inline bool is_inplace (hb_is_inplace_context_t *c) const
  {
    TRACE_IS_INPLACE (this);
    return TRACE_RETURN (true);
  }

B
Behdad Esfahbod 已提交
130
  inline void closure (hb_closure_context_t *c) const
131
  {
B
Behdad Esfahbod 已提交
132
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
133 134 135
    Coverage::Iter iter;
    for (iter.init (this+coverage); iter.more (); iter.next ()) {
      if (c->glyphs->has (iter.get_glyph ()))
B
Behdad Esfahbod 已提交
136
	c->glyphs->add (substitute[iter.get_coverage ()]);
B
Behdad Esfahbod 已提交
137
    }
138 139
  }

140 141
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
142
    TRACE_COLLECT_GLYPHS (this);
143 144
    Coverage::Iter iter;
    for (iter.init (this+coverage); iter.more (); iter.next ()) {
B
Minor  
Behdad Esfahbod 已提交
145 146
      c->input->add (iter.get_glyph ());
      c->output->add (substitute[iter.get_coverage ()]);
147 148 149
    }
  }

150 151 152 153 154
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

155 156
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
157
    TRACE_WOULD_APPLY (this);
158
    return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
159 160
  }

B
Behdad Esfahbod 已提交
161
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
162
  {
B
Behdad Esfahbod 已提交
163
    TRACE_APPLY (this);
164
    hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
165
    unsigned int index = (this+coverage).get_coverage (glyph_id);
166
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
167

168
    if (unlikely (index >= substitute.len)) return TRACE_RETURN (false);
169 170

    glyph_id = substitute[index];
171
    c->replace_glyph (glyph_id);
B
Behdad Esfahbod 已提交
172

173
    return TRACE_RETURN (true);
174
  }
B
Behdad Esfahbod 已提交
175

B
Behdad Esfahbod 已提交
176
  inline bool serialize (hb_serialize_context_t *c,
177 178
			 Supplier<GlyphID> &glyphs,
			 Supplier<GlyphID> &substitutes,
B
Behdad Esfahbod 已提交
179 180
			 unsigned int num_glyphs)
  {
B
Behdad Esfahbod 已提交
181
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
182 183
    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
    if (unlikely (!substitute.serialize (c, substitutes, num_glyphs))) return TRACE_RETURN (false);
184
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
185 186 187
    return TRACE_RETURN (true);
  }

B
Behdad Esfahbod 已提交
188
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
189
    TRACE_SANITIZE (this);
190
    return TRACE_RETURN (coverage.sanitize (c, this) && substitute.sanitize (c));
B
Behdad Esfahbod 已提交
191 192
  }

193
  protected:
B
Behdad Esfahbod 已提交
194
  USHORT	format;			/* Format identifier--format = 2 */
B
Behdad Esfahbod 已提交
195 196
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
197
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
198 199 200
  ArrayOf<GlyphID>
		substitute;		/* Array of substitute
					 * GlyphIDs--ordered by Coverage Index */
201
  public:
202
  DEFINE_SIZE_ARRAY (6, substitute);
B
Behdad Esfahbod 已提交
203 204
};

B
Behdad Esfahbod 已提交
205 206
struct SingleSubst
{
B
Behdad Esfahbod 已提交
207
  inline bool serialize (hb_serialize_context_t *c,
208 209
			 Supplier<GlyphID> &glyphs,
			 Supplier<GlyphID> &substitutes,
B
Behdad Esfahbod 已提交
210 211
			 unsigned int num_glyphs)
  {
B
Behdad Esfahbod 已提交
212
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
213 214
    if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
    unsigned int format = 2;
B
Minor  
Behdad Esfahbod 已提交
215
    int delta;
B
Behdad Esfahbod 已提交
216 217
    if (num_glyphs) {
      format = 1;
B
Minor  
Behdad Esfahbod 已提交
218
      /* TODO(serialize) check for wrap-around */
B
Behdad Esfahbod 已提交
219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
      delta = substitutes[0] - glyphs[0];
      for (unsigned int i = 1; i < num_glyphs; i++)
	if (delta != substitutes[i] - glyphs[i]) {
	  format = 2;
	  break;
	}
    }
    u.format.set (format);
    switch (u.format) {
    case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, num_glyphs, delta));
    case 2: return TRACE_RETURN (u.format2.serialize (c, glyphs, substitutes, num_glyphs));
    default:return TRACE_RETURN (false);
    }
  }

B
Behdad Esfahbod 已提交
234 235 236 237 238 239 240 241 242 243 244
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
  {
    TRACE_DISPATCH (this);
    switch (u.format) {
    case 1: return TRACE_RETURN (c->dispatch (u.format1));
    case 2: return TRACE_RETURN (c->dispatch (u.format2));
    default:return TRACE_RETURN (c->default_return_value ());
    }
  }

B
Behdad Esfahbod 已提交
245
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
246
    TRACE_SANITIZE (this);
247
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
248
    switch (u.format) {
249 250 251
    case 1: return TRACE_RETURN (u.format1.sanitize (c));
    case 2: return TRACE_RETURN (u.format2.sanitize (c));
    default:return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
252 253 254
    }
  }

255
  protected:
256
  union {
B
Behdad Esfahbod 已提交
257
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
258 259
  SingleSubstFormat1	format1;
  SingleSubstFormat2	format2;
260
  } u;
B
Behdad Esfahbod 已提交
261
};
262

B
Behdad Esfahbod 已提交
263

B
Behdad Esfahbod 已提交
264 265
struct Sequence
{
266 267 268 269 270 271 272
  inline bool is_inplace (hb_is_inplace_context_t *c) const
  {
    TRACE_IS_INPLACE (this);
    /* For len==0 we don't do anything, so it's harmless. */
    return TRACE_RETURN (substitute.len <= 1);
  }

B
Behdad Esfahbod 已提交
273
  inline void closure (hb_closure_context_t *c) const
274
  {
B
Behdad Esfahbod 已提交
275
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
276 277
    unsigned int count = substitute.len;
    for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
278
      c->glyphs->add (substitute[i]);
279 280
  }

281 282
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
283
    TRACE_COLLECT_GLYPHS (this);
284 285
    unsigned int count = substitute.len;
    for (unsigned int i = 0; i < count; i++)
B
Minor  
Behdad Esfahbod 已提交
286
      c->output->add (substitute[i]);
287 288
  }

B
Behdad Esfahbod 已提交
289
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
290
  {
B
Behdad Esfahbod 已提交
291
    TRACE_APPLY (this);
292
    if (unlikely (!substitute.len)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
293

294
    unsigned int klass = c->buffer->cur().glyph_props() &
295 296
			 HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE ?
			 HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
297
    unsigned int count = substitute.len;
298 299 300 301 302 303 304
    if (count == 1) /* Special-case to make it in-place. */
    {
      c->replace_glyph (substitute.array[0]);
    }
    else
    {
      for (unsigned int i = 0; i < count; i++) {
B
Behdad Esfahbod 已提交
305
	_hb_glyph_info_set_lig_props_for_component (&c->buffer->cur(), i);
306 307 308
	c->output_glyph (substitute.array[i], klass);
      }
      c->buffer->skip_glyph ();
309
    }
B
Behdad Esfahbod 已提交
310

311
    return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
312 313
  }

314
  inline bool serialize (hb_serialize_context_t *c,
315
			 Supplier<GlyphID> &glyphs,
316 317
			 unsigned int num_glyphs)
  {
B
Behdad Esfahbod 已提交
318
    TRACE_SERIALIZE (this);
319 320 321 322 323
    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
    if (unlikely (!substitute.serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
    return TRACE_RETURN (true);
  }

B
Behdad Esfahbod 已提交
324
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
325
    TRACE_SANITIZE (this);
326
    return TRACE_RETURN (substitute.sanitize (c));
B
Behdad Esfahbod 已提交
327 328
  }

329
  protected:
B
Behdad Esfahbod 已提交
330 331
  ArrayOf<GlyphID>
		substitute;		/* String of GlyphIDs to substitute */
332
  public:
333
  DEFINE_SIZE_ARRAY (2, substitute);
B
Behdad Esfahbod 已提交
334 335
};

B
Behdad Esfahbod 已提交
336 337
struct MultipleSubstFormat1
{
338 339 340 341 342 343 344 345 346 347 348 349
  inline bool is_inplace (hb_is_inplace_context_t *c) const
  {
    TRACE_IS_INPLACE (this);
    /* Some tools generate MultipleSubst with each substitute having length 1!
     * So, check them. */
    unsigned int count = sequence.len;
    for (unsigned int i = 0; i < count; i++)
	if (!(this+sequence[i]).is_inplace (c))
	  return TRACE_RETURN (false);
    return TRACE_RETURN (true);
  }

B
Behdad Esfahbod 已提交
350
  inline void closure (hb_closure_context_t *c) const
351
  {
B
Behdad Esfahbod 已提交
352
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
353 354 355
    Coverage::Iter iter;
    for (iter.init (this+coverage); iter.more (); iter.next ()) {
      if (c->glyphs->has (iter.get_glyph ()))
B
Behdad Esfahbod 已提交
356
	(this+sequence[iter.get_coverage ()]).closure (c);
B
Behdad Esfahbod 已提交
357
    }
358 359
  }

360 361
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
362
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
363
    (this+coverage).add_coverage (c->input);
364 365 366 367 368
    unsigned int count = sequence.len;
    for (unsigned int i = 0; i < count; i++)
	(this+sequence[i]).collect_glyphs (c);
  }

369 370 371 372 373
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

374 375
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
376
    TRACE_WOULD_APPLY (this);
377
    return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
378 379
  }

B
Behdad Esfahbod 已提交
380
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
381
  {
B
Behdad Esfahbod 已提交
382
    TRACE_APPLY (this);
383

384
    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
385
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
386

387
    return TRACE_RETURN ((this+sequence[index]).apply (c));
388
  }
B
Behdad Esfahbod 已提交
389

390
  inline bool serialize (hb_serialize_context_t *c,
391 392
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &substitute_len_list,
393
			 unsigned int num_glyphs,
394
			 Supplier<GlyphID> &substitute_glyphs_list)
395
  {
B
Behdad Esfahbod 已提交
396
    TRACE_SERIALIZE (this);
397 398
    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
    if (unlikely (!sequence.serialize (c, num_glyphs))) return TRACE_RETURN (false);
399 400 401 402 403
    for (unsigned int i = 0; i < num_glyphs; i++)
      if (unlikely (!sequence[i].serialize (c, this).serialize (c,
								substitute_glyphs_list,
								substitute_len_list[i]))) return TRACE_RETURN (false);
    substitute_len_list.advance (num_glyphs);
404
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
405 406 407
    return TRACE_RETURN (true);
  }

B
Behdad Esfahbod 已提交
408
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
409
    TRACE_SANITIZE (this);
410
    return TRACE_RETURN (coverage.sanitize (c, this) && sequence.sanitize (c, this));
B
Behdad Esfahbod 已提交
411 412
  }

413
  protected:
B
Behdad Esfahbod 已提交
414
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
415 416
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
417
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
418 419 420
  OffsetArrayOf<Sequence>
		sequence;		/* Array of Sequence tables
					 * ordered by Coverage Index */
421
  public:
422
  DEFINE_SIZE_ARRAY (6, sequence);
B
Behdad Esfahbod 已提交
423
};
424

B
Behdad Esfahbod 已提交
425 426
struct MultipleSubst
{
427
  inline bool serialize (hb_serialize_context_t *c,
428 429
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &substitute_len_list,
430
			 unsigned int num_glyphs,
431
			 Supplier<GlyphID> &substitute_glyphs_list)
432
  {
B
Behdad Esfahbod 已提交
433
    TRACE_SERIALIZE (this);
434 435 436 437 438 439 440 441 442
    if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
    unsigned int format = 1;
    u.format.set (format);
    switch (u.format) {
    case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, substitute_len_list, num_glyphs, substitute_glyphs_list));
    default:return TRACE_RETURN (false);
    }
  }

B
Behdad Esfahbod 已提交
443 444 445 446 447 448 449 450 451 452
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
  {
    TRACE_DISPATCH (this);
    switch (u.format) {
    case 1: return TRACE_RETURN (c->dispatch (u.format1));
    default:return TRACE_RETURN (c->default_return_value ());
    }
  }

B
Behdad Esfahbod 已提交
453
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
454
    TRACE_SANITIZE (this);
455
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
456
    switch (u.format) {
457 458
    case 1: return TRACE_RETURN (u.format1.sanitize (c));
    default:return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
459 460 461
    }
  }

462
  protected:
463
  union {
B
Behdad Esfahbod 已提交
464
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
465
  MultipleSubstFormat1	format1;
466 467 468
  } u;
};

B
Behdad Esfahbod 已提交
469

B
Behdad Esfahbod 已提交
470
typedef ArrayOf<GlyphID> AlternateSet;	/* Array of alternate GlyphIDs--in
B
Behdad Esfahbod 已提交
471 472
					 * arbitrary order */

B
Behdad Esfahbod 已提交
473 474
struct AlternateSubstFormat1
{
475 476 477 478 479 480
  inline bool is_inplace (hb_is_inplace_context_t *c) const
  {
    TRACE_IS_INPLACE (this);
    return TRACE_RETURN (true);
  }

B
Behdad Esfahbod 已提交
481
  inline void closure (hb_closure_context_t *c) const
482
  {
B
Behdad Esfahbod 已提交
483
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
484 485 486 487 488 489
    Coverage::Iter iter;
    for (iter.init (this+coverage); iter.more (); iter.next ()) {
      if (c->glyphs->has (iter.get_glyph ())) {
	const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
	unsigned int count = alt_set.len;
	for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
490
	  c->glyphs->add (alt_set[i]);
B
Behdad Esfahbod 已提交
491 492
      }
    }
493 494
  }

495 496
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
497
    TRACE_COLLECT_GLYPHS (this);
498 499
    Coverage::Iter iter;
    for (iter.init (this+coverage); iter.more (); iter.next ()) {
B
Minor  
Behdad Esfahbod 已提交
500
      c->input->add (iter.get_glyph ());
501 502 503
      const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
      unsigned int count = alt_set.len;
      for (unsigned int i = 0; i < count; i++)
B
Minor  
Behdad Esfahbod 已提交
504
	c->output->add (alt_set[i]);
505 506 507
    }
  }

508 509 510 511 512
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

513 514
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
515
    TRACE_WOULD_APPLY (this);
516
    return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
517 518
  }

B
Behdad Esfahbod 已提交
519
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
520
  {
B
Behdad Esfahbod 已提交
521
    TRACE_APPLY (this);
522
    hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
523

524
    unsigned int index = (this+coverage).get_coverage (glyph_id);
525
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
526

B
Behdad Esfahbod 已提交
527
    const AlternateSet &alt_set = this+alternateSet[index];
528

529
    if (unlikely (!alt_set.len)) return TRACE_RETURN (false);
530

531
    hb_mask_t glyph_mask = c->buffer->cur().mask;
B
Behdad Esfahbod 已提交
532 533
    hb_mask_t lookup_mask = c->lookup_mask;

B
Behdad Esfahbod 已提交
534
    /* Note: This breaks badly if two features enabled this lookup together. */
B
Behdad Esfahbod 已提交
535
    unsigned int shift = _hb_ctz (lookup_mask);
B
Behdad Esfahbod 已提交
536
    unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
537

538
    if (unlikely (alt_index > alt_set.len || alt_index == 0)) return TRACE_RETURN (false);
539

B
Behdad Esfahbod 已提交
540
    glyph_id = alt_set[alt_index - 1];
541

542
    c->replace_glyph (glyph_id);
543

544
    return TRACE_RETURN (true);
545
  }
B
Behdad Esfahbod 已提交
546

547
  inline bool serialize (hb_serialize_context_t *c,
548 549
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &alternate_len_list,
550
			 unsigned int num_glyphs,
551
			 Supplier<GlyphID> &alternate_glyphs_list)
552
  {
B
Behdad Esfahbod 已提交
553
    TRACE_SERIALIZE (this);
554 555
    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
    if (unlikely (!alternateSet.serialize (c, num_glyphs))) return TRACE_RETURN (false);
556 557 558 559 560
    for (unsigned int i = 0; i < num_glyphs; i++)
      if (unlikely (!alternateSet[i].serialize (c, this).serialize (c,
								    alternate_glyphs_list,
								    alternate_len_list[i]))) return TRACE_RETURN (false);
    alternate_len_list.advance (num_glyphs);
561
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
562 563 564
    return TRACE_RETURN (true);
  }

B
Behdad Esfahbod 已提交
565
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
566
    TRACE_SANITIZE (this);
567
    return TRACE_RETURN (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
568 569
  }

570
  protected:
B
Behdad Esfahbod 已提交
571
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
572 573
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
574
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
575 576 577
  OffsetArrayOf<AlternateSet>
		alternateSet;		/* Array of AlternateSet tables
					 * ordered by Coverage Index */
578
  public:
579
  DEFINE_SIZE_ARRAY (6, alternateSet);
B
Behdad Esfahbod 已提交
580
};
581

B
Behdad Esfahbod 已提交
582 583
struct AlternateSubst
{
584
  inline bool serialize (hb_serialize_context_t *c,
585 586
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &alternate_len_list,
587
			 unsigned int num_glyphs,
588
			 Supplier<GlyphID> &alternate_glyphs_list)
589
  {
B
Behdad Esfahbod 已提交
590
    TRACE_SERIALIZE (this);
591 592 593 594 595 596 597 598 599
    if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
    unsigned int format = 1;
    u.format.set (format);
    switch (u.format) {
    case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, alternate_len_list, num_glyphs, alternate_glyphs_list));
    default:return TRACE_RETURN (false);
    }
  }

B
Behdad Esfahbod 已提交
600 601 602 603 604 605 606 607 608 609
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
  {
    TRACE_DISPATCH (this);
    switch (u.format) {
    case 1: return TRACE_RETURN (c->dispatch (u.format1));
    default:return TRACE_RETURN (c->default_return_value ());
    }
  }

B
Behdad Esfahbod 已提交
610
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
611
    TRACE_SANITIZE (this);
612
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
613
    switch (u.format) {
614 615
    case 1: return TRACE_RETURN (u.format1.sanitize (c));
    default:return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
616 617 618
    }
  }

619
  protected:
620
  union {
B
Behdad Esfahbod 已提交
621
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
622
  AlternateSubstFormat1	format1;
623 624 625
  } u;
};

626

B
Behdad Esfahbod 已提交
627 628
struct Ligature
{
B
Behdad Esfahbod 已提交
629
  inline void closure (hb_closure_context_t *c) const
630
  {
B
Behdad Esfahbod 已提交
631
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
632 633 634
    unsigned int count = component.len;
    for (unsigned int i = 1; i < count; i++)
      if (!c->glyphs->has (component[i]))
B
Behdad Esfahbod 已提交
635 636
        return;
    c->glyphs->add (ligGlyph);
637 638
  }

639 640
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
641
    TRACE_COLLECT_GLYPHS (this);
642 643
    unsigned int count = component.len;
    for (unsigned int i = 1; i < count; i++)
B
Minor  
Behdad Esfahbod 已提交
644 645
      c->input->add (component[i]);
    c->output->add (ligGlyph);
646 647
  }

648
  inline bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
649
  {
B
Behdad Esfahbod 已提交
650
    TRACE_WOULD_APPLY (this);
651
    if (c->len != component.len)
652
      return TRACE_RETURN (false);
653 654 655

    for (unsigned int i = 1; i < c->len; i++)
      if (likely (c->glyphs[i] != component[i]))
656
	return TRACE_RETURN (false);
657

658
    return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
659 660
  }

661
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
662
  {
B
Behdad Esfahbod 已提交
663
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
664
    unsigned int count = component.len;
665
    if (unlikely (count < 1)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
666

B
Behdad Esfahbod 已提交
667 668
    bool is_mark_ligature = false;
    unsigned int total_component_count = 0;
669

670 671 672
    unsigned int match_length = 0;
    unsigned int match_positions[MAX_CONTEXT_LENGTH];

673 674 675 676
    if (likely (!match_input (c, count,
			      &component[1],
			      match_glyph,
			      NULL,
677 678
			      &match_length,
			      match_positions,
679 680 681
			      &is_mark_ligature,
			      &total_component_count)))
      return TRACE_RETURN (false);
682

683 684
    ligate_input (c,
		  count,
685 686
		  match_positions,
		  match_length,
687
		  ligGlyph,
688 689
		  is_mark_ligature,
		  total_component_count);
690

691
    return TRACE_RETURN (true);
692
  }
693

694 695 696 697 698
  inline bool serialize (hb_serialize_context_t *c,
			 GlyphID ligature,
			 Supplier<GlyphID> &components, /* Starting from second */
			 unsigned int num_components /* Including first component */)
  {
B
Behdad Esfahbod 已提交
699
    TRACE_SERIALIZE (this);
700
    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
701
    ligGlyph = ligature;
702 703 704 705
    if (unlikely (!component.serialize (c, components, num_components))) return TRACE_RETURN (false);
    return TRACE_RETURN (true);
  }

B
Behdad Esfahbod 已提交
706
  public:
B
Behdad Esfahbod 已提交
707
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
708
    TRACE_SANITIZE (this);
709
    return TRACE_RETURN (ligGlyph.sanitize (c) && component.sanitize (c));
B
Behdad Esfahbod 已提交
710 711
  }

712
  protected:
713
  GlyphID	ligGlyph;		/* GlyphID of ligature to substitute */
B
Behdad Esfahbod 已提交
714 715
  HeadlessArrayOf<GlyphID>
		component;		/* Array of component GlyphIDs--start
716 717
					 * with the second  component--ordered
					 * in writing direction */
718
  public:
719
  DEFINE_SIZE_ARRAY (4, component);
720
};
B
Behdad Esfahbod 已提交
721

B
Behdad Esfahbod 已提交
722 723
struct LigatureSet
{
B
Behdad Esfahbod 已提交
724
  inline void closure (hb_closure_context_t *c) const
725
  {
B
Behdad Esfahbod 已提交
726
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
727 728
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
B
Behdad Esfahbod 已提交
729
      (this+ligature[i]).closure (c);
730 731
  }

732 733
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
734
    TRACE_COLLECT_GLYPHS (this);
735 736 737 738 739
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
      (this+ligature[i]).collect_glyphs (c);
  }

740
  inline bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
741
  {
B
Behdad Esfahbod 已提交
742
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
743 744 745 746
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
    {
      const Ligature &lig = this+ligature[i];
747
      if (lig.would_apply (c))
748
        return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
749
    }
750
    return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
751 752
  }

753
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
754
  {
B
Behdad Esfahbod 已提交
755
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
756
    unsigned int num_ligs = ligature.len;
B
Behdad Esfahbod 已提交
757 758
    for (unsigned int i = 0; i < num_ligs; i++)
    {
B
Behdad Esfahbod 已提交
759
      const Ligature &lig = this+ligature[i];
760
      if (lig.apply (c)) return TRACE_RETURN (true);
761 762
    }

763
    return TRACE_RETURN (false);
764
  }
B
Behdad Esfahbod 已提交
765

766 767 768 769 770 771
  inline bool serialize (hb_serialize_context_t *c,
			 Supplier<GlyphID> &ligatures,
			 Supplier<unsigned int> &component_count_list,
			 unsigned int num_ligatures,
			 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
  {
B
Behdad Esfahbod 已提交
772
    TRACE_SERIALIZE (this);
773 774 775 776 777 778 779
    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
    if (unlikely (!ligature.serialize (c, num_ligatures))) return TRACE_RETURN (false);
    for (unsigned int i = 0; i < num_ligatures; i++)
      if (unlikely (!ligature[i].serialize (c, this).serialize (c,
								ligatures[i],
								component_list,
								component_count_list[i]))) return TRACE_RETURN (false);
780
    ligatures.advance (num_ligatures);
781 782 783 784
    component_count_list.advance (num_ligatures);
    return TRACE_RETURN (true);
  }

B
Behdad Esfahbod 已提交
785
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
786
    TRACE_SANITIZE (this);
787
    return TRACE_RETURN (ligature.sanitize (c, this));
B
Behdad Esfahbod 已提交
788 789
  }

790
  protected:
B
Behdad Esfahbod 已提交
791 792 793
  OffsetArrayOf<Ligature>
		ligature;		/* Array LigatureSet tables
					 * ordered by preference */
794
  public:
795
  DEFINE_SIZE_ARRAY (2, ligature);
B
Behdad Esfahbod 已提交
796 797
};

B
Behdad Esfahbod 已提交
798 799
struct LigatureSubstFormat1
{
800 801 802 803 804 805
  inline bool is_inplace (hb_is_inplace_context_t *c) const
  {
    TRACE_IS_INPLACE (this);
    return TRACE_RETURN (false);
  }

B
Behdad Esfahbod 已提交
806
  inline void closure (hb_closure_context_t *c) const
807
  {
B
Behdad Esfahbod 已提交
808
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
809 810 811
    Coverage::Iter iter;
    for (iter.init (this+coverage); iter.more (); iter.next ()) {
      if (c->glyphs->has (iter.get_glyph ()))
B
Behdad Esfahbod 已提交
812
	(this+ligatureSet[iter.get_coverage ()]).closure (c);
B
Behdad Esfahbod 已提交
813
    }
814 815
  }

816 817
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
818
    TRACE_COLLECT_GLYPHS (this);
819 820
    Coverage::Iter iter;
    for (iter.init (this+coverage); iter.more (); iter.next ()) {
B
Minor  
Behdad Esfahbod 已提交
821
      c->input->add (iter.get_glyph ());
822 823 824 825
      (this+ligatureSet[iter.get_coverage ()]).collect_glyphs (c);
    }
  }

826 827 828 829 830
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

831
  inline bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
832
  {
B
Behdad Esfahbod 已提交
833
    TRACE_WOULD_APPLY (this);
834
    unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
835 836 837 838
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);

    const LigatureSet &lig_set = this+ligatureSet[index];
    return TRACE_RETURN (lig_set.would_apply (c));
B
Behdad Esfahbod 已提交
839 840
  }

B
Behdad Esfahbod 已提交
841
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
842
  {
B
Behdad Esfahbod 已提交
843
    TRACE_APPLY (this);
844
    hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
845

846
    unsigned int index = (this+coverage).get_coverage (glyph_id);
847
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
848

B
Behdad Esfahbod 已提交
849
    const LigatureSet &lig_set = this+ligatureSet[index];
850
    return TRACE_RETURN (lig_set.apply (c));
851
  }
B
Behdad Esfahbod 已提交
852

853 854 855 856 857 858 859 860
  inline bool serialize (hb_serialize_context_t *c,
			 Supplier<GlyphID> &first_glyphs,
			 Supplier<unsigned int> &ligature_per_first_glyph_count_list,
			 unsigned int num_first_glyphs,
			 Supplier<GlyphID> &ligatures_list,
			 Supplier<unsigned int> &component_count_list,
			 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
  {
B
Behdad Esfahbod 已提交
861
    TRACE_SERIALIZE (this);
862 863 864 865 866 867 868 869 870
    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
    if (unlikely (!ligatureSet.serialize (c, num_first_glyphs))) return TRACE_RETURN (false);
    for (unsigned int i = 0; i < num_first_glyphs; i++)
      if (unlikely (!ligatureSet[i].serialize (c, this).serialize (c,
								   ligatures_list,
								   component_count_list,
								   ligature_per_first_glyph_count_list[i],
								   component_list))) return TRACE_RETURN (false);
    ligature_per_first_glyph_count_list.advance (num_first_glyphs);
871
    if (unlikely (!coverage.serialize (c, this).serialize (c, first_glyphs, num_first_glyphs))) return TRACE_RETURN (false);
872 873 874
    return TRACE_RETURN (true);
  }

B
Behdad Esfahbod 已提交
875
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
876
    TRACE_SANITIZE (this);
877
    return TRACE_RETURN (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
878 879
  }

880
  protected:
B
Behdad Esfahbod 已提交
881
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
882 883
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
884
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
885
  OffsetArrayOf<LigatureSet>
B
Behdad Esfahbod 已提交
886 887
		ligatureSet;		/* Array LigatureSet tables
					 * ordered by Coverage Index */
888
  public:
889
  DEFINE_SIZE_ARRAY (6, ligatureSet);
B
Behdad Esfahbod 已提交
890
};
891

B
Behdad Esfahbod 已提交
892 893
struct LigatureSubst
{
894 895 896 897 898 899 900 901
  inline bool serialize (hb_serialize_context_t *c,
			 Supplier<GlyphID> &first_glyphs,
			 Supplier<unsigned int> &ligature_per_first_glyph_count_list,
			 unsigned int num_first_glyphs,
			 Supplier<GlyphID> &ligatures_list,
			 Supplier<unsigned int> &component_count_list,
			 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
  {
B
Behdad Esfahbod 已提交
902
    TRACE_SERIALIZE (this);
903 904 905 906 907 908 909 910 911 912
    if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
    unsigned int format = 1;
    u.format.set (format);
    switch (u.format) {
    case 1: return TRACE_RETURN (u.format1.serialize (c, first_glyphs, ligature_per_first_glyph_count_list, num_first_glyphs,
						      ligatures_list, component_count_list, component_list));
    default:return TRACE_RETURN (false);
    }
  }

B
Behdad Esfahbod 已提交
913 914 915 916 917 918 919 920 921 922
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
  {
    TRACE_DISPATCH (this);
    switch (u.format) {
    case 1: return TRACE_RETURN (c->dispatch (u.format1));
    default:return TRACE_RETURN (c->default_return_value ());
    }
  }

B
Behdad Esfahbod 已提交
923
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
924
    TRACE_SANITIZE (this);
925
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
926
    switch (u.format) {
927 928
    case 1: return TRACE_RETURN (u.format1.sanitize (c));
    default:return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
929 930 931
    }
  }

932
  protected:
933
  union {
B
Behdad Esfahbod 已提交
934
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
935
  LigatureSubstFormat1	format1;
936 937 938
  } u;
};

B
Behdad Esfahbod 已提交
939

B
Minor  
Behdad Esfahbod 已提交
940
struct ContextSubst : Context {};
B
Behdad Esfahbod 已提交
941

B
Minor  
Behdad Esfahbod 已提交
942
struct ChainContextSubst : ChainContext {};
943

B
Behdad Esfahbod 已提交
944
struct ExtensionSubst : Extension<ExtensionSubst>
B
Behdad Esfahbod 已提交
945
{
946
  typedef struct SubstLookupSubTable LookupSubTable;
B
Behdad Esfahbod 已提交
947

B
Behdad Esfahbod 已提交
948
  inline bool is_reverse (void) const;
949 950 951
};


B
Behdad Esfahbod 已提交
952 953
struct ReverseChainSingleSubstFormat1
{
954 955 956 957 958 959
  inline bool is_inplace (hb_is_inplace_context_t *c) const
  {
    TRACE_IS_INPLACE (this);
    return TRACE_RETURN (true);
  }

B
Behdad Esfahbod 已提交
960
  inline void closure (hb_closure_context_t *c) const
961
  {
B
Behdad Esfahbod 已提交
962
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
963 964 965 966 967 968 969
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);

    unsigned int count;

    count = backtrack.len;
    for (unsigned int i = 0; i < count; i++)
      if (!(this+backtrack[i]).intersects (c->glyphs))
B
Behdad Esfahbod 已提交
970
        return;
B
Behdad Esfahbod 已提交
971 972 973 974

    count = lookahead.len;
    for (unsigned int i = 0; i < count; i++)
      if (!(this+lookahead[i]).intersects (c->glyphs))
B
Behdad Esfahbod 已提交
975
        return;
B
Behdad Esfahbod 已提交
976 977 978 979 980

    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
    Coverage::Iter iter;
    for (iter.init (this+coverage); iter.more (); iter.next ()) {
      if (c->glyphs->has (iter.get_glyph ()))
B
Behdad Esfahbod 已提交
981
	c->glyphs->add (substitute[iter.get_coverage ()]);
B
Behdad Esfahbod 已提交
982
    }
983 984
  }

985 986
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
987 988
    TRACE_COLLECT_GLYPHS (this);

989 990 991 992
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);

    unsigned int count;

B
Minor  
Behdad Esfahbod 已提交
993
    (this+coverage).add_coverage (c->input);
994 995 996

    count = backtrack.len;
    for (unsigned int i = 0; i < count; i++)
B
Minor  
Behdad Esfahbod 已提交
997
      (this+backtrack[i]).add_coverage (c->before);
998 999 1000

    count = lookahead.len;
    for (unsigned int i = 0; i < count; i++)
B
Minor  
Behdad Esfahbod 已提交
1001
      (this+lookahead[i]).add_coverage (c->after);
1002 1003 1004 1005

    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
    count = substitute.len;
    for (unsigned int i = 0; i < count; i++)
B
Minor  
Behdad Esfahbod 已提交
1006
      c->output->add (substitute[i]);
1007 1008
  }

1009 1010 1011 1012 1013
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

1014 1015
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1016
    TRACE_WOULD_APPLY (this);
1017
    return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
1018 1019
  }

B
Behdad Esfahbod 已提交
1020
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1021
  {
B
Behdad Esfahbod 已提交
1022
    TRACE_APPLY (this);
1023 1024
    if (unlikely (c->nesting_level_left != MAX_NESTING_LEVEL))
      return TRACE_RETURN (false); /* No chaining to this type */
1025

1026
    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
1027
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
1028

1029 1030
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
1031

B
Behdad Esfahbod 已提交
1032
    if (match_backtrack (c,
B
Behdad Esfahbod 已提交
1033
			 backtrack.len, (USHORT *) backtrack.array,
B
Behdad Esfahbod 已提交
1034
			 match_coverage, this) &&
B
Behdad Esfahbod 已提交
1035
        match_lookahead (c,
B
Behdad Esfahbod 已提交
1036
			 lookahead.len, (USHORT *) lookahead.array,
B
Behdad Esfahbod 已提交
1037
			 match_coverage, this,
1038 1039
			 1))
    {
B
Behdad Esfahbod 已提交
1040
      c->replace_glyph_inplace (substitute[index]);
1041 1042 1043
      /* Note: We DON'T decrease buffer->idx.  The main loop does it
       * for us.  This is useful for preventing surprises if someone
       * calls us through a Context lookup. */
1044
      return TRACE_RETURN (true);
1045 1046
    }

1047
    return TRACE_RETURN (false);
1048
  }
B
Behdad Esfahbod 已提交
1049

B
Behdad Esfahbod 已提交
1050
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
1051
    TRACE_SANITIZE (this);
1052 1053
    if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
      return TRACE_RETURN (false);
1054
    OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
B
Behdad Esfahbod 已提交
1055
    if (!lookahead.sanitize (c, this))
1056
      return TRACE_RETURN (false);
1057
    ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
1058
    return TRACE_RETURN (substitute.sanitize (c));
B
Behdad Esfahbod 已提交
1059 1060
  }

1061
  protected:
B
Behdad Esfahbod 已提交
1062
  USHORT	format;			/* Format identifier--format = 1 */
1063 1064 1065 1066 1067
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of table */
  OffsetArrayOf<Coverage>
		backtrack;		/* Array of coverage tables
B
Behdad Esfahbod 已提交
1068 1069
					 * in backtracking sequence, in  glyph
					 * sequence order */
1070 1071 1072
  OffsetArrayOf<Coverage>
		lookaheadX;		/* Array of coverage tables
					 * in lookahead sequence, in glyph
B
Behdad Esfahbod 已提交
1073
					 * sequence order */
1074 1075 1076
  ArrayOf<GlyphID>
		substituteX;		/* Array of substitute
					 * GlyphIDs--ordered by Coverage Index */
1077
  public:
B
Behdad Esfahbod 已提交
1078
  DEFINE_SIZE_MIN (10);
B
Behdad Esfahbod 已提交
1079 1080
};

B
Behdad Esfahbod 已提交
1081 1082
struct ReverseChainSingleSubst
{
1083
  template <typename context_t>
1084
  inline typename context_t::return_t dispatch (context_t *c) const
1085
  {
1086
    TRACE_DISPATCH (this);
1087
    switch (u.format) {
1088
    case 1: return TRACE_RETURN (c->dispatch (u.format1));
B
Behdad Esfahbod 已提交
1089
    default:return TRACE_RETURN (c->default_return_value ());
1090 1091 1092
    }
  }

B
Behdad Esfahbod 已提交
1093
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
1094
    TRACE_SANITIZE (this);
1095
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1096
    switch (u.format) {
1097 1098
    case 1: return TRACE_RETURN (u.format1.sanitize (c));
    default:return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
1099 1100 1101
    }
  }

1102
  protected:
1103 1104
  union {
  USHORT				format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1105
  ReverseChainSingleSubstFormat1	format1;
1106 1107 1108 1109 1110
  } u;
};



B
Behdad Esfahbod 已提交
1111 1112 1113 1114
/*
 * SubstLookup
 */

B
Behdad Esfahbod 已提交
1115 1116
struct SubstLookupSubTable
{
B
Behdad Esfahbod 已提交
1117 1118
  friend struct SubstLookup;

B
Behdad Esfahbod 已提交
1119
  enum Type {
1120 1121 1122 1123 1124 1125 1126
    Single		= 1,
    Multiple		= 2,
    Alternate		= 3,
    Ligature		= 4,
    Context		= 5,
    ChainContext	= 6,
    Extension		= 7,
1127
    ReverseChainSingle	= 8
1128 1129
  };

1130
  template <typename context_t>
1131
  inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
1132
  {
1133
    TRACE_DISPATCH (this);
1134
    switch (lookup_type) {
1135 1136 1137 1138 1139 1140 1141 1142
    case Single:		return TRACE_RETURN (u.single.dispatch (c));
    case Multiple:		return TRACE_RETURN (u.multiple.dispatch (c));
    case Alternate:		return TRACE_RETURN (u.alternate.dispatch (c));
    case Ligature:		return TRACE_RETURN (u.ligature.dispatch (c));
    case Context:		return TRACE_RETURN (u.context.dispatch (c));
    case ChainContext:		return TRACE_RETURN (u.chainContext.dispatch (c));
    case Extension:		return TRACE_RETURN (u.extension.dispatch (c));
    case ReverseChainSingle:	return TRACE_RETURN (u.reverseChainContextSingle.dispatch (c));
B
Behdad Esfahbod 已提交
1143
    default:			return TRACE_RETURN (c->default_return_value ());
1144 1145 1146
    }
  }

B
Behdad Esfahbod 已提交
1147
  inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
B
Behdad Esfahbod 已提交
1148
    TRACE_SANITIZE (this);
1149
    if (!u.header.sub_format.sanitize (c))
1150
      return TRACE_RETURN (false);
1151
    switch (lookup_type) {
1152 1153 1154 1155
    case Single:		return TRACE_RETURN (u.single.sanitize (c));
    case Multiple:		return TRACE_RETURN (u.multiple.sanitize (c));
    case Alternate:		return TRACE_RETURN (u.alternate.sanitize (c));
    case Ligature:		return TRACE_RETURN (u.ligature.sanitize (c));
1156
    case Context:		return TRACE_RETURN (u.context.sanitize (c));
1157 1158 1159 1160
    case ChainContext:		return TRACE_RETURN (u.chainContext.sanitize (c));
    case Extension:		return TRACE_RETURN (u.extension.sanitize (c));
    case ReverseChainSingle:	return TRACE_RETURN (u.reverseChainContextSingle.sanitize (c));
    default:			return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
1161 1162 1163
    }
  }

1164
  protected:
B
Behdad Esfahbod 已提交
1165
  union {
1166 1167 1168
  struct {
    USHORT			sub_format;
  } header;
B
Behdad Esfahbod 已提交
1169 1170 1171 1172
  SingleSubst			single;
  MultipleSubst			multiple;
  AlternateSubst		alternate;
  LigatureSubst			ligature;
1173
  ContextSubst			context;
B
Behdad Esfahbod 已提交
1174 1175 1176
  ChainContextSubst		chainContext;
  ExtensionSubst		extension;
  ReverseChainSingleSubst	reverseChainContextSingle;
B
Behdad Esfahbod 已提交
1177
  } u;
B
Behdad Esfahbod 已提交
1178
  public:
1179
  DEFINE_SIZE_UNION (2, header.sub_format);
B
Behdad Esfahbod 已提交
1180 1181
};

1182

B
Behdad Esfahbod 已提交
1183 1184
struct SubstLookup : Lookup
{
1185 1186
  inline const SubstLookupSubTable& get_subtable (unsigned int i) const
  { return this+CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable)[i]; }
B
Behdad Esfahbod 已提交
1187

B
Behdad Esfahbod 已提交
1188
  inline static bool lookup_type_is_reverse (unsigned int lookup_type)
1189
  { return lookup_type == SubstLookupSubTable::ReverseChainSingle; }
B
Behdad Esfahbod 已提交
1190 1191

  inline bool is_reverse (void) const
B
Behdad Esfahbod 已提交
1192
  {
B
Behdad Esfahbod 已提交
1193
    unsigned int type = get_type ();
1194
    if (unlikely (type == SubstLookupSubTable::Extension))
1195
      return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
B
Behdad Esfahbod 已提交
1196
    return lookup_type_is_reverse (type);
B
Behdad Esfahbod 已提交
1197
  }
1198 1199 1200 1201 1202 1203 1204

  inline hb_is_inplace_context_t::return_t is_inplace (hb_is_inplace_context_t *c) const
  {
    TRACE_IS_INPLACE (this);
    c->set_recurse_func (dispatch_recurse_func<hb_is_inplace_context_t>);
    return TRACE_RETURN (dispatch (c));
  }
B
Behdad Esfahbod 已提交
1205

1206 1207
  inline hb_closure_context_t::return_t closure (hb_closure_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1208
    TRACE_CLOSURE (this);
1209 1210
    c->set_recurse_func (dispatch_recurse_func<hb_closure_context_t>);
    return TRACE_RETURN (dispatch (c));
B
Behdad Esfahbod 已提交
1211 1212
  }

B
Behdad Esfahbod 已提交
1213
  inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
B
Behdad Esfahbod 已提交
1214 1215
  {
    TRACE_COLLECT_GLYPHS (this);
1216 1217
    c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
    return TRACE_RETURN (dispatch (c));
1218 1219
  }

B
Behdad Esfahbod 已提交
1220 1221 1222
  template <typename set_t>
  inline void add_coverage (set_t *glyphs) const
  {
1223
    hb_get_coverage_context_t c;
B
Behdad Esfahbod 已提交
1224 1225 1226
    const Coverage *last = NULL;
    unsigned int count = get_subtable_count ();
    for (unsigned int i = 0; i < count; i++) {
1227
      const Coverage *coverage = &get_subtable (i).dispatch (&c, get_type ());
1228 1229 1230
      if (coverage != last) {
        coverage->add_coverage (glyphs);
        last = coverage;
B
Behdad Esfahbod 已提交
1231 1232 1233 1234
      }
    }
  }

B
Behdad Esfahbod 已提交
1235
  inline bool would_apply (hb_would_apply_context_t *c, const hb_set_digest_t *digest) const
B
Behdad Esfahbod 已提交
1236
  {
B
Behdad Esfahbod 已提交
1237
    TRACE_WOULD_APPLY (this);
1238 1239
    if (unlikely (!c->len))  return TRACE_RETURN (false);
    if (!digest->may_have (c->glyphs[0]))  return TRACE_RETURN (false);
1240
      return TRACE_RETURN (dispatch (c));
B
Behdad Esfahbod 已提交
1241 1242
  }

1243
  inline bool apply_once (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1244
  {
B
Behdad Esfahbod 已提交
1245
    TRACE_APPLY (this);
1246
    if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props))
B
Behdad Esfahbod 已提交
1247
      return TRACE_RETURN (false);
1248
    return TRACE_RETURN (dispatch (c));
B
Behdad Esfahbod 已提交
1249
  }
1250

1251
  static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);
B
Behdad Esfahbod 已提交
1252

1253 1254 1255 1256 1257 1258 1259 1260 1261 1262
  inline SubstLookupSubTable& serialize_subtable (hb_serialize_context_t *c,
						  unsigned int i)
  { return CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable)[i].serialize (c, this); }

  inline bool serialize_single (hb_serialize_context_t *c,
				uint32_t lookup_props,
			        Supplier<GlyphID> &glyphs,
			        Supplier<GlyphID> &substitutes,
			        unsigned int num_glyphs)
  {
B
Behdad Esfahbod 已提交
1263
    TRACE_SERIALIZE (this);
1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274
    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Single, lookup_props, 1))) return TRACE_RETURN (false);
    return TRACE_RETURN (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes, num_glyphs));
  }

  inline bool serialize_multiple (hb_serialize_context_t *c,
				  uint32_t lookup_props,
				  Supplier<GlyphID> &glyphs,
				  Supplier<unsigned int> &substitute_len_list,
				  unsigned int num_glyphs,
				  Supplier<GlyphID> &substitute_glyphs_list)
  {
B
Behdad Esfahbod 已提交
1275
    TRACE_SERIALIZE (this);
1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287
    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Multiple, lookup_props, 1))) return TRACE_RETURN (false);
    return TRACE_RETURN (serialize_subtable (c, 0).u.multiple.serialize (c, glyphs, substitute_len_list, num_glyphs,
									 substitute_glyphs_list));
  }

  inline bool serialize_alternate (hb_serialize_context_t *c,
				   uint32_t lookup_props,
				   Supplier<GlyphID> &glyphs,
				   Supplier<unsigned int> &alternate_len_list,
				   unsigned int num_glyphs,
				   Supplier<GlyphID> &alternate_glyphs_list)
  {
B
Behdad Esfahbod 已提交
1288
    TRACE_SERIALIZE (this);
1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302
    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Alternate, lookup_props, 1))) return TRACE_RETURN (false);
    return TRACE_RETURN (serialize_subtable (c, 0).u.alternate.serialize (c, glyphs, alternate_len_list, num_glyphs,
									  alternate_glyphs_list));
  }

  inline bool serialize_ligature (hb_serialize_context_t *c,
				  uint32_t lookup_props,
				  Supplier<GlyphID> &first_glyphs,
				  Supplier<unsigned int> &ligature_per_first_glyph_count_list,
				  unsigned int num_first_glyphs,
				  Supplier<GlyphID> &ligatures_list,
				  Supplier<unsigned int> &component_count_list,
				  Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
  {
B
Behdad Esfahbod 已提交
1303
    TRACE_SERIALIZE (this);
1304 1305 1306 1307 1308
    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Ligature, lookup_props, 1))) return TRACE_RETURN (false);
    return TRACE_RETURN (serialize_subtable (c, 0).u.ligature.serialize (c, first_glyphs, ligature_per_first_glyph_count_list, num_first_glyphs,
									 ligatures_list, component_count_list, component_list));
  }

B
Behdad Esfahbod 已提交
1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325
  template <typename context_t>
  static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);

  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
  {
    TRACE_DISPATCH (this);
    unsigned int lookup_type = get_type ();
    unsigned int count = get_subtable_count ();
    for (unsigned int i = 0; i < count; i++) {
      typename context_t::return_t r = get_subtable (i).dispatch (c, lookup_type);
      if (c->stop_sublookup_iteration (r))
        return TRACE_RETURN (r);
    }
    return TRACE_RETURN (c->default_return_value ());
  }

1326 1327
  inline bool sanitize (hb_sanitize_context_t *c)
  {
B
Behdad Esfahbod 已提交
1328
    TRACE_SANITIZE (this);
1329
    if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false);
1330
    OffsetArrayOf<SubstLookupSubTable> &list = CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable);
B
Behdad Esfahbod 已提交
1331 1332 1333 1334 1335 1336
    if (unlikely (!list.sanitize (c, this, get_type ()))) return TRACE_RETURN (false);

    if (unlikely (get_type () == SubstLookupSubTable::Extension))
    {
      /* The spec says all subtables of an Extension lookup should
       * have the same type.  This is specially important if one has
B
Minor  
Behdad Esfahbod 已提交
1337
       * a reverse type! */
B
Behdad Esfahbod 已提交
1338 1339 1340 1341 1342 1343 1344
      unsigned int type = get_subtable (0).u.extension.get_type ();
      unsigned int count = get_subtable_count ();
      for (unsigned int i = 1; i < count; i++)
        if (get_subtable (i).u.extension.get_type () != type)
	  return TRACE_RETURN (false);
    }
    return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
1345
  }
B
Behdad Esfahbod 已提交
1346 1347
};

B
Behdad Esfahbod 已提交
1348
typedef OffsetListOf<SubstLookup> SubstLookupList;
1349

B
Minor  
Behdad Esfahbod 已提交
1350
/*
B
Behdad Esfahbod 已提交
1351
 * GSUB -- The Glyph Substitution Table
B
Minor  
Behdad Esfahbod 已提交
1352 1353
 */

B
Behdad Esfahbod 已提交
1354 1355
struct GSUB : GSUBGPOS
{
1356
  static const hb_tag_t tableTag	= HB_OT_TAG_GSUB;
B
Minor  
Behdad Esfahbod 已提交
1357

B
Behdad Esfahbod 已提交
1358
  inline const SubstLookup& get_lookup (unsigned int i) const
1359
  { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
B
Behdad Esfahbod 已提交
1360

1361 1362
  static inline void substitute_start (hb_font_t *font, hb_buffer_t *buffer);
  static inline void substitute_finish (hb_font_t *font, hb_buffer_t *buffer);
B
Behdad Esfahbod 已提交
1363

B
Behdad Esfahbod 已提交
1364
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
1365
    TRACE_SANITIZE (this);
1366
    if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false);
1367
    OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
1368
    return TRACE_RETURN (list.sanitize (c, this));
B
Behdad Esfahbod 已提交
1369
  }
1370 1371
  public:
  DEFINE_SIZE_STATIC (10);
B
Minor  
Behdad Esfahbod 已提交
1372
};
1373 1374


B
Behdad Esfahbod 已提交
1375
void
1376
GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer)
B
Behdad Esfahbod 已提交
1377
{
B
Minor  
Behdad Esfahbod 已提交
1378
  HB_BUFFER_ALLOCATE_VAR (buffer, glyph_props);
1379
  HB_BUFFER_ALLOCATE_VAR (buffer, lig_props);
1380
  HB_BUFFER_ALLOCATE_VAR (buffer, syllable);
1381

1382
  const GDEF &gdef = *hb_ot_layout_from_face (font->face)->gdef;
B
Behdad Esfahbod 已提交
1383
  unsigned int count = buffer->len;
1384 1385
  for (unsigned int i = 0; i < count; i++) {
    buffer->info[i].lig_props() = buffer->info[i].syllable() = 0;
1386
    _hb_glyph_info_set_glyph_props (&buffer->info[i], gdef.get_glyph_props (buffer->info[i].codepoint));
1387
  }
B
Behdad Esfahbod 已提交
1388 1389 1390
}

void
1391
GSUB::substitute_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSED)
B
Behdad Esfahbod 已提交
1392 1393 1394 1395
{
}


B
Behdad Esfahbod 已提交
1396
/* Out-of-class implementation for methods recursing */
1397

B
Behdad Esfahbod 已提交
1398 1399 1400
inline bool ExtensionSubst::is_reverse (void) const
{
  unsigned int type = get_type ();
1401
  if (unlikely (type == SubstLookupSubTable::Extension))
1402
    return CastR<ExtensionSubst> (get_subtable<SubstLookupSubTable>()).is_reverse ();
B
Behdad Esfahbod 已提交
1403 1404 1405
  return SubstLookup::lookup_type_is_reverse (type);
}

1406
template <typename context_t>
1407
inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
1408 1409 1410
{
  const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
  const SubstLookup &l = gsub.get_lookup (lookup_index);
1411
  return l.dispatch (c);
1412 1413
}

1414
inline bool SubstLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
B
Behdad Esfahbod 已提交
1415
{
1416
  const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
1417
  const SubstLookup &l = gsub.get_lookup (lookup_index);
1418
  unsigned int saved_lookup_props = c->lookup_props;
1419
  c->set_lookup (l);
1420 1421 1422
  bool ret = l.apply_once (c);
  c->lookup_props = saved_lookup_props;
  return ret;
1423 1424 1425
}


B
Behdad Esfahbod 已提交
1426
} /* namespace OT */
1427

B
Behdad Esfahbod 已提交
1428

1429
#endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */