hb-ot-layout-gsub-table.hh 43.2 KB
Newer Older
B
Behdad Esfahbod 已提交
1
/*
B
Behdad Esfahbod 已提交
2
 * Copyright © 2007,2008,2009,2010  Red Hat, Inc.
B
Behdad Esfahbod 已提交
3
 * Copyright © 2010,2012  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
{
B
Behdad Esfahbod 已提交
40
  inline void closure (hb_closure_context_t *c) const
41
  {
B
Behdad Esfahbod 已提交
42
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
43 44 45 46
    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 已提交
47
	c->glyphs->add ((glyph_id + deltaGlyphID) & 0xFFFF);
B
Behdad Esfahbod 已提交
48
    }
49 50
  }

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

62 63 64 65 66
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

67 68
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
69
    TRACE_WOULD_APPLY (this);
70
    return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
71 72
  }

B
Behdad Esfahbod 已提交
73
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
74
  {
B
Behdad Esfahbod 已提交
75
    TRACE_APPLY (this);
76
    hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
77
    unsigned int index = (this+coverage).get_coverage (glyph_id);
78
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
79

80 81 82
    /* According to the Adobe Annotated OpenType Suite, result is always
     * limited to 16bit. */
    glyph_id = (glyph_id + deltaGlyphID) & 0xFFFF;
83
    c->replace_glyph (glyph_id);
B
Behdad Esfahbod 已提交
84

85
    return TRACE_RETURN (true);
86
  }
B
Behdad Esfahbod 已提交
87

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

B
Behdad Esfahbod 已提交
100
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
101
    TRACE_SANITIZE (this);
102
    return TRACE_RETURN (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
B
Behdad Esfahbod 已提交
103 104
  }

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

B
Behdad Esfahbod 已提交
116 117
struct SingleSubstFormat2
{
B
Behdad Esfahbod 已提交
118
  inline void closure (hb_closure_context_t *c) const
119
  {
B
Behdad Esfahbod 已提交
120
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
121 122 123
    Coverage::Iter iter;
    for (iter.init (this+coverage); iter.more (); iter.next ()) {
      if (c->glyphs->has (iter.get_glyph ()))
B
Behdad Esfahbod 已提交
124
	c->glyphs->add (substitute[iter.get_coverage ()]);
B
Behdad Esfahbod 已提交
125
    }
126 127
  }

128 129
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
130
    TRACE_COLLECT_GLYPHS (this);
131 132
    Coverage::Iter iter;
    for (iter.init (this+coverage); iter.more (); iter.next ()) {
B
Minor  
Behdad Esfahbod 已提交
133 134
      c->input->add (iter.get_glyph ());
      c->output->add (substitute[iter.get_coverage ()]);
135 136 137
    }
  }

138 139 140 141 142
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

143 144
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
145
    TRACE_WOULD_APPLY (this);
146
    return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
147 148
  }

B
Behdad Esfahbod 已提交
149
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
150
  {
B
Behdad Esfahbod 已提交
151
    TRACE_APPLY (this);
152
    hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
153
    unsigned int index = (this+coverage).get_coverage (glyph_id);
154
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
155

156
    if (unlikely (index >= substitute.len)) return TRACE_RETURN (false);
157 158

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

161
    return TRACE_RETURN (true);
162
  }
B
Behdad Esfahbod 已提交
163

B
Behdad Esfahbod 已提交
164
  inline bool serialize (hb_serialize_context_t *c,
165 166
			 Supplier<GlyphID> &glyphs,
			 Supplier<GlyphID> &substitutes,
B
Behdad Esfahbod 已提交
167 168
			 unsigned int num_glyphs)
  {
B
Behdad Esfahbod 已提交
169
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
170 171
    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
    if (unlikely (!substitute.serialize (c, substitutes, num_glyphs))) return TRACE_RETURN (false);
172
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
173 174 175
    return TRACE_RETURN (true);
  }

B
Behdad Esfahbod 已提交
176
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
177
    TRACE_SANITIZE (this);
178
    return TRACE_RETURN (coverage.sanitize (c, this) && substitute.sanitize (c));
B
Behdad Esfahbod 已提交
179 180
  }

181
  protected:
B
Behdad Esfahbod 已提交
182
  USHORT	format;			/* Format identifier--format = 2 */
B
Behdad Esfahbod 已提交
183 184
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
185
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
186 187 188
  ArrayOf<GlyphID>
		substitute;		/* Array of substitute
					 * GlyphIDs--ordered by Coverage Index */
189
  public:
190
  DEFINE_SIZE_ARRAY (6, substitute);
B
Behdad Esfahbod 已提交
191 192
};

B
Behdad Esfahbod 已提交
193 194
struct SingleSubst
{
195 196
  template <typename context_t>
  inline typename context_t::return_t process (context_t *c) const
197
  {
B
Behdad Esfahbod 已提交
198
    TRACE_PROCESS (this);
199
    switch (u.format) {
B
Behdad Esfahbod 已提交
200 201 202
    case 1: return TRACE_RETURN (c->process (u.format1));
    case 2: return TRACE_RETURN (c->process (u.format2));
    default:return TRACE_RETURN (c->default_return_value ());
203 204 205
    }
  }

B
Behdad Esfahbod 已提交
206
  inline bool serialize (hb_serialize_context_t *c,
207 208
			 Supplier<GlyphID> &glyphs,
			 Supplier<GlyphID> &substitutes,
B
Behdad Esfahbod 已提交
209 210
			 unsigned int num_glyphs)
  {
B
Behdad Esfahbod 已提交
211
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
212 213
    if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
    unsigned int format = 2;
B
Minor  
Behdad Esfahbod 已提交
214
    int delta;
B
Behdad Esfahbod 已提交
215 216
    if (num_glyphs) {
      format = 1;
B
Minor  
Behdad Esfahbod 已提交
217
      /* TODO(serialize) check for wrap-around */
B
Behdad Esfahbod 已提交
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
      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 已提交
233
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
234
    TRACE_SANITIZE (this);
235
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
236
    switch (u.format) {
237 238 239
    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 已提交
240 241 242
    }
  }

243
  protected:
244
  union {
B
Behdad Esfahbod 已提交
245
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
246 247
  SingleSubstFormat1	format1;
  SingleSubstFormat2	format2;
248
  } u;
B
Behdad Esfahbod 已提交
249
};
250

B
Behdad Esfahbod 已提交
251

B
Behdad Esfahbod 已提交
252 253
struct Sequence
{
B
Behdad Esfahbod 已提交
254
  inline void closure (hb_closure_context_t *c) const
255
  {
B
Behdad Esfahbod 已提交
256
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
257 258
    unsigned int count = substitute.len;
    for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
259
      c->glyphs->add (substitute[i]);
260 261
  }

262 263
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
264
    TRACE_COLLECT_GLYPHS (this);
265 266
    unsigned int count = substitute.len;
    for (unsigned int i = 0; i < count; i++)
B
Minor  
Behdad Esfahbod 已提交
267
      c->output->add (substitute[i]);
268 269
  }

B
Behdad Esfahbod 已提交
270
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
271
  {
B
Behdad Esfahbod 已提交
272
    TRACE_APPLY (this);
273
    if (unlikely (!substitute.len)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
274

275 276
    unsigned int klass = c->buffer->cur().glyph_props() &
			 HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE ? HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
277
    unsigned int count = substitute.len;
278
    for (unsigned int i = 0; i < count; i++) {
B
Behdad Esfahbod 已提交
279
      set_lig_props_for_component (c->buffer->cur(), i);
280
      c->output_glyph (substitute.array[i], klass);
281
    }
282
    c->buffer->skip_glyph ();
B
Behdad Esfahbod 已提交
283

284
    return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
285 286
  }

287
  inline bool serialize (hb_serialize_context_t *c,
288
			 Supplier<GlyphID> &glyphs,
289 290
			 unsigned int num_glyphs)
  {
B
Behdad Esfahbod 已提交
291
    TRACE_SERIALIZE (this);
292 293 294 295 296
    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 已提交
297
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
298
    TRACE_SANITIZE (this);
299
    return TRACE_RETURN (substitute.sanitize (c));
B
Behdad Esfahbod 已提交
300 301
  }

302
  protected:
B
Behdad Esfahbod 已提交
303 304
  ArrayOf<GlyphID>
		substitute;		/* String of GlyphIDs to substitute */
305
  public:
306
  DEFINE_SIZE_ARRAY (2, substitute);
B
Behdad Esfahbod 已提交
307 308
};

B
Behdad Esfahbod 已提交
309 310
struct MultipleSubstFormat1
{
B
Behdad Esfahbod 已提交
311
  inline void closure (hb_closure_context_t *c) const
312
  {
B
Behdad Esfahbod 已提交
313
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
314 315 316
    Coverage::Iter iter;
    for (iter.init (this+coverage); iter.more (); iter.next ()) {
      if (c->glyphs->has (iter.get_glyph ()))
B
Behdad Esfahbod 已提交
317
	(this+sequence[iter.get_coverage ()]).closure (c);
B
Behdad Esfahbod 已提交
318
    }
319 320
  }

321 322
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
323
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
324
    (this+coverage).add_coverage (c->input);
325 326 327 328 329
    unsigned int count = sequence.len;
    for (unsigned int i = 0; i < count; i++)
	(this+sequence[i]).collect_glyphs (c);
  }

330 331 332 333 334
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

335 336
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
337
    TRACE_WOULD_APPLY (this);
338
    return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
339 340
  }

B
Behdad Esfahbod 已提交
341
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
342
  {
B
Behdad Esfahbod 已提交
343
    TRACE_APPLY (this);
344

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

348
    return TRACE_RETURN ((this+sequence[index]).apply (c));
349
  }
B
Behdad Esfahbod 已提交
350

351
  inline bool serialize (hb_serialize_context_t *c,
352 353
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &substitute_len_list,
354
			 unsigned int num_glyphs,
355
			 Supplier<GlyphID> &substitute_glyphs_list)
356
  {
B
Behdad Esfahbod 已提交
357
    TRACE_SERIALIZE (this);
358 359
    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
    if (unlikely (!sequence.serialize (c, num_glyphs))) return TRACE_RETURN (false);
360 361 362 363 364
    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);
365
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
366 367 368
    return TRACE_RETURN (true);
  }

B
Behdad Esfahbod 已提交
369
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
370
    TRACE_SANITIZE (this);
371
    return TRACE_RETURN (coverage.sanitize (c, this) && sequence.sanitize (c, this));
B
Behdad Esfahbod 已提交
372 373
  }

374
  protected:
B
Behdad Esfahbod 已提交
375
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
376 377
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
378
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
379 380 381
  OffsetArrayOf<Sequence>
		sequence;		/* Array of Sequence tables
					 * ordered by Coverage Index */
382
  public:
383
  DEFINE_SIZE_ARRAY (6, sequence);
B
Behdad Esfahbod 已提交
384
};
385

B
Behdad Esfahbod 已提交
386 387
struct MultipleSubst
{
388 389
  template <typename context_t>
  inline typename context_t::return_t process (context_t *c) const
390
  {
B
Behdad Esfahbod 已提交
391
    TRACE_PROCESS (this);
392
    switch (u.format) {
B
Behdad Esfahbod 已提交
393 394
    case 1: return TRACE_RETURN (c->process (u.format1));
    default:return TRACE_RETURN (c->default_return_value ());
395 396 397
    }
  }

398
  inline bool serialize (hb_serialize_context_t *c,
399 400
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &substitute_len_list,
401
			 unsigned int num_glyphs,
402
			 Supplier<GlyphID> &substitute_glyphs_list)
403
  {
B
Behdad Esfahbod 已提交
404
    TRACE_SERIALIZE (this);
405 406 407 408 409 410 411 412 413
    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 已提交
414
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
415
    TRACE_SANITIZE (this);
416
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
417
    switch (u.format) {
418 419
    case 1: return TRACE_RETURN (u.format1.sanitize (c));
    default:return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
420 421 422
    }
  }

423
  protected:
424
  union {
B
Behdad Esfahbod 已提交
425
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
426
  MultipleSubstFormat1	format1;
427 428 429
  } u;
};

B
Behdad Esfahbod 已提交
430

B
Behdad Esfahbod 已提交
431
typedef ArrayOf<GlyphID> AlternateSet;	/* Array of alternate GlyphIDs--in
B
Behdad Esfahbod 已提交
432 433
					 * arbitrary order */

B
Behdad Esfahbod 已提交
434 435
struct AlternateSubstFormat1
{
B
Behdad Esfahbod 已提交
436
  inline void closure (hb_closure_context_t *c) const
437
  {
B
Behdad Esfahbod 已提交
438
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
439 440 441 442 443 444
    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 已提交
445
	  c->glyphs->add (alt_set[i]);
B
Behdad Esfahbod 已提交
446 447
      }
    }
448 449
  }

450 451
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
452
    TRACE_COLLECT_GLYPHS (this);
453 454
    Coverage::Iter iter;
    for (iter.init (this+coverage); iter.more (); iter.next ()) {
B
Minor  
Behdad Esfahbod 已提交
455
      c->input->add (iter.get_glyph ());
456 457 458
      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 已提交
459
	c->output->add (alt_set[i]);
460 461 462
    }
  }

463 464 465 466 467
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

468 469
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
470
    TRACE_WOULD_APPLY (this);
471
    return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
472 473
  }

B
Behdad Esfahbod 已提交
474
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
475
  {
B
Behdad Esfahbod 已提交
476
    TRACE_APPLY (this);
477
    hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
478

479
    unsigned int index = (this+coverage).get_coverage (glyph_id);
480
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
481

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

484
    if (unlikely (!alt_set.len)) return TRACE_RETURN (false);
485

486
    hb_mask_t glyph_mask = c->buffer->cur().mask;
B
Behdad Esfahbod 已提交
487 488
    hb_mask_t lookup_mask = c->lookup_mask;

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

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

B
Behdad Esfahbod 已提交
495
    glyph_id = alt_set[alt_index - 1];
496

497
    c->replace_glyph (glyph_id);
498

499
    return TRACE_RETURN (true);
500
  }
B
Behdad Esfahbod 已提交
501

502
  inline bool serialize (hb_serialize_context_t *c,
503 504
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &alternate_len_list,
505
			 unsigned int num_glyphs,
506
			 Supplier<GlyphID> &alternate_glyphs_list)
507
  {
B
Behdad Esfahbod 已提交
508
    TRACE_SERIALIZE (this);
509 510
    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
    if (unlikely (!alternateSet.serialize (c, num_glyphs))) return TRACE_RETURN (false);
511 512 513 514 515
    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);
516
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
517 518 519
    return TRACE_RETURN (true);
  }

B
Behdad Esfahbod 已提交
520
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
521
    TRACE_SANITIZE (this);
522
    return TRACE_RETURN (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
523 524
  }

525
  protected:
B
Behdad Esfahbod 已提交
526
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
527 528
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
529
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
530 531 532
  OffsetArrayOf<AlternateSet>
		alternateSet;		/* Array of AlternateSet tables
					 * ordered by Coverage Index */
533
  public:
534
  DEFINE_SIZE_ARRAY (6, alternateSet);
B
Behdad Esfahbod 已提交
535
};
536

B
Behdad Esfahbod 已提交
537 538
struct AlternateSubst
{
539 540
  template <typename context_t>
  inline typename context_t::return_t process (context_t *c) const
541
  {
B
Behdad Esfahbod 已提交
542
    TRACE_PROCESS (this);
543
    switch (u.format) {
B
Behdad Esfahbod 已提交
544 545
    case 1: return TRACE_RETURN (c->process (u.format1));
    default:return TRACE_RETURN (c->default_return_value ());
546 547 548
    }
  }

549
  inline bool serialize (hb_serialize_context_t *c,
550 551
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &alternate_len_list,
552
			 unsigned int num_glyphs,
553
			 Supplier<GlyphID> &alternate_glyphs_list)
554
  {
B
Behdad Esfahbod 已提交
555
    TRACE_SERIALIZE (this);
556 557 558 559 560 561 562 563 564
    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 已提交
565
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
566
    TRACE_SANITIZE (this);
567
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
568
    switch (u.format) {
569 570
    case 1: return TRACE_RETURN (u.format1.sanitize (c));
    default:return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
571 572 573
    }
  }

574
  protected:
575
  union {
B
Behdad Esfahbod 已提交
576
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
577
  AlternateSubstFormat1	format1;
578 579 580
  } u;
};

581

B
Behdad Esfahbod 已提交
582 583
struct Ligature
{
B
Behdad Esfahbod 已提交
584
  inline void closure (hb_closure_context_t *c) const
585
  {
B
Behdad Esfahbod 已提交
586
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
587 588 589
    unsigned int count = component.len;
    for (unsigned int i = 1; i < count; i++)
      if (!c->glyphs->has (component[i]))
B
Behdad Esfahbod 已提交
590 591
        return;
    c->glyphs->add (ligGlyph);
592 593
  }

594 595
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
596
    TRACE_COLLECT_GLYPHS (this);
597 598
    unsigned int count = component.len;
    for (unsigned int i = 1; i < count; i++)
B
Minor  
Behdad Esfahbod 已提交
599 600
      c->input->add (component[i]);
    c->output->add (ligGlyph);
601 602
  }

603
  inline bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
604
  {
B
Behdad Esfahbod 已提交
605
    TRACE_WOULD_APPLY (this);
606
    if (c->len != component.len)
607
      return TRACE_RETURN (false);
608 609 610

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

613
    return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
614 615
  }

616
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
617
  {
B
Behdad Esfahbod 已提交
618
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
619
    unsigned int count = component.len;
620
    if (unlikely (count < 1)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
621

B
Behdad Esfahbod 已提交
622 623 624
    unsigned int end_offset = 0;
    bool is_mark_ligature = false;
    unsigned int total_component_count = 0;
625 626 627 628 629 630 631 632 633

    if (likely (!match_input (c, count,
			      &component[1],
			      match_glyph,
			      NULL,
			      &end_offset,
			      &is_mark_ligature,
			      &total_component_count)))
      return TRACE_RETURN (false);
634

635
    /* Deal, we are forming the ligature. */
636
    c->buffer->merge_clusters (c->buffer->idx, c->buffer->idx + end_offset);
637

638 639 640 641 642
    ligate_input (c,
		  count,
		  &component[1],
		  match_glyph,
		  NULL,
643
		  ligGlyph,
644 645
		  is_mark_ligature,
		  total_component_count);
646

647
    return TRACE_RETURN (true);
648
  }
649

650 651 652 653 654
  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 已提交
655
    TRACE_SERIALIZE (this);
656
    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
657
    ligGlyph = ligature;
658 659 660 661
    if (unlikely (!component.serialize (c, components, num_components))) return TRACE_RETURN (false);
    return TRACE_RETURN (true);
  }

B
Behdad Esfahbod 已提交
662
  public:
B
Behdad Esfahbod 已提交
663
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
664
    TRACE_SANITIZE (this);
665
    return TRACE_RETURN (ligGlyph.sanitize (c) && component.sanitize (c));
B
Behdad Esfahbod 已提交
666 667
  }

668
  protected:
669
  GlyphID	ligGlyph;		/* GlyphID of ligature to substitute */
B
Behdad Esfahbod 已提交
670 671
  HeadlessArrayOf<GlyphID>
		component;		/* Array of component GlyphIDs--start
672 673
					 * with the second  component--ordered
					 * in writing direction */
674
  public:
675
  DEFINE_SIZE_ARRAY (4, component);
676
};
B
Behdad Esfahbod 已提交
677

B
Behdad Esfahbod 已提交
678 679
struct LigatureSet
{
B
Behdad Esfahbod 已提交
680
  inline void closure (hb_closure_context_t *c) const
681
  {
B
Behdad Esfahbod 已提交
682
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
683 684
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
B
Behdad Esfahbod 已提交
685
      (this+ligature[i]).closure (c);
686 687
  }

688 689
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
690
    TRACE_COLLECT_GLYPHS (this);
691 692 693 694 695
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
      (this+ligature[i]).collect_glyphs (c);
  }

696
  inline bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
697
  {
B
Behdad Esfahbod 已提交
698
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
699 700 701 702
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
    {
      const Ligature &lig = this+ligature[i];
703
      if (lig.would_apply (c))
704
        return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
705
    }
706
    return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
707 708
  }

709
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
710
  {
B
Behdad Esfahbod 已提交
711
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
712
    unsigned int num_ligs = ligature.len;
B
Behdad Esfahbod 已提交
713 714
    for (unsigned int i = 0; i < num_ligs; i++)
    {
B
Behdad Esfahbod 已提交
715
      const Ligature &lig = this+ligature[i];
716
      if (lig.apply (c)) return TRACE_RETURN (true);
717 718
    }

719
    return TRACE_RETURN (false);
720
  }
B
Behdad Esfahbod 已提交
721

722 723 724 725 726 727
  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 已提交
728
    TRACE_SERIALIZE (this);
729 730 731 732 733 734 735
    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);
736
    ligatures.advance (num_ligatures);
737 738 739 740
    component_count_list.advance (num_ligatures);
    return TRACE_RETURN (true);
  }

B
Behdad Esfahbod 已提交
741
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
742
    TRACE_SANITIZE (this);
743
    return TRACE_RETURN (ligature.sanitize (c, this));
B
Behdad Esfahbod 已提交
744 745
  }

746
  protected:
B
Behdad Esfahbod 已提交
747 748 749
  OffsetArrayOf<Ligature>
		ligature;		/* Array LigatureSet tables
					 * ordered by preference */
750
  public:
751
  DEFINE_SIZE_ARRAY (2, ligature);
B
Behdad Esfahbod 已提交
752 753
};

B
Behdad Esfahbod 已提交
754 755
struct LigatureSubstFormat1
{
B
Behdad Esfahbod 已提交
756
  inline void closure (hb_closure_context_t *c) const
757
  {
B
Behdad Esfahbod 已提交
758
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
759 760 761
    Coverage::Iter iter;
    for (iter.init (this+coverage); iter.more (); iter.next ()) {
      if (c->glyphs->has (iter.get_glyph ()))
B
Behdad Esfahbod 已提交
762
	(this+ligatureSet[iter.get_coverage ()]).closure (c);
B
Behdad Esfahbod 已提交
763
    }
764 765
  }

766 767
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
768
    TRACE_COLLECT_GLYPHS (this);
769 770
    Coverage::Iter iter;
    for (iter.init (this+coverage); iter.more (); iter.next ()) {
B
Minor  
Behdad Esfahbod 已提交
771
      c->input->add (iter.get_glyph ());
772 773 774 775
      (this+ligatureSet[iter.get_coverage ()]).collect_glyphs (c);
    }
  }

776 777 778 779 780
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

781
  inline bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
782
  {
B
Behdad Esfahbod 已提交
783
    TRACE_WOULD_APPLY (this);
784
    unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
785 786 787 788
    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 已提交
789 790
  }

B
Behdad Esfahbod 已提交
791
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
792
  {
B
Behdad Esfahbod 已提交
793
    TRACE_APPLY (this);
794
    hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
795

796
    unsigned int index = (this+coverage).get_coverage (glyph_id);
797
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
798

B
Behdad Esfahbod 已提交
799
    const LigatureSet &lig_set = this+ligatureSet[index];
800
    return TRACE_RETURN (lig_set.apply (c));
801
  }
B
Behdad Esfahbod 已提交
802

803 804 805 806 807 808 809 810
  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 已提交
811
    TRACE_SERIALIZE (this);
812 813 814 815 816 817 818 819 820
    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);
821
    if (unlikely (!coverage.serialize (c, this).serialize (c, first_glyphs, num_first_glyphs))) return TRACE_RETURN (false);
822 823 824
    return TRACE_RETURN (true);
  }

B
Behdad Esfahbod 已提交
825
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
826
    TRACE_SANITIZE (this);
827
    return TRACE_RETURN (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
828 829
  }

830
  protected:
B
Behdad Esfahbod 已提交
831
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
832 833
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
834
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
835
  OffsetArrayOf<LigatureSet>
B
Behdad Esfahbod 已提交
836 837
		ligatureSet;		/* Array LigatureSet tables
					 * ordered by Coverage Index */
838
  public:
839
  DEFINE_SIZE_ARRAY (6, ligatureSet);
B
Behdad Esfahbod 已提交
840
};
841

B
Behdad Esfahbod 已提交
842 843
struct LigatureSubst
{
844 845
  template <typename context_t>
  inline typename context_t::return_t process (context_t *c) const
846
  {
B
Behdad Esfahbod 已提交
847
    TRACE_PROCESS (this);
848
    switch (u.format) {
B
Behdad Esfahbod 已提交
849 850
    case 1: return TRACE_RETURN (c->process (u.format1));
    default:return TRACE_RETURN (c->default_return_value ());
B
Behdad Esfahbod 已提交
851 852 853
    }
  }

854 855 856 857 858 859 860 861
  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 已提交
862
    TRACE_SERIALIZE (this);
863 864 865 866 867 868 869 870 871 872
    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 已提交
873
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
874
    TRACE_SANITIZE (this);
875
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
876
    switch (u.format) {
877 878
    case 1: return TRACE_RETURN (u.format1.sanitize (c));
    default:return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
879 880 881
    }
  }

882
  protected:
883
  union {
B
Behdad Esfahbod 已提交
884
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
885
  LigatureSubstFormat1	format1;
886 887 888
  } u;
};

B
Behdad Esfahbod 已提交
889

B
Minor  
Behdad Esfahbod 已提交
890
struct ContextSubst : Context {};
B
Behdad Esfahbod 已提交
891

B
Minor  
Behdad Esfahbod 已提交
892
struct ChainContextSubst : ChainContext {};
893

B
Behdad Esfahbod 已提交
894
struct ExtensionSubst : Extension<ExtensionSubst>
B
Behdad Esfahbod 已提交
895
{
896
  typedef struct SubstLookupSubTable LookupSubTable;
B
Behdad Esfahbod 已提交
897

B
Behdad Esfahbod 已提交
898
  inline bool is_reverse (void) const;
899 900 901
};


B
Behdad Esfahbod 已提交
902 903
struct ReverseChainSingleSubstFormat1
{
B
Behdad Esfahbod 已提交
904
  inline void closure (hb_closure_context_t *c) const
905
  {
B
Behdad Esfahbod 已提交
906
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
907 908 909 910 911 912 913
    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 已提交
914
        return;
B
Behdad Esfahbod 已提交
915 916 917 918

    count = lookahead.len;
    for (unsigned int i = 0; i < count; i++)
      if (!(this+lookahead[i]).intersects (c->glyphs))
B
Behdad Esfahbod 已提交
919
        return;
B
Behdad Esfahbod 已提交
920 921 922 923 924

    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 已提交
925
	c->glyphs->add (substitute[iter.get_coverage ()]);
B
Behdad Esfahbod 已提交
926
    }
927 928
  }

929 930
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
931 932
    TRACE_COLLECT_GLYPHS (this);

933 934 935 936
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);

    unsigned int count;

B
Minor  
Behdad Esfahbod 已提交
937
    (this+coverage).add_coverage (c->input);
938 939 940

    count = backtrack.len;
    for (unsigned int i = 0; i < count; i++)
B
Minor  
Behdad Esfahbod 已提交
941
      (this+backtrack[i]).add_coverage (c->before);
942 943 944

    count = lookahead.len;
    for (unsigned int i = 0; i < count; i++)
B
Minor  
Behdad Esfahbod 已提交
945
      (this+lookahead[i]).add_coverage (c->after);
946 947 948 949

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

953 954 955 956 957
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

958 959
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
960
    TRACE_WOULD_APPLY (this);
961
    return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
962 963
  }

B
Behdad Esfahbod 已提交
964
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
965
  {
B
Behdad Esfahbod 已提交
966
    TRACE_APPLY (this);
967 968
    if (unlikely (c->nesting_level_left != MAX_NESTING_LEVEL))
      return TRACE_RETURN (false); /* No chaining to this type */
969

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

973 974
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
975

B
Behdad Esfahbod 已提交
976
    if (match_backtrack (c,
B
Behdad Esfahbod 已提交
977
			 backtrack.len, (USHORT *) backtrack.array,
B
Behdad Esfahbod 已提交
978
			 match_coverage, this) &&
B
Behdad Esfahbod 已提交
979
        match_lookahead (c,
B
Behdad Esfahbod 已提交
980
			 lookahead.len, (USHORT *) lookahead.array,
B
Behdad Esfahbod 已提交
981
			 match_coverage, this,
982 983
			 1))
    {
B
Behdad Esfahbod 已提交
984
      c->replace_glyph_inplace (substitute[index]);
985
      c->buffer->idx--; /* Reverse! */
986
      return TRACE_RETURN (true);
987 988
    }

989
    return TRACE_RETURN (false);
990
  }
B
Behdad Esfahbod 已提交
991

B
Behdad Esfahbod 已提交
992
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
993
    TRACE_SANITIZE (this);
994 995
    if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
      return TRACE_RETURN (false);
996
    OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
B
Behdad Esfahbod 已提交
997
    if (!lookahead.sanitize (c, this))
998
      return TRACE_RETURN (false);
999
    ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
1000
    return TRACE_RETURN (substitute.sanitize (c));
B
Behdad Esfahbod 已提交
1001 1002
  }

1003
  protected:
B
Behdad Esfahbod 已提交
1004
  USHORT	format;			/* Format identifier--format = 1 */
1005 1006 1007 1008 1009
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of table */
  OffsetArrayOf<Coverage>
		backtrack;		/* Array of coverage tables
B
Behdad Esfahbod 已提交
1010 1011
					 * in backtracking sequence, in  glyph
					 * sequence order */
1012 1013 1014
  OffsetArrayOf<Coverage>
		lookaheadX;		/* Array of coverage tables
					 * in lookahead sequence, in glyph
B
Behdad Esfahbod 已提交
1015
					 * sequence order */
1016 1017 1018
  ArrayOf<GlyphID>
		substituteX;		/* Array of substitute
					 * GlyphIDs--ordered by Coverage Index */
1019
  public:
B
Behdad Esfahbod 已提交
1020
  DEFINE_SIZE_MIN (10);
B
Behdad Esfahbod 已提交
1021 1022
};

B
Behdad Esfahbod 已提交
1023 1024
struct ReverseChainSingleSubst
{
1025 1026
  template <typename context_t>
  inline typename context_t::return_t process (context_t *c) const
1027
  {
B
Behdad Esfahbod 已提交
1028
    TRACE_PROCESS (this);
1029
    switch (u.format) {
B
Behdad Esfahbod 已提交
1030 1031
    case 1: return TRACE_RETURN (c->process (u.format1));
    default:return TRACE_RETURN (c->default_return_value ());
1032 1033 1034
    }
  }

B
Behdad Esfahbod 已提交
1035
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
1036
    TRACE_SANITIZE (this);
1037
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1038
    switch (u.format) {
1039 1040
    case 1: return TRACE_RETURN (u.format1.sanitize (c));
    default:return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
1041 1042 1043
    }
  }

1044
  protected:
1045 1046
  union {
  USHORT				format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1047
  ReverseChainSingleSubstFormat1	format1;
1048 1049 1050 1051 1052
  } u;
};



B
Behdad Esfahbod 已提交
1053 1054 1055 1056
/*
 * SubstLookup
 */

B
Behdad Esfahbod 已提交
1057 1058
struct SubstLookupSubTable
{
B
Behdad Esfahbod 已提交
1059 1060
  friend struct SubstLookup;

B
Behdad Esfahbod 已提交
1061
  enum Type {
1062 1063 1064 1065 1066 1067 1068
    Single		= 1,
    Multiple		= 2,
    Alternate		= 3,
    Ligature		= 4,
    Context		= 5,
    ChainContext	= 6,
    Extension		= 7,
1069
    ReverseChainSingle	= 8
1070 1071
  };

1072 1073
  template <typename context_t>
  inline typename context_t::return_t process (context_t *c, unsigned int lookup_type) const
1074
  {
B
Behdad Esfahbod 已提交
1075
    TRACE_PROCESS (this);
1076
    switch (lookup_type) {
B
Behdad Esfahbod 已提交
1077 1078 1079 1080 1081 1082 1083 1084 1085
    case Single:		return TRACE_RETURN (u.single.process (c));
    case Multiple:		return TRACE_RETURN (u.multiple.process (c));
    case Alternate:		return TRACE_RETURN (u.alternate.process (c));
    case Ligature:		return TRACE_RETURN (u.ligature.process (c));
    case Context:		return TRACE_RETURN (u.context.process (c));
    case ChainContext:		return TRACE_RETURN (u.chainContext.process (c));
    case Extension:		return TRACE_RETURN (u.extension.process (c));
    case ReverseChainSingle:	return TRACE_RETURN (u.reverseChainContextSingle.process (c));
    default:			return TRACE_RETURN (c->default_return_value ());
1086 1087 1088
    }
  }

B
Behdad Esfahbod 已提交
1089
  inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
B
Behdad Esfahbod 已提交
1090
    TRACE_SANITIZE (this);
1091
    if (!u.header.sub_format.sanitize (c))
1092
      return TRACE_RETURN (false);
1093
    switch (lookup_type) {
1094 1095 1096 1097
    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));
1098
    case Context:		return TRACE_RETURN (u.context.sanitize (c));
1099 1100 1101 1102
    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 已提交
1103 1104 1105
    }
  }

1106
  protected:
B
Behdad Esfahbod 已提交
1107
  union {
1108 1109 1110
  struct {
    USHORT			sub_format;
  } header;
B
Behdad Esfahbod 已提交
1111 1112 1113 1114
  SingleSubst			single;
  MultipleSubst			multiple;
  AlternateSubst		alternate;
  LigatureSubst			ligature;
1115
  ContextSubst			context;
B
Behdad Esfahbod 已提交
1116 1117 1118
  ChainContextSubst		chainContext;
  ExtensionSubst		extension;
  ReverseChainSingleSubst	reverseChainContextSingle;
B
Behdad Esfahbod 已提交
1119
  } u;
B
Behdad Esfahbod 已提交
1120
  public:
1121
  DEFINE_SIZE_UNION (2, header.sub_format);
B
Behdad Esfahbod 已提交
1122 1123
};

1124

B
Behdad Esfahbod 已提交
1125 1126
struct SubstLookup : Lookup
{
1127 1128
  inline const SubstLookupSubTable& get_subtable (unsigned int i) const
  { return this+CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable)[i]; }
B
Behdad Esfahbod 已提交
1129

B
Behdad Esfahbod 已提交
1130
  inline static bool lookup_type_is_reverse (unsigned int lookup_type)
1131
  { return lookup_type == SubstLookupSubTable::ReverseChainSingle; }
B
Behdad Esfahbod 已提交
1132 1133

  inline bool is_reverse (void) const
B
Behdad Esfahbod 已提交
1134
  {
B
Behdad Esfahbod 已提交
1135
    unsigned int type = get_type ();
1136
    if (unlikely (type == SubstLookupSubTable::Extension))
1137
      return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
B
Behdad Esfahbod 已提交
1138
    return lookup_type_is_reverse (type);
B
Behdad Esfahbod 已提交
1139 1140
  }

1141 1142
  template <typename context_t>
  inline typename context_t::return_t process (context_t *c) const
1143
  {
B
Behdad Esfahbod 已提交
1144
    TRACE_PROCESS (this);
1145
    unsigned int lookup_type = get_type ();
B
Behdad Esfahbod 已提交
1146
    unsigned int count = get_subtable_count ();
1147 1148 1149
    for (unsigned int i = 0; i < count; i++) {
      typename context_t::return_t r = get_subtable (i).process (c, lookup_type);
      if (c->stop_sublookup_iteration (r))
B
Behdad Esfahbod 已提交
1150
        return TRACE_RETURN (r);
1151
    }
B
Behdad Esfahbod 已提交
1152
    return TRACE_RETURN (c->default_return_value ());
1153
  }
1154 1155
  template <typename context_t>
  static inline typename context_t::return_t process_recurse_func (context_t *c, unsigned int lookup_index);
B
Behdad Esfahbod 已提交
1156

1157 1158
  inline hb_closure_context_t::return_t closure (hb_closure_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1159
    TRACE_CLOSURE (this);
1160
    c->set_recurse_func (process_recurse_func<hb_closure_context_t>);
B
Behdad Esfahbod 已提交
1161 1162 1163 1164 1165 1166 1167 1168
    return TRACE_RETURN (process (c));
  }

  inline hb_collect_glyphs_context_t::return_t collect_glyphs_lookup (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
    c->set_recurse_func (process_recurse_func<hb_collect_glyphs_context_t>);
    return TRACE_RETURN (process (c));
1169 1170
  }

B
Behdad Esfahbod 已提交
1171 1172 1173
  template <typename set_t>
  inline void add_coverage (set_t *glyphs) const
  {
1174
    hb_get_coverage_context_t c;
B
Behdad Esfahbod 已提交
1175 1176 1177
    const Coverage *last = NULL;
    unsigned int count = get_subtable_count ();
    for (unsigned int i = 0; i < count; i++) {
1178 1179 1180 1181
      const Coverage *coverage = &get_subtable (i).process (&c, get_type ());
      if (coverage != last) {
        coverage->add_coverage (glyphs);
        last = coverage;
B
Behdad Esfahbod 已提交
1182 1183 1184 1185
      }
    }
  }

B
Behdad Esfahbod 已提交
1186
  inline bool would_apply (hb_would_apply_context_t *c, const hb_set_digest_t *digest) const
B
Behdad Esfahbod 已提交
1187
  {
B
Behdad Esfahbod 已提交
1188
    TRACE_WOULD_APPLY (this);
1189 1190 1191
    if (unlikely (!c->len))  return TRACE_RETURN (false);
    if (!digest->may_have (c->glyphs[0]))  return TRACE_RETURN (false);
      return TRACE_RETURN (process (c));
B
Behdad Esfahbod 已提交
1192 1193
  }

1194
  inline bool apply_once (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1195
  {
B
Behdad Esfahbod 已提交
1196
    TRACE_APPLY (this);
1197
    if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props))
B
Behdad Esfahbod 已提交
1198 1199
      return TRACE_RETURN (false);
    return TRACE_RETURN (process (c));
B
Behdad Esfahbod 已提交
1200
  }
1201

1202
  static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);
B
Behdad Esfahbod 已提交
1203
  inline bool apply_string (hb_apply_context_t *c, const hb_set_digest_t *digest) const
B
Behdad Esfahbod 已提交
1204
  {
1205 1206
    bool ret = false;

B
Minor  
Behdad Esfahbod 已提交
1207
    if (unlikely (!c->buffer->len || !c->lookup_mask))
B
Behdad Esfahbod 已提交
1208 1209
      return false;

1210
    c->set_recurse_func (apply_recurse_func);
B
Behdad Esfahbod 已提交
1211
    c->set_lookup (*this);
1212

1213
    if (likely (!is_reverse ()))
B
Behdad Esfahbod 已提交
1214
    {
1215
	/* in/out forward substitution */
B
Behdad Esfahbod 已提交
1216 1217
	c->buffer->clear_output ();
	c->buffer->idx = 0;
1218

1219 1220 1221
	while (c->buffer->idx < c->buffer->len)
	{
	  if ((c->buffer->cur().mask & c->lookup_mask) &&
B
Behdad Esfahbod 已提交
1222
	      digest->may_have (c->buffer->cur().codepoint) &&
1223 1224 1225 1226 1227
	      apply_once (c))
	    ret = true;
	  else
	    c->buffer->next_glyph ();
	}
1228
	if (ret)
B
Behdad Esfahbod 已提交
1229
	  c->buffer->swap_buffers ();
B
Behdad Esfahbod 已提交
1230 1231 1232
    }
    else
    {
1233
	/* in-place backward substitution */
B
Behdad Esfahbod 已提交
1234
	c->buffer->remove_output ();
B
Behdad Esfahbod 已提交
1235
	c->buffer->idx = c->buffer->len - 1;
B
Behdad Esfahbod 已提交
1236 1237
	do
	{
1238
	  if ((c->buffer->cur().mask & c->lookup_mask) &&
B
Behdad Esfahbod 已提交
1239
	      digest->may_have (c->buffer->cur().codepoint) &&
1240
	      apply_once (c))
1241 1242
	    ret = true;
	  else
B
Behdad Esfahbod 已提交
1243
	    c->buffer->idx--;
1244

B
Behdad Esfahbod 已提交
1245
	}
B
Behdad Esfahbod 已提交
1246
	while ((int) c->buffer->idx >= 0);
1247 1248 1249 1250
    }

    return ret;
  }
B
Behdad Esfahbod 已提交
1251

1252 1253 1254 1255 1256 1257 1258 1259 1260 1261
  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 已提交
1262
    TRACE_SERIALIZE (this);
1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273
    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 已提交
1274
    TRACE_SERIALIZE (this);
1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286
    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 已提交
1287
    TRACE_SERIALIZE (this);
1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301
    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 已提交
1302
    TRACE_SERIALIZE (this);
1303 1304 1305 1306 1307 1308 1309
    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));
  }

  inline bool sanitize (hb_sanitize_context_t *c)
  {
B
Behdad Esfahbod 已提交
1310
    TRACE_SANITIZE (this);
1311
    if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false);
1312
    OffsetArrayOf<SubstLookupSubTable> &list = CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable);
B
Behdad Esfahbod 已提交
1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328
    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
       * a reverse type!
       *
       * We just check that they are all either forward, or reverse. */
      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 已提交
1329
  }
B
Behdad Esfahbod 已提交
1330 1331
};

B
Behdad Esfahbod 已提交
1332
typedef OffsetListOf<SubstLookup> SubstLookupList;
1333

B
Minor  
Behdad Esfahbod 已提交
1334
/*
B
Behdad Esfahbod 已提交
1335
 * GSUB -- The Glyph Substitution Table
B
Minor  
Behdad Esfahbod 已提交
1336 1337
 */

B
Behdad Esfahbod 已提交
1338 1339
struct GSUB : GSUBGPOS
{
B
Behdad Esfahbod 已提交
1340
  static const hb_tag_t Tag	= HB_OT_TAG_GSUB;
B
Minor  
Behdad Esfahbod 已提交
1341

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

1345 1346
  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 已提交
1347

B
Behdad Esfahbod 已提交
1348
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
1349
    TRACE_SANITIZE (this);
1350
    if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false);
1351
    OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
1352
    return TRACE_RETURN (list.sanitize (c, this));
B
Behdad Esfahbod 已提交
1353
  }
1354 1355
  public:
  DEFINE_SIZE_STATIC (10);
B
Minor  
Behdad Esfahbod 已提交
1356
};
1357 1358


B
Behdad Esfahbod 已提交
1359
void
1360
GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer)
B
Behdad Esfahbod 已提交
1361
{
B
Minor  
Behdad Esfahbod 已提交
1362
  HB_BUFFER_ALLOCATE_VAR (buffer, glyph_props);
1363
  HB_BUFFER_ALLOCATE_VAR (buffer, lig_props);
1364
  HB_BUFFER_ALLOCATE_VAR (buffer, syllable);
1365

1366
  const GDEF &gdef = *hb_ot_layout_from_face (font->face)->gdef;
B
Behdad Esfahbod 已提交
1367
  unsigned int count = buffer->len;
1368 1369
  for (unsigned int i = 0; i < count; i++) {
    buffer->info[i].lig_props() = buffer->info[i].syllable() = 0;
B
Minor  
Behdad Esfahbod 已提交
1370
    buffer->info[i].glyph_props() = gdef.get_glyph_props (buffer->info[i].codepoint);
1371
  }
B
Behdad Esfahbod 已提交
1372 1373 1374
}

void
1375
GSUB::substitute_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSED)
B
Behdad Esfahbod 已提交
1376 1377 1378 1379
{
}


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

B
Behdad Esfahbod 已提交
1382 1383 1384
inline bool ExtensionSubst::is_reverse (void) const
{
  unsigned int type = get_type ();
1385
  if (unlikely (type == SubstLookupSubTable::Extension))
1386
    return CastR<ExtensionSubst> (get_subtable<SubstLookupSubTable>()).is_reverse ();
B
Behdad Esfahbod 已提交
1387 1388 1389
  return SubstLookup::lookup_type_is_reverse (type);
}

1390 1391
template <typename context_t>
inline typename context_t::return_t SubstLookup::process_recurse_func (context_t *c, unsigned int lookup_index)
1392 1393 1394 1395 1396 1397
{
  const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
  const SubstLookup &l = gsub.get_lookup (lookup_index);
  return l.process (c);
}

1398
inline bool SubstLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
B
Behdad Esfahbod 已提交
1399
{
1400
  const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
1401
  const SubstLookup &l = gsub.get_lookup (lookup_index);
1402
  unsigned int saved_lookup_props = c->lookup_props;
1403
  c->set_lookup (l);
1404 1405 1406
  bool ret = l.apply_once (c);
  c->lookup_props = saved_lookup_props;
  return ret;
1407 1408 1409
}


B
Behdad Esfahbod 已提交
1410
} /* namespace OT */
1411

B
Behdad Esfahbod 已提交
1412

1413
#endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */