hb-ot-layout-gsub-table.hh 44.4 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.hh"
B
Behdad Esfahbod 已提交
33

B
Behdad Esfahbod 已提交
34

35 36
namespace OT {

37

B
Behdad Esfahbod 已提交
38 39
struct SingleSubstFormat1
{
40 41 42
  inline bool intersects (const hb_set_t *glyphs) const
  { return (this+coverage).intersects (glyphs); }

B
Behdad Esfahbod 已提交
43
  inline void closure (hb_closure_context_t *c) const
44
  {
B
Behdad Esfahbod 已提交
45
    TRACE_CLOSURE (this);
46
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
47 48
    {
      /* TODO Switch to range-based API to work around malicious fonts.
49
       * https://github.com/harfbuzz/harfbuzz/issues/363 */
B
Behdad Esfahbod 已提交
50 51
      hb_codepoint_t glyph_id = iter.get_glyph ();
      if (c->glyphs->has (glyph_id))
52
	c->out->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
B
Behdad Esfahbod 已提交
53
    }
54 55
  }

56 57
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
58
    TRACE_COLLECT_GLYPHS (this);
59
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
60
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
61 62
    {
      /* TODO Switch to range-based API to work around malicious fonts.
63
       * https://github.com/harfbuzz/harfbuzz/issues/363 */
64
      hb_codepoint_t glyph_id = iter.get_glyph ();
65
      c->output->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
66 67 68
    }
  }

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

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

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

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

B
Behdad Esfahbod 已提交
90
    return_trace (true);
91
  }
B
Behdad Esfahbod 已提交
92

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

105 106 107 108 109 110 111
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

B
Behdad Esfahbod 已提交
112 113
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
114
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
115
    return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
B
Behdad Esfahbod 已提交
116 117
  }

118
  protected:
B
Behdad Esfahbod 已提交
119
  HBUINT16	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
120 121
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
122
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
123
  HBINT16	deltaGlyphID;		/* Add to original GlyphID to get
B
Behdad Esfahbod 已提交
124
					 * substitute GlyphID */
125 126
  public:
  DEFINE_SIZE_STATIC (6);
B
Behdad Esfahbod 已提交
127 128
};

B
Behdad Esfahbod 已提交
129 130
struct SingleSubstFormat2
{
131 132 133
  inline bool intersects (const hb_set_t *glyphs) const
  { return (this+coverage).intersects (glyphs); }

B
Behdad Esfahbod 已提交
134
  inline void closure (hb_closure_context_t *c) const
135
  {
B
Behdad Esfahbod 已提交
136
    TRACE_CLOSURE (this);
137
    unsigned int count = substitute.len;
138
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
139 140
    {
      if (unlikely (iter.get_coverage () >= count))
141
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
B
Behdad Esfahbod 已提交
142
      if (c->glyphs->has (iter.get_glyph ()))
143
	c->out->add (substitute[iter.get_coverage ()]);
B
Behdad Esfahbod 已提交
144
    }
145 146
  }

147 148
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
149
    TRACE_COLLECT_GLYPHS (this);
150
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
151
    unsigned int count = substitute.len;
152
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
153 154
    {
      if (unlikely (iter.get_coverage () >= count))
155
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
B
Minor  
Behdad Esfahbod 已提交
156
      c->output->add (substitute[iter.get_coverage ()]);
157 158 159
    }
  }

160
  inline const Coverage &get_coverage (void) const
161
  { return this+coverage; }
162

163 164
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
165
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
166
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
167 168
  }

169
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
170
  {
B
Behdad Esfahbod 已提交
171
    TRACE_APPLY (this);
172
    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
B
Behdad Esfahbod 已提交
173
    if (likely (index == NOT_COVERED)) return_trace (false);
174

B
Behdad Esfahbod 已提交
175
    if (unlikely (index >= substitute.len)) return_trace (false);
176

177
    c->replace_glyph (substitute[index]);
B
Behdad Esfahbod 已提交
178

B
Behdad Esfahbod 已提交
179
    return_trace (true);
180
  }
B
Behdad Esfahbod 已提交
181

B
Behdad Esfahbod 已提交
182
  inline bool serialize (hb_serialize_context_t *c,
183 184
			 Supplier<GlyphID> &glyphs,
			 Supplier<GlyphID> &substitutes,
B
Behdad Esfahbod 已提交
185 186
			 unsigned int num_glyphs)
  {
B
Behdad Esfahbod 已提交
187
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
188 189 190 191
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    if (unlikely (!substitute.serialize (c, substitutes, num_glyphs))) return_trace (false);
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
    return_trace (true);
B
Behdad Esfahbod 已提交
192 193
  }

194 195 196 197 198 199 200
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

B
Behdad Esfahbod 已提交
201 202
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
203
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
204
    return_trace (coverage.sanitize (c, this) && substitute.sanitize (c));
B
Behdad Esfahbod 已提交
205 206
  }

207
  protected:
B
Behdad Esfahbod 已提交
208
  HBUINT16	format;			/* Format identifier--format = 2 */
B
Behdad Esfahbod 已提交
209 210
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
211
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
212 213 214
  ArrayOf<GlyphID>
		substitute;		/* Array of substitute
					 * GlyphIDs--ordered by Coverage Index */
215
  public:
216
  DEFINE_SIZE_ARRAY (6, substitute);
B
Behdad Esfahbod 已提交
217 218
};

B
Behdad Esfahbod 已提交
219 220
struct SingleSubst
{
B
Behdad Esfahbod 已提交
221
  inline bool serialize (hb_serialize_context_t *c,
222 223
			 Supplier<GlyphID> &glyphs,
			 Supplier<GlyphID> &substitutes,
B
Behdad Esfahbod 已提交
224 225
			 unsigned int num_glyphs)
  {
B
Behdad Esfahbod 已提交
226
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
227
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
B
Behdad Esfahbod 已提交
228
    unsigned int format = 2;
B
Behdad Esfahbod 已提交
229
    int delta = 0;
B
Behdad Esfahbod 已提交
230 231
    if (num_glyphs) {
      format = 1;
B
Minor  
Behdad Esfahbod 已提交
232
      /* TODO(serialize) check for wrap-around */
B
Behdad Esfahbod 已提交
233 234 235 236 237 238 239 240 241
      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) {
B
Behdad Esfahbod 已提交
242 243 244
    case 1: return_trace (u.format1.serialize (c, glyphs, num_glyphs, delta));
    case 2: return_trace (u.format2.serialize (c, glyphs, substitutes, num_glyphs));
    default:return_trace (false);
B
Behdad Esfahbod 已提交
245 246 247
    }
  }

B
Behdad Esfahbod 已提交
248 249 250
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
  {
251
    TRACE_DISPATCH (this, u.format);
252
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
253
    switch (u.format) {
B
Behdad Esfahbod 已提交
254 255 256
    case 1: return_trace (c->dispatch (u.format1));
    case 2: return_trace (c->dispatch (u.format2));
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
257 258 259
    }
  }

260
  protected:
261
  union {
B
Behdad Esfahbod 已提交
262
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
263 264
  SingleSubstFormat1	format1;
  SingleSubstFormat2	format2;
265
  } u;
B
Behdad Esfahbod 已提交
266
};
267

B
Behdad Esfahbod 已提交
268

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

279 280
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
281
    TRACE_COLLECT_GLYPHS (this);
282
    c->output->add_array (substitute.arrayZ, substitute.len);
283 284
  }

285
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
286
  {
B
Behdad Esfahbod 已提交
287
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
288
    unsigned int count = substitute.len;
289

B
Behdad Esfahbod 已提交
290 291 292
    /* Special-case to make it in-place and not consider this
     * as a "multiplied" substitution. */
    if (unlikely (count == 1))
293
    {
294
      c->replace_glyph (substitute.arrayZ[0]);
B
Behdad Esfahbod 已提交
295
      return_trace (true);
296
    }
297
    /* Spec disallows this, but Uniscribe allows it.
298
     * https://github.com/harfbuzz/harfbuzz/issues/253 */
299 300 301 302 303
    else if (unlikely (count == 0))
    {
      c->buffer->delete_glyph ();
      return_trace (true);
    }
B
Behdad Esfahbod 已提交
304 305 306 307 308 309

    unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ?
			 HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;

    for (unsigned int i = 0; i < count; i++) {
      _hb_glyph_info_set_lig_props_for_component (&c->buffer->cur(), i);
310
      c->output_glyph_for_component (substitute.arrayZ[i], klass);
311
    }
B
Behdad Esfahbod 已提交
312
    c->buffer->skip_glyph ();
B
Behdad Esfahbod 已提交
313

B
Behdad Esfahbod 已提交
314
    return_trace (true);
B
Behdad Esfahbod 已提交
315 316
  }

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

B
Behdad Esfahbod 已提交
327 328
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
329
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
330
    return_trace (substitute.sanitize (c));
B
Behdad Esfahbod 已提交
331 332
  }

333
  protected:
B
Behdad Esfahbod 已提交
334 335
  ArrayOf<GlyphID>
		substitute;		/* String of GlyphIDs to substitute */
336
  public:
337
  DEFINE_SIZE_ARRAY (2, substitute);
B
Behdad Esfahbod 已提交
338 339
};

B
Behdad Esfahbod 已提交
340 341
struct MultipleSubstFormat1
{
342 343 344
  inline bool intersects (const hb_set_t *glyphs) const
  { return (this+coverage).intersects (glyphs); }

B
Behdad Esfahbod 已提交
345
  inline void closure (hb_closure_context_t *c) const
346
  {
B
Behdad Esfahbod 已提交
347
    TRACE_CLOSURE (this);
348
    unsigned int count = sequence.len;
349
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
350 351
    {
      if (unlikely (iter.get_coverage () >= count))
352
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
B
Behdad Esfahbod 已提交
353
      if (c->glyphs->has (iter.get_glyph ()))
B
Behdad Esfahbod 已提交
354
	(this+sequence[iter.get_coverage ()]).closure (c);
B
Behdad Esfahbod 已提交
355
    }
356 357
  }

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

367
  inline const Coverage &get_coverage (void) const
368
  { return this+coverage; }
369

370 371
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
372
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
373
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
374 375
  }

376
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
377
  {
B
Behdad Esfahbod 已提交
378
    TRACE_APPLY (this);
379

380
    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
B
Behdad Esfahbod 已提交
381
    if (likely (index == NOT_COVERED)) return_trace (false);
382

B
Behdad Esfahbod 已提交
383
    return_trace ((this+sequence[index]).apply (c));
384
  }
B
Behdad Esfahbod 已提交
385

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

404 405 406 407 408 409 410
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

B
Behdad Esfahbod 已提交
411 412
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
413
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
414
    return_trace (coverage.sanitize (c, this) && sequence.sanitize (c, this));
B
Behdad Esfahbod 已提交
415 416
  }

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

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

B
Behdad Esfahbod 已提交
447 448 449
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
  {
450
    TRACE_DISPATCH (this, u.format);
451
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
452
    switch (u.format) {
B
Behdad Esfahbod 已提交
453 454
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
455 456 457
    }
  }

458
  protected:
459
  union {
B
Behdad Esfahbod 已提交
460
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
461
  MultipleSubstFormat1	format1;
462 463 464
  } u;
};

465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497
struct AlternateSet
{
  inline void closure (hb_closure_context_t *c) const
  {
    TRACE_CLOSURE (this);
    unsigned int count = alternates.len;
    for (unsigned int i = 0; i < count; i++)
      c->out->add (alternates[i]);
  }

  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
    c->output->add_array (alternates.arrayZ, alternates.len);
  }

  inline bool apply (hb_ot_apply_context_t *c) const
  {
    TRACE_APPLY (this);
    unsigned int count = alternates.len;

    if (unlikely (!count)) return_trace (false);

    hb_mask_t glyph_mask = c->buffer->cur().mask;
    hb_mask_t lookup_mask = c->lookup_mask;

    /* Note: This breaks badly if two features enabled this lookup together. */
    unsigned int shift = hb_ctz (lookup_mask);
    unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);

    if (unlikely (alt_index > count || alt_index == 0)) return_trace (false);

    c->replace_glyph (alternates[alt_index - 1]);
B
Behdad Esfahbod 已提交
498

499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520
    return_trace (true);
  }

  inline bool serialize (hb_serialize_context_t *c,
			 Supplier<GlyphID> &glyphs,
			 unsigned int num_glyphs)
  {
    TRACE_SERIALIZE (this);
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    if (unlikely (!alternates.serialize (c, glyphs, num_glyphs))) return_trace (false);
    return_trace (true);
  }

  inline bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    return_trace (alternates.sanitize (c));
  }

  protected:
  ArrayOf<GlyphID>
		alternates;		/* Array of alternate GlyphIDs--in
B
Behdad Esfahbod 已提交
521
					 * arbitrary order */
522 523 524
  public:
  DEFINE_SIZE_ARRAY (2, alternates);
};
B
Behdad Esfahbod 已提交
525

B
Behdad Esfahbod 已提交
526 527
struct AlternateSubstFormat1
{
528 529 530
  inline bool intersects (const hb_set_t *glyphs) const
  { return (this+coverage).intersects (glyphs); }

B
Behdad Esfahbod 已提交
531
  inline void closure (hb_closure_context_t *c) const
532
  {
B
Behdad Esfahbod 已提交
533
    TRACE_CLOSURE (this);
534
    unsigned int count = alternateSet.len;
535
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
536 537
    {
      if (unlikely (iter.get_coverage () >= count))
538
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
539 540
      if (c->glyphs->has (iter.get_glyph ()))
	(this+alternateSet[iter.get_coverage ()]).closure (c);
B
Behdad Esfahbod 已提交
541
    }
542 543
  }

544 545
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
546
    TRACE_COLLECT_GLYPHS (this);
547
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
548
    unsigned int count = alternateSet.len;
549
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
550 551
    {
      if (unlikely (iter.get_coverage () >= count))
552
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
553
      (this+alternateSet[iter.get_coverage ()]).collect_glyphs (c);
554 555 556
    }
  }

557
  inline const Coverage &get_coverage (void) const
558
  { return this+coverage; }
559

560 561
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
562
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
563
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
564 565
  }

566
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
567
  {
B
Behdad Esfahbod 已提交
568
    TRACE_APPLY (this);
569

570
    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
B
Behdad Esfahbod 已提交
571
    if (likely (index == NOT_COVERED)) return_trace (false);
572

573
    return_trace ((this+alternateSet[index]).apply (c));
574
  }
B
Behdad Esfahbod 已提交
575

576
  inline bool serialize (hb_serialize_context_t *c,
577 578
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &alternate_len_list,
579
			 unsigned int num_glyphs,
580
			 Supplier<GlyphID> &alternate_glyphs_list)
581
  {
B
Behdad Esfahbod 已提交
582
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
583 584
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    if (unlikely (!alternateSet.serialize (c, num_glyphs))) return_trace (false);
585 586 587
    for (unsigned int i = 0; i < num_glyphs; i++)
      if (unlikely (!alternateSet[i].serialize (c, this).serialize (c,
								    alternate_glyphs_list,
B
Behdad Esfahbod 已提交
588
								    alternate_len_list[i]))) return_trace (false);
589
    alternate_len_list += num_glyphs;
B
Behdad Esfahbod 已提交
590 591
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
    return_trace (true);
592 593
  }

594 595 596 597 598 599 600
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

B
Behdad Esfahbod 已提交
601 602
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
603
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
604
    return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
605 606
  }

607
  protected:
B
Behdad Esfahbod 已提交
608
  HBUINT16	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
609 610
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
611
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
612 613 614
  OffsetArrayOf<AlternateSet>
		alternateSet;		/* Array of AlternateSet tables
					 * ordered by Coverage Index */
615
  public:
616
  DEFINE_SIZE_ARRAY (6, alternateSet);
B
Behdad Esfahbod 已提交
617
};
618

B
Behdad Esfahbod 已提交
619 620
struct AlternateSubst
{
621
  inline bool serialize (hb_serialize_context_t *c,
622 623
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &alternate_len_list,
624
			 unsigned int num_glyphs,
625
			 Supplier<GlyphID> &alternate_glyphs_list)
626
  {
B
Behdad Esfahbod 已提交
627
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
628
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
629 630 631
    unsigned int format = 1;
    u.format.set (format);
    switch (u.format) {
B
Behdad Esfahbod 已提交
632 633
    case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, num_glyphs, alternate_glyphs_list));
    default:return_trace (false);
634 635 636
    }
  }

B
Behdad Esfahbod 已提交
637 638 639
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
  {
640
    TRACE_DISPATCH (this, u.format);
641
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
642
    switch (u.format) {
B
Behdad Esfahbod 已提交
643 644
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
645 646 647
    }
  }

648
  protected:
649
  union {
B
Behdad Esfahbod 已提交
650
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
651
  AlternateSubstFormat1	format1;
652 653 654
  } u;
};

655

B
Behdad Esfahbod 已提交
656 657
struct Ligature
{
658 659 660 661 662 663 664 665 666
  inline bool intersects (const hb_set_t *glyphs) const
  {
    unsigned int count = component.len;
    for (unsigned int i = 1; i < count; i++)
      if (!glyphs->has (component[i]))
        return false;
    return true;
  }

B
Behdad Esfahbod 已提交
667
  inline void closure (hb_closure_context_t *c) const
668
  {
B
Behdad Esfahbod 已提交
669
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
670 671 672
    unsigned int count = component.len;
    for (unsigned int i = 1; i < count; i++)
      if (!c->glyphs->has (component[i]))
B
Behdad Esfahbod 已提交
673
        return;
674
    c->out->add (ligGlyph);
675 676
  }

677 678
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
679
    TRACE_COLLECT_GLYPHS (this);
680
    c->input->add_array (component.arrayZ, component.len ? component.len - 1 : 0);
B
Minor  
Behdad Esfahbod 已提交
681
    c->output->add (ligGlyph);
682 683
  }

684
  inline bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
685
  {
B
Behdad Esfahbod 已提交
686
    TRACE_WOULD_APPLY (this);
687
    if (c->len != component.len)
B
Behdad Esfahbod 已提交
688
      return_trace (false);
689 690 691

    for (unsigned int i = 1; i < c->len; i++)
      if (likely (c->glyphs[i] != component[i]))
B
Behdad Esfahbod 已提交
692
	return_trace (false);
693

B
Behdad Esfahbod 已提交
694
    return_trace (true);
B
Behdad Esfahbod 已提交
695 696
  }

697
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
698
  {
B
Behdad Esfahbod 已提交
699
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
700
    unsigned int count = component.len;
B
Behdad Esfahbod 已提交
701

B
Behdad Esfahbod 已提交
702
    if (unlikely (!count)) return_trace (false);
B
Behdad Esfahbod 已提交
703

704 705 706 707 708
    /* Special-case to make it in-place and not consider this
     * as a "ligated" substitution. */
    if (unlikely (count == 1))
    {
      c->replace_glyph (ligGlyph);
B
Behdad Esfahbod 已提交
709
      return_trace (true);
710 711
    }

B
Behdad Esfahbod 已提交
712 713
    bool is_mark_ligature = false;
    unsigned int total_component_count = 0;
714

715
    unsigned int match_length = 0;
716
    unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
717

718 719 720
    if (likely (!match_input (c, count,
			      &component[1],
			      match_glyph,
B
Behdad Esfahbod 已提交
721
			      nullptr,
722 723
			      &match_length,
			      match_positions,
724 725
			      &is_mark_ligature,
			      &total_component_count)))
B
Behdad Esfahbod 已提交
726
      return_trace (false);
727

728 729
    ligate_input (c,
		  count,
730 731
		  match_positions,
		  match_length,
732
		  ligGlyph,
733 734
		  is_mark_ligature,
		  total_component_count);
735

B
Behdad Esfahbod 已提交
736
    return_trace (true);
737
  }
738

739 740 741 742 743
  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 已提交
744
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
745
    if (unlikely (!c->extend_min (*this))) return_trace (false);
746
    ligGlyph = ligature;
B
Behdad Esfahbod 已提交
747 748
    if (unlikely (!component.serialize (c, components, num_components))) return_trace (false);
    return_trace (true);
749 750
  }

B
Behdad Esfahbod 已提交
751
  public:
B
Behdad Esfahbod 已提交
752 753
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
754
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
755
    return_trace (ligGlyph.sanitize (c) && component.sanitize (c));
B
Behdad Esfahbod 已提交
756 757
  }

758
  protected:
759
  GlyphID	ligGlyph;		/* GlyphID of ligature to substitute */
B
Behdad Esfahbod 已提交
760 761
  HeadlessArrayOf<GlyphID>
		component;		/* Array of component GlyphIDs--start
762 763
					 * with the second  component--ordered
					 * in writing direction */
764
  public:
765
  DEFINE_SIZE_ARRAY (4, component);
766
};
B
Behdad Esfahbod 已提交
767

B
Behdad Esfahbod 已提交
768 769
struct LigatureSet
{
770 771 772 773 774 775 776 777 778
  inline bool intersects (const hb_set_t *glyphs) const
  {
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
      if ((this+ligature[i]).intersects (glyphs))
        return true;
    return false;
  }

B
Behdad Esfahbod 已提交
779
  inline void closure (hb_closure_context_t *c) const
780
  {
B
Behdad Esfahbod 已提交
781
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
782 783
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
B
Behdad Esfahbod 已提交
784
      (this+ligature[i]).closure (c);
785 786
  }

787 788
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
789
    TRACE_COLLECT_GLYPHS (this);
790 791 792 793 794
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
      (this+ligature[i]).collect_glyphs (c);
  }

795
  inline bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
796
  {
B
Behdad Esfahbod 已提交
797
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
798 799 800 801
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
    {
      const Ligature &lig = this+ligature[i];
802
      if (lig.would_apply (c))
B
Behdad Esfahbod 已提交
803
        return_trace (true);
B
Behdad Esfahbod 已提交
804
    }
B
Behdad Esfahbod 已提交
805
    return_trace (false);
B
Behdad Esfahbod 已提交
806 807
  }

808
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
809
  {
B
Behdad Esfahbod 已提交
810
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
811
    unsigned int num_ligs = ligature.len;
B
Behdad Esfahbod 已提交
812 813
    for (unsigned int i = 0; i < num_ligs; i++)
    {
B
Behdad Esfahbod 已提交
814
      const Ligature &lig = this+ligature[i];
B
Behdad Esfahbod 已提交
815
      if (lig.apply (c)) return_trace (true);
816 817
    }

B
Behdad Esfahbod 已提交
818
    return_trace (false);
819
  }
B
Behdad Esfahbod 已提交
820

821 822 823 824 825 826
  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 已提交
827
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
828 829
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    if (unlikely (!ligature.serialize (c, num_ligatures))) return_trace (false);
830 831 832 833
    for (unsigned int i = 0; i < num_ligatures; i++)
      if (unlikely (!ligature[i].serialize (c, this).serialize (c,
								ligatures[i],
								component_list,
B
Behdad Esfahbod 已提交
834
								component_count_list[i]))) return_trace (false);
835 836
    ligatures += num_ligatures;
    component_count_list += num_ligatures;
B
Behdad Esfahbod 已提交
837
    return_trace (true);
838 839
  }

B
Behdad Esfahbod 已提交
840 841
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
842
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
843
    return_trace (ligature.sanitize (c, this));
B
Behdad Esfahbod 已提交
844 845
  }

846
  protected:
B
Behdad Esfahbod 已提交
847 848 849
  OffsetArrayOf<Ligature>
		ligature;		/* Array LigatureSet tables
					 * ordered by preference */
850
  public:
851
  DEFINE_SIZE_ARRAY (2, ligature);
B
Behdad Esfahbod 已提交
852 853
};

B
Behdad Esfahbod 已提交
854 855
struct LigatureSubstFormat1
{
856 857 858 859 860 861 862 863 864 865 866 867 868 869
  inline bool intersects (const hb_set_t *glyphs) const
  {
    unsigned int count = ligatureSet.len;
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
    {
      if (unlikely (iter.get_coverage () >= count))
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
      if (glyphs->has (iter.get_glyph ()) &&
	  (this+ligatureSet[iter.get_coverage ()]).intersects (glyphs))
        return true;
    }
    return false;
  }

B
Behdad Esfahbod 已提交
870
  inline void closure (hb_closure_context_t *c) const
871
  {
B
Behdad Esfahbod 已提交
872
    TRACE_CLOSURE (this);
873
    unsigned int count = ligatureSet.len;
874
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
875 876
    {
      if (unlikely (iter.get_coverage () >= count))
877
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
B
Behdad Esfahbod 已提交
878
      if (c->glyphs->has (iter.get_glyph ()))
B
Behdad Esfahbod 已提交
879
	(this+ligatureSet[iter.get_coverage ()]).closure (c);
B
Behdad Esfahbod 已提交
880
    }
881 882
  }

883 884
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
885
    TRACE_COLLECT_GLYPHS (this);
886
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
887
    unsigned int count = ligatureSet.len;
888
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
889 890
    {
      if (unlikely (iter.get_coverage () >= count))
891
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
892 893 894 895
      (this+ligatureSet[iter.get_coverage ()]).collect_glyphs (c);
    }
  }

896
  inline const Coverage &get_coverage (void) const
897
  { return this+coverage; }
898

899
  inline bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
900
  {
B
Behdad Esfahbod 已提交
901
    TRACE_WOULD_APPLY (this);
902
    unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
B
Behdad Esfahbod 已提交
903
    if (likely (index == NOT_COVERED)) return_trace (false);
904 905

    const LigatureSet &lig_set = this+ligatureSet[index];
B
Behdad Esfahbod 已提交
906
    return_trace (lig_set.would_apply (c));
B
Behdad Esfahbod 已提交
907 908
  }

909
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
910
  {
B
Behdad Esfahbod 已提交
911
    TRACE_APPLY (this);
912

913
    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
B
Behdad Esfahbod 已提交
914
    if (likely (index == NOT_COVERED)) return_trace (false);
915

B
Behdad Esfahbod 已提交
916
    const LigatureSet &lig_set = this+ligatureSet[index];
B
Behdad Esfahbod 已提交
917
    return_trace (lig_set.apply (c));
918
  }
B
Behdad Esfahbod 已提交
919

920 921 922 923 924 925 926 927
  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 已提交
928
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
929 930
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    if (unlikely (!ligatureSet.serialize (c, num_first_glyphs))) return_trace (false);
931 932 933 934 935
    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],
B
Behdad Esfahbod 已提交
936
								   component_list))) return_trace (false);
937
    ligature_per_first_glyph_count_list += num_first_glyphs;
B
Behdad Esfahbod 已提交
938 939
    if (unlikely (!coverage.serialize (c, this).serialize (c, first_glyphs, num_first_glyphs))) return_trace (false);
    return_trace (true);
940 941
  }

942 943 944 945 946 947 948
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

B
Behdad Esfahbod 已提交
949 950
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
951
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
952
    return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
953 954
  }

955
  protected:
B
Behdad Esfahbod 已提交
956
  HBUINT16	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
957 958
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
959
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
960
  OffsetArrayOf<LigatureSet>
B
Behdad Esfahbod 已提交
961 962
		ligatureSet;		/* Array LigatureSet tables
					 * ordered by Coverage Index */
963
  public:
964
  DEFINE_SIZE_ARRAY (6, ligatureSet);
B
Behdad Esfahbod 已提交
965
};
966

B
Behdad Esfahbod 已提交
967 968
struct LigatureSubst
{
969 970 971 972 973 974 975 976
  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 已提交
977
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
978
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
979 980 981
    unsigned int format = 1;
    u.format.set (format);
    switch (u.format) {
B
Behdad Esfahbod 已提交
982 983 984 985 986 987 988 989
    case 1: return_trace (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 (false);
990 991 992
    }
  }

B
Behdad Esfahbod 已提交
993 994 995
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
  {
996
    TRACE_DISPATCH (this, u.format);
997
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
998
    switch (u.format) {
B
Behdad Esfahbod 已提交
999 1000
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
1001 1002 1003
    }
  }

1004
  protected:
1005
  union {
B
Behdad Esfahbod 已提交
1006
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1007
  LigatureSubstFormat1	format1;
1008 1009 1010
  } u;
};

B
Behdad Esfahbod 已提交
1011

B
Minor  
Behdad Esfahbod 已提交
1012
struct ContextSubst : Context {};
B
Behdad Esfahbod 已提交
1013

B
Minor  
Behdad Esfahbod 已提交
1014
struct ChainContextSubst : ChainContext {};
1015

B
Behdad Esfahbod 已提交
1016
struct ExtensionSubst : Extension<ExtensionSubst>
B
Behdad Esfahbod 已提交
1017
{
B
Behdad Esfahbod 已提交
1018
  typedef struct SubstLookupSubTable SubTable;
B
Behdad Esfahbod 已提交
1019

B
Behdad Esfahbod 已提交
1020
  inline bool is_reverse (void) const;
1021 1022 1023
};


B
Behdad Esfahbod 已提交
1024 1025
struct ReverseChainSingleSubstFormat1
{
1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047
  inline bool intersects (const hb_set_t *glyphs) const
  {
    if (!(this+coverage).intersects (glyphs))
      return false;

    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 (glyphs))
        return false;

    count = lookahead.len;
    for (unsigned int i = 0; i < count; i++)
      if (!(this+lookahead[i]).intersects (glyphs))
        return false;

    return true;
  }

B
Behdad Esfahbod 已提交
1048
  inline void closure (hb_closure_context_t *c) const
1049
  {
B
Behdad Esfahbod 已提交
1050
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
1051 1052 1053 1054 1055 1056 1057
    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 已提交
1058
        return;
B
Behdad Esfahbod 已提交
1059 1060 1061 1062

    count = lookahead.len;
    for (unsigned int i = 0; i < count; i++)
      if (!(this+lookahead[i]).intersects (c->glyphs))
B
Behdad Esfahbod 已提交
1063
        return;
B
Behdad Esfahbod 已提交
1064 1065

    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
1066
    count = substitute.len;
1067
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
1068 1069
    {
      if (unlikely (iter.get_coverage () >= count))
1070
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
B
Behdad Esfahbod 已提交
1071
      if (c->glyphs->has (iter.get_glyph ()))
1072
	c->out->add (substitute[iter.get_coverage ()]);
B
Behdad Esfahbod 已提交
1073
    }
1074 1075
  }

1076 1077
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1078
    TRACE_COLLECT_GLYPHS (this);
1079
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
1080 1081 1082 1083 1084

    unsigned int count;

    count = backtrack.len;
    for (unsigned int i = 0; i < count; i++)
1085
      if (unlikely (!(this+backtrack[i]).add_coverage (c->before))) return;
1086

1087
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1088 1089
    count = lookahead.len;
    for (unsigned int i = 0; i < count; i++)
1090
      if (unlikely (!(this+lookahead[i]).add_coverage (c->after))) return;
1091 1092 1093

    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
    count = substitute.len;
1094
    c->output->add_array (substitute.arrayZ, substitute.len);
1095 1096
  }

1097
  inline const Coverage &get_coverage (void) const
1098
  { return this+coverage; }
1099

1100 1101
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1102
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
1103
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
1104 1105
  }

1106
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1107
  {
B
Behdad Esfahbod 已提交
1108
    TRACE_APPLY (this);
1109
    if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
B
Behdad Esfahbod 已提交
1110
      return_trace (false); /* No chaining to this type */
1111

1112
    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
B
Behdad Esfahbod 已提交
1113
    if (likely (index == NOT_COVERED)) return_trace (false);
1114

1115 1116
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
1117

1118
  unsigned int start_index = 0, end_index = 0;
B
Behdad Esfahbod 已提交
1119
    if (match_backtrack (c,
1120
			 backtrack.len, (HBUINT16 *) backtrack.arrayZ,
1121 1122
			 match_coverage, this,
			 &start_index) &&
B
Behdad Esfahbod 已提交
1123
        match_lookahead (c,
1124
			 lookahead.len, (HBUINT16 *) lookahead.arrayZ,
B
Behdad Esfahbod 已提交
1125
			 match_coverage, this,
1126
			 1, &end_index))
1127
    {
1128
      c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index);
B
Behdad Esfahbod 已提交
1129
      c->replace_glyph_inplace (substitute[index]);
1130 1131 1132
      /* 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. */
B
Behdad Esfahbod 已提交
1133
      return_trace (true);
1134 1135
    }

B
Behdad Esfahbod 已提交
1136
    return_trace (false);
1137
  }
B
Behdad Esfahbod 已提交
1138

1139 1140 1141 1142 1143 1144 1145
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

B
Behdad Esfahbod 已提交
1146 1147
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1148
    TRACE_SANITIZE (this);
1149
    if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
B
Behdad Esfahbod 已提交
1150
      return_trace (false);
B
Behdad Esfahbod 已提交
1151
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
B
Behdad Esfahbod 已提交
1152
    if (!lookahead.sanitize (c, this))
B
Behdad Esfahbod 已提交
1153
      return_trace (false);
B
Behdad Esfahbod 已提交
1154
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
B
Behdad Esfahbod 已提交
1155
    return_trace (substitute.sanitize (c));
B
Behdad Esfahbod 已提交
1156 1157
  }

1158
  protected:
B
Behdad Esfahbod 已提交
1159
  HBUINT16	format;			/* Format identifier--format = 1 */
1160 1161 1162 1163 1164
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of table */
  OffsetArrayOf<Coverage>
		backtrack;		/* Array of coverage tables
1165
					 * in backtracking sequence, in glyph
B
Behdad Esfahbod 已提交
1166
					 * sequence order */
1167 1168 1169
  OffsetArrayOf<Coverage>
		lookaheadX;		/* Array of coverage tables
					 * in lookahead sequence, in glyph
B
Behdad Esfahbod 已提交
1170
					 * sequence order */
1171 1172 1173
  ArrayOf<GlyphID>
		substituteX;		/* Array of substitute
					 * GlyphIDs--ordered by Coverage Index */
1174
  public:
B
Behdad Esfahbod 已提交
1175
  DEFINE_SIZE_MIN (10);
B
Behdad Esfahbod 已提交
1176 1177
};

B
Behdad Esfahbod 已提交
1178 1179
struct ReverseChainSingleSubst
{
1180
  template <typename context_t>
1181
  inline typename context_t::return_t dispatch (context_t *c) const
1182
  {
1183
    TRACE_DISPATCH (this, u.format);
1184
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1185
    switch (u.format) {
B
Behdad Esfahbod 已提交
1186 1187
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
1188 1189 1190
    }
  }

1191
  protected:
1192
  union {
B
Behdad Esfahbod 已提交
1193
  HBUINT16				format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1194
  ReverseChainSingleSubstFormat1	format1;
1195 1196 1197 1198 1199
  } u;
};



B
Behdad Esfahbod 已提交
1200 1201 1202 1203
/*
 * SubstLookup
 */

B
Behdad Esfahbod 已提交
1204 1205
struct SubstLookupSubTable
{
B
Behdad Esfahbod 已提交
1206
  friend struct Lookup;
B
Behdad Esfahbod 已提交
1207 1208
  friend struct SubstLookup;

B
Behdad Esfahbod 已提交
1209
  enum Type {
1210 1211 1212 1213 1214 1215 1216
    Single		= 1,
    Multiple		= 2,
    Alternate		= 3,
    Ligature		= 4,
    Context		= 5,
    ChainContext	= 6,
    Extension		= 7,
1217
    ReverseChainSingle	= 8
1218 1219
  };

1220
  template <typename context_t>
1221
  inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
1222
  {
1223
    TRACE_DISPATCH (this, lookup_type);
1224
    if (unlikely (!c->may_dispatch (this, &u.sub_format))) return_trace (c->no_dispatch_return_value ());
1225
    switch (lookup_type) {
B
Behdad Esfahbod 已提交
1226 1227 1228 1229 1230 1231 1232 1233 1234
    case Single:		return_trace (u.single.dispatch (c));
    case Multiple:		return_trace (u.multiple.dispatch (c));
    case Alternate:		return_trace (u.alternate.dispatch (c));
    case Ligature:		return_trace (u.ligature.dispatch (c));
    case Context:		return_trace (u.context.dispatch (c));
    case ChainContext:		return_trace (u.chainContext.dispatch (c));
    case Extension:		return_trace (u.extension.dispatch (c));
    case ReverseChainSingle:	return_trace (u.reverseChainContextSingle.dispatch (c));
    default:			return_trace (c->default_return_value ());
1235 1236 1237
    }
  }

1238
  protected:
B
Behdad Esfahbod 已提交
1239
  union {
B
Behdad Esfahbod 已提交
1240
  HBUINT16			sub_format;
B
Behdad Esfahbod 已提交
1241 1242 1243 1244
  SingleSubst			single;
  MultipleSubst			multiple;
  AlternateSubst		alternate;
  LigatureSubst			ligature;
1245
  ContextSubst			context;
B
Behdad Esfahbod 已提交
1246 1247 1248
  ChainContextSubst		chainContext;
  ExtensionSubst		extension;
  ReverseChainSingleSubst	reverseChainContextSingle;
B
Behdad Esfahbod 已提交
1249
  } u;
B
Behdad Esfahbod 已提交
1250
  public:
B
Minor  
Behdad Esfahbod 已提交
1251
  DEFINE_SIZE_UNION (2, sub_format);
B
Behdad Esfahbod 已提交
1252 1253
};

1254

B
Behdad Esfahbod 已提交
1255 1256
struct SubstLookup : Lookup
{
B
Behdad Esfahbod 已提交
1257 1258 1259 1260
  typedef SubstLookupSubTable SubTable;

  inline const SubTable& get_subtable (unsigned int i) const
  { return Lookup::get_subtable<SubTable> (i); }
B
Behdad Esfahbod 已提交
1261

B
Behdad Esfahbod 已提交
1262
  inline static bool lookup_type_is_reverse (unsigned int lookup_type)
B
Behdad Esfahbod 已提交
1263
  { return lookup_type == SubTable::ReverseChainSingle; }
B
Behdad Esfahbod 已提交
1264 1265

  inline bool is_reverse (void) const
B
Behdad Esfahbod 已提交
1266
  {
B
Behdad Esfahbod 已提交
1267
    unsigned int type = get_type ();
B
Behdad Esfahbod 已提交
1268
    if (unlikely (type == SubTable::Extension))
1269
      return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
B
Behdad Esfahbod 已提交
1270
    return lookup_type_is_reverse (type);
B
Behdad Esfahbod 已提交
1271
  }
1272

1273
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1274 1275
  {
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
1276
    return_trace (dispatch (c));
B
Behdad Esfahbod 已提交
1277 1278
  }

1279 1280 1281 1282 1283 1284
  inline bool intersects (const hb_set_t *glyphs) const
  {
    hb_intersects_context_t c (glyphs);
    return dispatch (&c);
  }

1285
  inline hb_closure_context_t::return_t closure (hb_closure_context_t *c, unsigned int this_index) const
1286
  {
B
Behdad Esfahbod 已提交
1287
    TRACE_CLOSURE (this);
1288
    if (!c->should_visit_lookup (this_index))
1289 1290 1291
      return_trace (HB_VOID);

    c->set_recurse_func (dispatch_closure_recurse_func);
1292 1293 1294 1295 1296 1297

    hb_closure_context_t::return_t ret = dispatch (c);

    c->flush ();

    return_trace (ret);
B
Behdad Esfahbod 已提交
1298 1299
  }

B
Behdad Esfahbod 已提交
1300
  inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
B
Behdad Esfahbod 已提交
1301 1302
  {
    TRACE_COLLECT_GLYPHS (this);
1303
    c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
B
Behdad Esfahbod 已提交
1304
    return_trace (dispatch (c));
1305 1306
  }

B
Behdad Esfahbod 已提交
1307 1308 1309
  template <typename set_t>
  inline void add_coverage (set_t *glyphs) const
  {
1310 1311
    hb_add_coverage_context_t<set_t> c (glyphs);
    dispatch (&c);
B
Behdad Esfahbod 已提交
1312 1313
  }

1314 1315
  inline bool would_apply (hb_would_apply_context_t *c,
			   const hb_ot_layout_lookup_accelerator_t *accel) const
B
Behdad Esfahbod 已提交
1316
  {
B
Behdad Esfahbod 已提交
1317
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
1318 1319 1320
    if (unlikely (!c->len))  return_trace (false);
    if (!accel->may_have (c->glyphs[0]))  return_trace (false);
      return_trace (dispatch (c));
B
Behdad Esfahbod 已提交
1321 1322
  }

1323
  static bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index);
B
Behdad Esfahbod 已提交
1324

B
Behdad Esfahbod 已提交
1325 1326 1327
  inline SubTable& serialize_subtable (hb_serialize_context_t *c,
				       unsigned int i)
  { return get_subtables<SubTable> ()[i].serialize (c, this); }
1328 1329 1330 1331 1332 1333 1334

  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 已提交
1335
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1336
    if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1337
    return_trace (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes, num_glyphs));
1338 1339 1340 1341 1342 1343 1344 1345 1346
  }

  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 已提交
1347
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1348
    if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1349 1350 1351 1352 1353
    return_trace (serialize_subtable (c, 0).u.multiple.serialize (c,
								  glyphs,
								  substitute_len_list,
								  num_glyphs,
								  substitute_glyphs_list));
1354 1355 1356 1357 1358 1359 1360 1361 1362
  }

  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 已提交
1363
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1364
    if (unlikely (!Lookup::serialize (c, SubTable::Alternate, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1365 1366 1367 1368 1369
    return_trace (serialize_subtable (c, 0).u.alternate.serialize (c,
								   glyphs,
								   alternate_len_list,
								   num_glyphs,
								   alternate_glyphs_list));
1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380
  }

  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 已提交
1381
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1382
    if (unlikely (!Lookup::serialize (c, SubTable::Ligature, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1383 1384 1385 1386 1387 1388 1389
    return_trace (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));
1390 1391
  }

B
Behdad Esfahbod 已提交
1392 1393 1394
  template <typename context_t>
  static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);

B
Behdad Esfahbod 已提交
1395
  static inline hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned int lookup_index)
1396
  {
1397
    if (!c->should_visit_lookup (lookup_index))
1398
      return HB_VOID;
1399 1400 1401 1402 1403 1404

    hb_closure_context_t::return_t ret = dispatch_recurse_func (c, lookup_index);

    c->flush ();

    return ret;
1405 1406
  }

B
Behdad Esfahbod 已提交
1407 1408
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
B
Behdad Esfahbod 已提交
1409 1410 1411
  { return Lookup::dispatch<SubTable> (c); }

  inline bool subset (hb_subset_context_t *c) const
1412
  { return Lookup::subset<SubTable> (c); }
B
Behdad Esfahbod 已提交
1413

B
Behdad Esfahbod 已提交
1414
  inline bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
1415
  { return Lookup::sanitize<SubTable> (c); }
B
Behdad Esfahbod 已提交
1416 1417
};

B
Minor  
Behdad Esfahbod 已提交
1418
/*
1419 1420
 * GSUB -- Glyph Substitution
 * https://docs.microsoft.com/en-us/typography/opentype/spec/gsub
B
Minor  
Behdad Esfahbod 已提交
1421 1422
 */

B
Behdad Esfahbod 已提交
1423 1424
struct GSUB : GSUBGPOS
{
1425
  static const hb_tag_t tableTag	= HB_OT_TAG_GSUB;
B
Minor  
Behdad Esfahbod 已提交
1426

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

1430
  inline bool subset (hb_subset_context_t *c) const
1431
  { return GSUBGPOS::subset<SubstLookup> (c); }
1432

B
Behdad Esfahbod 已提交
1433
  inline bool sanitize (hb_sanitize_context_t *c) const
1434
  { return GSUBGPOS::sanitize<SubstLookup> (c); }
B
WIP  
Behdad Esfahbod 已提交
1435 1436

  typedef GSUBGPOS::accelerator_t<GSUB> accelerator_t;
B
Minor  
Behdad Esfahbod 已提交
1437
};
1438 1439


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

1442
/*static*/ inline bool ExtensionSubst::is_reverse (void) const
B
Behdad Esfahbod 已提交
1443 1444
{
  unsigned int type = get_type ();
B
Behdad Esfahbod 已提交
1445 1446
  if (unlikely (type == SubTable::Extension))
    return CastR<ExtensionSubst> (get_subtable<SubTable>()).is_reverse ();
B
Behdad Esfahbod 已提交
1447 1448 1449
  return SubstLookup::lookup_type_is_reverse (type);
}

1450
template <typename context_t>
1451
/*static*/ inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
1452
{
1453
  const SubstLookup &l = _get_gsub_relaxed (c->face).get_lookup (lookup_index);
1454
  return l.dispatch (c);
1455 1456
}

1457
/*static*/ inline bool SubstLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index)
B
Behdad Esfahbod 已提交
1458
{
1459
  const SubstLookup &l = _get_gsub_relaxed (c->face).get_lookup (lookup_index);
1460
  unsigned int saved_lookup_props = c->lookup_props;
1461 1462 1463
  unsigned int saved_lookup_index = c->lookup_index;
  c->set_lookup_index (lookup_index);
  c->set_lookup_props (l.get_props ());
1464
  bool ret = l.dispatch (c);
1465
  c->set_lookup_index (saved_lookup_index);
1466
  c->set_lookup_props (saved_lookup_props);
1467
  return ret;
1468 1469
}

1470
struct GSUB_accelerator_t : GSUB::accelerator_t {};
1471

B
Behdad Esfahbod 已提交
1472
} /* namespace OT */
1473

B
Behdad Esfahbod 已提交
1474

1475
#endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */