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

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

32
#include "hb-ot-layout-gsubgpos.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
  inline bool subset (hb_subset_context_t *c) const
  {
107
    return false;
108
    TRACE_SUBSET (this);
109 110 111 112 113 114 115 116 117 118
    hb_auto_t<hb_vector_t<hb_codepoint_t>> from;
    hb_auto_t<hb_vector_t<hb_codepoint_t>> to;
    hb_codepoint_t delta = deltaGlyphID;
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
    {
      //if (!c->plan->glyphs->has (iter.get_glyph ()))
      //  continue;
      from.push (iter.get_glyph ());
      to.push ((iter.get_glyph () + delta) & 0xFFFF);
    }
119 120 121
    return_trace (false);
  }

B
Behdad Esfahbod 已提交
122 123
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
124
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
125
    return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
B
Behdad Esfahbod 已提交
126 127
  }

128
  protected:
B
Behdad Esfahbod 已提交
129
  HBUINT16	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
130 131
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
132
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
133
  HBINT16	deltaGlyphID;		/* Add to original GlyphID to get
B
Behdad Esfahbod 已提交
134
					 * substitute GlyphID */
135 136
  public:
  DEFINE_SIZE_STATIC (6);
B
Behdad Esfahbod 已提交
137 138
};

B
Behdad Esfahbod 已提交
139 140
struct SingleSubstFormat2
{
141 142 143
  inline bool intersects (const hb_set_t *glyphs) const
  { return (this+coverage).intersects (glyphs); }

B
Behdad Esfahbod 已提交
144
  inline void closure (hb_closure_context_t *c) const
145
  {
B
Behdad Esfahbod 已提交
146
    TRACE_CLOSURE (this);
147
    unsigned int count = substitute.len;
148
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
149 150
    {
      if (unlikely (iter.get_coverage () >= count))
151
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
B
Behdad Esfahbod 已提交
152
      if (c->glyphs->has (iter.get_glyph ()))
153
	c->out->add (substitute[iter.get_coverage ()]);
B
Behdad Esfahbod 已提交
154
    }
155 156
  }

157 158
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
159
    TRACE_COLLECT_GLYPHS (this);
160
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
161
    unsigned int count = substitute.len;
162
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
163 164
    {
      if (unlikely (iter.get_coverage () >= count))
165
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
B
Minor  
Behdad Esfahbod 已提交
166
      c->output->add (substitute[iter.get_coverage ()]);
167 168 169
    }
  }

170
  inline const Coverage &get_coverage (void) const
171
  { return this+coverage; }
172

173 174
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
175
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
176
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
177 178
  }

179
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
180
  {
B
Behdad Esfahbod 已提交
181
    TRACE_APPLY (this);
182
    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
B
Behdad Esfahbod 已提交
183
    if (likely (index == NOT_COVERED)) return_trace (false);
184

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

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

B
Behdad Esfahbod 已提交
189
    return_trace (true);
190
  }
B
Behdad Esfahbod 已提交
191

B
Behdad Esfahbod 已提交
192
  inline bool serialize (hb_serialize_context_t *c,
193 194
			 Supplier<GlyphID> &glyphs,
			 Supplier<GlyphID> &substitutes,
B
Behdad Esfahbod 已提交
195 196
			 unsigned int num_glyphs)
  {
B
Behdad Esfahbod 已提交
197
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
198 199 200 201
    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 已提交
202 203
  }

204 205 206 207 208 209 210
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

B
Behdad Esfahbod 已提交
211 212
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
213
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
214
    return_trace (coverage.sanitize (c, this) && substitute.sanitize (c));
B
Behdad Esfahbod 已提交
215 216
  }

217
  protected:
B
Behdad Esfahbod 已提交
218
  HBUINT16	format;			/* Format identifier--format = 2 */
B
Behdad Esfahbod 已提交
219 220
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
221
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
222 223 224
  ArrayOf<GlyphID>
		substitute;		/* Array of substitute
					 * GlyphIDs--ordered by Coverage Index */
225
  public:
226
  DEFINE_SIZE_ARRAY (6, substitute);
B
Behdad Esfahbod 已提交
227 228
};

B
Behdad Esfahbod 已提交
229 230
struct SingleSubst
{
B
Behdad Esfahbod 已提交
231
  inline bool serialize (hb_serialize_context_t *c,
232 233
			 Supplier<GlyphID> &glyphs,
			 Supplier<GlyphID> &substitutes,
B
Behdad Esfahbod 已提交
234 235
			 unsigned int num_glyphs)
  {
B
Behdad Esfahbod 已提交
236
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
237
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
B
Behdad Esfahbod 已提交
238
    unsigned int format = 2;
B
Behdad Esfahbod 已提交
239
    int delta = 0;
B
Behdad Esfahbod 已提交
240 241
    if (num_glyphs) {
      format = 1;
B
Minor  
Behdad Esfahbod 已提交
242
      /* TODO(serialize) check for wrap-around */
B
Behdad Esfahbod 已提交
243 244 245 246 247 248 249 250 251
      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 已提交
252 253 254
    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 已提交
255 256 257
    }
  }

B
Behdad Esfahbod 已提交
258 259 260
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
  {
261
    TRACE_DISPATCH (this, u.format);
262
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
263
    switch (u.format) {
B
Behdad Esfahbod 已提交
264 265 266
    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 已提交
267 268 269
    }
  }

270
  protected:
271
  union {
B
Behdad Esfahbod 已提交
272
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
273 274
  SingleSubstFormat1	format1;
  SingleSubstFormat2	format2;
275
  } u;
B
Behdad Esfahbod 已提交
276
};
277

B
Behdad Esfahbod 已提交
278

B
Behdad Esfahbod 已提交
279 280
struct Sequence
{
B
Behdad Esfahbod 已提交
281
  inline void closure (hb_closure_context_t *c) const
282
  {
B
Behdad Esfahbod 已提交
283
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
284 285
    unsigned int count = substitute.len;
    for (unsigned int i = 0; i < count; i++)
286
      c->out->add (substitute[i]);
287 288
  }

289 290
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
291
    TRACE_COLLECT_GLYPHS (this);
292
    c->output->add_array (substitute.arrayZ, substitute.len);
293 294
  }

295
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
296
  {
B
Behdad Esfahbod 已提交
297
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
298
    unsigned int count = substitute.len;
299

B
Behdad Esfahbod 已提交
300 301 302
    /* Special-case to make it in-place and not consider this
     * as a "multiplied" substitution. */
    if (unlikely (count == 1))
303
    {
304
      c->replace_glyph (substitute.arrayZ[0]);
B
Behdad Esfahbod 已提交
305
      return_trace (true);
306
    }
307
    /* Spec disallows this, but Uniscribe allows it.
308
     * https://github.com/harfbuzz/harfbuzz/issues/253 */
309 310 311 312 313
    else if (unlikely (count == 0))
    {
      c->buffer->delete_glyph ();
      return_trace (true);
    }
B
Behdad Esfahbod 已提交
314 315 316 317 318 319

    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);
320
      c->output_glyph_for_component (substitute.arrayZ[i], klass);
321
    }
B
Behdad Esfahbod 已提交
322
    c->buffer->skip_glyph ();
B
Behdad Esfahbod 已提交
323

B
Behdad Esfahbod 已提交
324
    return_trace (true);
B
Behdad Esfahbod 已提交
325 326
  }

327
  inline bool serialize (hb_serialize_context_t *c,
328
			 Supplier<GlyphID> &glyphs,
329 330
			 unsigned int num_glyphs)
  {
B
Behdad Esfahbod 已提交
331
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
332 333 334
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    if (unlikely (!substitute.serialize (c, glyphs, num_glyphs))) return_trace (false);
    return_trace (true);
335 336
  }

B
Behdad Esfahbod 已提交
337 338
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
339
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
340
    return_trace (substitute.sanitize (c));
B
Behdad Esfahbod 已提交
341 342
  }

343
  protected:
B
Behdad Esfahbod 已提交
344 345
  ArrayOf<GlyphID>
		substitute;		/* String of GlyphIDs to substitute */
346
  public:
347
  DEFINE_SIZE_ARRAY (2, substitute);
B
Behdad Esfahbod 已提交
348 349
};

B
Behdad Esfahbod 已提交
350 351
struct MultipleSubstFormat1
{
352 353 354
  inline bool intersects (const hb_set_t *glyphs) const
  { return (this+coverage).intersects (glyphs); }

B
Behdad Esfahbod 已提交
355
  inline void closure (hb_closure_context_t *c) const
356
  {
B
Behdad Esfahbod 已提交
357
    TRACE_CLOSURE (this);
358
    unsigned int count = sequence.len;
359
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
360 361
    {
      if (unlikely (iter.get_coverage () >= count))
362
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
B
Behdad Esfahbod 已提交
363
      if (c->glyphs->has (iter.get_glyph ()))
B
Behdad Esfahbod 已提交
364
	(this+sequence[iter.get_coverage ()]).closure (c);
B
Behdad Esfahbod 已提交
365
    }
366 367
  }

368 369
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
370
    TRACE_COLLECT_GLYPHS (this);
371
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
372 373
    unsigned int count = sequence.len;
    for (unsigned int i = 0; i < count; i++)
374
      (this+sequence[i]).collect_glyphs (c);
375 376
  }

377
  inline const Coverage &get_coverage (void) const
378
  { return this+coverage; }
379

380 381
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
382
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
383
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
384 385
  }

386
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
387
  {
B
Behdad Esfahbod 已提交
388
    TRACE_APPLY (this);
389

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

B
Behdad Esfahbod 已提交
393
    return_trace ((this+sequence[index]).apply (c));
394
  }
B
Behdad Esfahbod 已提交
395

396
  inline bool serialize (hb_serialize_context_t *c,
397 398
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &substitute_len_list,
399
			 unsigned int num_glyphs,
400
			 Supplier<GlyphID> &substitute_glyphs_list)
401
  {
B
Behdad Esfahbod 已提交
402
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
403 404
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    if (unlikely (!sequence.serialize (c, num_glyphs))) return_trace (false);
405 406 407
    for (unsigned int i = 0; i < num_glyphs; i++)
      if (unlikely (!sequence[i].serialize (c, this).serialize (c,
								substitute_glyphs_list,
B
Behdad Esfahbod 已提交
408
								substitute_len_list[i]))) return_trace (false);
409
    substitute_len_list += num_glyphs;
B
Behdad Esfahbod 已提交
410 411
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
    return_trace (true);
412 413
  }

414 415 416 417 418 419 420
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

B
Behdad Esfahbod 已提交
421 422
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
423
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
424
    return_trace (coverage.sanitize (c, this) && sequence.sanitize (c, this));
B
Behdad Esfahbod 已提交
425 426
  }

427
  protected:
B
Behdad Esfahbod 已提交
428
  HBUINT16	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
429 430
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
431
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
432 433 434
  OffsetArrayOf<Sequence>
		sequence;		/* Array of Sequence tables
					 * ordered by Coverage Index */
435
  public:
436
  DEFINE_SIZE_ARRAY (6, sequence);
B
Behdad Esfahbod 已提交
437
};
438

B
Behdad Esfahbod 已提交
439 440
struct MultipleSubst
{
441
  inline bool serialize (hb_serialize_context_t *c,
442 443
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &substitute_len_list,
444
			 unsigned int num_glyphs,
445
			 Supplier<GlyphID> &substitute_glyphs_list)
446
  {
B
Behdad Esfahbod 已提交
447
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
448
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
449 450 451
    unsigned int format = 1;
    u.format.set (format);
    switch (u.format) {
B
Behdad Esfahbod 已提交
452 453
    case 1: return_trace (u.format1.serialize (c, glyphs, substitute_len_list, num_glyphs, substitute_glyphs_list));
    default:return_trace (false);
454 455 456
    }
  }

B
Behdad Esfahbod 已提交
457 458 459
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
  {
460
    TRACE_DISPATCH (this, u.format);
461
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
462
    switch (u.format) {
B
Behdad Esfahbod 已提交
463 464
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
465 466 467
    }
  }

468
  protected:
469
  union {
B
Behdad Esfahbod 已提交
470
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
471
  MultipleSubstFormat1	format1;
472 473 474
  } u;
};

475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507
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 已提交
508

509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530
    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 已提交
531
					 * arbitrary order */
532 533 534
  public:
  DEFINE_SIZE_ARRAY (2, alternates);
};
B
Behdad Esfahbod 已提交
535

B
Behdad Esfahbod 已提交
536 537
struct AlternateSubstFormat1
{
538 539 540
  inline bool intersects (const hb_set_t *glyphs) const
  { return (this+coverage).intersects (glyphs); }

B
Behdad Esfahbod 已提交
541
  inline void closure (hb_closure_context_t *c) const
542
  {
B
Behdad Esfahbod 已提交
543
    TRACE_CLOSURE (this);
544
    unsigned int count = alternateSet.len;
545
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
546 547
    {
      if (unlikely (iter.get_coverage () >= count))
548
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
549 550
      if (c->glyphs->has (iter.get_glyph ()))
	(this+alternateSet[iter.get_coverage ()]).closure (c);
B
Behdad Esfahbod 已提交
551
    }
552 553
  }

554 555
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
556
    TRACE_COLLECT_GLYPHS (this);
557
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
558
    unsigned int count = alternateSet.len;
559
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
560 561
    {
      if (unlikely (iter.get_coverage () >= count))
562
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
563
      (this+alternateSet[iter.get_coverage ()]).collect_glyphs (c);
564 565 566
    }
  }

567
  inline const Coverage &get_coverage (void) const
568
  { return this+coverage; }
569

570 571
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
572
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
573
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
574 575
  }

576
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
577
  {
B
Behdad Esfahbod 已提交
578
    TRACE_APPLY (this);
579

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

583
    return_trace ((this+alternateSet[index]).apply (c));
584
  }
B
Behdad Esfahbod 已提交
585

586
  inline bool serialize (hb_serialize_context_t *c,
587 588
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &alternate_len_list,
589
			 unsigned int num_glyphs,
590
			 Supplier<GlyphID> &alternate_glyphs_list)
591
  {
B
Behdad Esfahbod 已提交
592
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
593 594
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    if (unlikely (!alternateSet.serialize (c, num_glyphs))) return_trace (false);
595 596 597
    for (unsigned int i = 0; i < num_glyphs; i++)
      if (unlikely (!alternateSet[i].serialize (c, this).serialize (c,
								    alternate_glyphs_list,
B
Behdad Esfahbod 已提交
598
								    alternate_len_list[i]))) return_trace (false);
599
    alternate_len_list += num_glyphs;
B
Behdad Esfahbod 已提交
600 601
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
    return_trace (true);
602 603
  }

604 605 606 607 608 609 610
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

B
Behdad Esfahbod 已提交
611 612
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
613
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
614
    return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
615 616
  }

617
  protected:
B
Behdad Esfahbod 已提交
618
  HBUINT16	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
619 620
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
621
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
622 623 624
  OffsetArrayOf<AlternateSet>
		alternateSet;		/* Array of AlternateSet tables
					 * ordered by Coverage Index */
625
  public:
626
  DEFINE_SIZE_ARRAY (6, alternateSet);
B
Behdad Esfahbod 已提交
627
};
628

B
Behdad Esfahbod 已提交
629 630
struct AlternateSubst
{
631
  inline bool serialize (hb_serialize_context_t *c,
632 633
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &alternate_len_list,
634
			 unsigned int num_glyphs,
635
			 Supplier<GlyphID> &alternate_glyphs_list)
636
  {
B
Behdad Esfahbod 已提交
637
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
638
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
639 640 641
    unsigned int format = 1;
    u.format.set (format);
    switch (u.format) {
B
Behdad Esfahbod 已提交
642 643
    case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, num_glyphs, alternate_glyphs_list));
    default:return_trace (false);
644 645 646
    }
  }

B
Behdad Esfahbod 已提交
647 648 649
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
  {
650
    TRACE_DISPATCH (this, u.format);
651
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
652
    switch (u.format) {
B
Behdad Esfahbod 已提交
653 654
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
655 656 657
    }
  }

658
  protected:
659
  union {
B
Behdad Esfahbod 已提交
660
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
661
  AlternateSubstFormat1	format1;
662 663 664
  } u;
};

665

B
Behdad Esfahbod 已提交
666 667
struct Ligature
{
668 669 670 671 672 673 674 675 676
  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 已提交
677
  inline void closure (hb_closure_context_t *c) const
678
  {
B
Behdad Esfahbod 已提交
679
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
680 681 682
    unsigned int count = component.len;
    for (unsigned int i = 1; i < count; i++)
      if (!c->glyphs->has (component[i]))
B
Behdad Esfahbod 已提交
683
        return;
684
    c->out->add (ligGlyph);
685 686
  }

687 688
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
689
    TRACE_COLLECT_GLYPHS (this);
690
    c->input->add_array (component.arrayZ, component.len ? component.len - 1 : 0);
B
Minor  
Behdad Esfahbod 已提交
691
    c->output->add (ligGlyph);
692 693
  }

694
  inline bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
695
  {
B
Behdad Esfahbod 已提交
696
    TRACE_WOULD_APPLY (this);
697
    if (c->len != component.len)
B
Behdad Esfahbod 已提交
698
      return_trace (false);
699 700 701

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

B
Behdad Esfahbod 已提交
704
    return_trace (true);
B
Behdad Esfahbod 已提交
705 706
  }

707
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
708
  {
B
Behdad Esfahbod 已提交
709
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
710
    unsigned int count = component.len;
B
Behdad Esfahbod 已提交
711

B
Behdad Esfahbod 已提交
712
    if (unlikely (!count)) return_trace (false);
B
Behdad Esfahbod 已提交
713

714 715 716 717 718
    /* 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 已提交
719
      return_trace (true);
720 721
    }

B
Behdad Esfahbod 已提交
722 723
    bool is_mark_ligature = false;
    unsigned int total_component_count = 0;
724

725
    unsigned int match_length = 0;
726
    unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
727

728 729 730
    if (likely (!match_input (c, count,
			      &component[1],
			      match_glyph,
B
Behdad Esfahbod 已提交
731
			      nullptr,
732 733
			      &match_length,
			      match_positions,
734 735
			      &is_mark_ligature,
			      &total_component_count)))
B
Behdad Esfahbod 已提交
736
      return_trace (false);
737

738 739
    ligate_input (c,
		  count,
740 741
		  match_positions,
		  match_length,
742
		  ligGlyph,
743 744
		  is_mark_ligature,
		  total_component_count);
745

B
Behdad Esfahbod 已提交
746
    return_trace (true);
747
  }
748

749 750 751 752 753
  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 已提交
754
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
755
    if (unlikely (!c->extend_min (*this))) return_trace (false);
756
    ligGlyph = ligature;
B
Behdad Esfahbod 已提交
757 758
    if (unlikely (!component.serialize (c, components, num_components))) return_trace (false);
    return_trace (true);
759 760
  }

B
Behdad Esfahbod 已提交
761
  public:
B
Behdad Esfahbod 已提交
762 763
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
764
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
765
    return_trace (ligGlyph.sanitize (c) && component.sanitize (c));
B
Behdad Esfahbod 已提交
766 767
  }

768
  protected:
769
  GlyphID	ligGlyph;		/* GlyphID of ligature to substitute */
B
Behdad Esfahbod 已提交
770 771
  HeadlessArrayOf<GlyphID>
		component;		/* Array of component GlyphIDs--start
772 773
					 * with the second  component--ordered
					 * in writing direction */
774
  public:
775
  DEFINE_SIZE_ARRAY (4, component);
776
};
B
Behdad Esfahbod 已提交
777

B
Behdad Esfahbod 已提交
778 779
struct LigatureSet
{
780 781 782 783 784 785 786 787 788
  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 已提交
789
  inline void closure (hb_closure_context_t *c) const
790
  {
B
Behdad Esfahbod 已提交
791
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
792 793
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
B
Behdad Esfahbod 已提交
794
      (this+ligature[i]).closure (c);
795 796
  }

797 798
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
799
    TRACE_COLLECT_GLYPHS (this);
800 801 802 803 804
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
      (this+ligature[i]).collect_glyphs (c);
  }

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

818
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
819
  {
B
Behdad Esfahbod 已提交
820
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
821
    unsigned int num_ligs = ligature.len;
B
Behdad Esfahbod 已提交
822 823
    for (unsigned int i = 0; i < num_ligs; i++)
    {
B
Behdad Esfahbod 已提交
824
      const Ligature &lig = this+ligature[i];
B
Behdad Esfahbod 已提交
825
      if (lig.apply (c)) return_trace (true);
826 827
    }

B
Behdad Esfahbod 已提交
828
    return_trace (false);
829
  }
B
Behdad Esfahbod 已提交
830

831 832 833 834 835 836
  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 已提交
837
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
838 839
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    if (unlikely (!ligature.serialize (c, num_ligatures))) return_trace (false);
840 841 842 843
    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 已提交
844
								component_count_list[i]))) return_trace (false);
845 846
    ligatures += num_ligatures;
    component_count_list += num_ligatures;
B
Behdad Esfahbod 已提交
847
    return_trace (true);
848 849
  }

B
Behdad Esfahbod 已提交
850 851
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
852
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
853
    return_trace (ligature.sanitize (c, this));
B
Behdad Esfahbod 已提交
854 855
  }

856
  protected:
B
Behdad Esfahbod 已提交
857 858 859
  OffsetArrayOf<Ligature>
		ligature;		/* Array LigatureSet tables
					 * ordered by preference */
860
  public:
861
  DEFINE_SIZE_ARRAY (2, ligature);
B
Behdad Esfahbod 已提交
862 863
};

B
Behdad Esfahbod 已提交
864 865
struct LigatureSubstFormat1
{
866 867 868 869 870 871 872 873 874 875 876 877 878 879
  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 已提交
880
  inline void closure (hb_closure_context_t *c) const
881
  {
B
Behdad Esfahbod 已提交
882
    TRACE_CLOSURE (this);
883
    unsigned int count = ligatureSet.len;
884
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
885 886
    {
      if (unlikely (iter.get_coverage () >= count))
887
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
B
Behdad Esfahbod 已提交
888
      if (c->glyphs->has (iter.get_glyph ()))
B
Behdad Esfahbod 已提交
889
	(this+ligatureSet[iter.get_coverage ()]).closure (c);
B
Behdad Esfahbod 已提交
890
    }
891 892
  }

893 894
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
895
    TRACE_COLLECT_GLYPHS (this);
896
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
897
    unsigned int count = ligatureSet.len;
898
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
899 900
    {
      if (unlikely (iter.get_coverage () >= count))
901
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
902 903 904 905
      (this+ligatureSet[iter.get_coverage ()]).collect_glyphs (c);
    }
  }

906
  inline const Coverage &get_coverage (void) const
907
  { return this+coverage; }
908

909
  inline bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
910
  {
B
Behdad Esfahbod 已提交
911
    TRACE_WOULD_APPLY (this);
912
    unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
B
Behdad Esfahbod 已提交
913
    if (likely (index == NOT_COVERED)) return_trace (false);
914 915

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

919
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
920
  {
B
Behdad Esfahbod 已提交
921
    TRACE_APPLY (this);
922

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

B
Behdad Esfahbod 已提交
926
    const LigatureSet &lig_set = this+ligatureSet[index];
B
Behdad Esfahbod 已提交
927
    return_trace (lig_set.apply (c));
928
  }
B
Behdad Esfahbod 已提交
929

930 931 932 933 934 935 936 937
  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 已提交
938
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
939 940
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    if (unlikely (!ligatureSet.serialize (c, num_first_glyphs))) return_trace (false);
941 942 943 944 945
    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 已提交
946
								   component_list))) return_trace (false);
947
    ligature_per_first_glyph_count_list += num_first_glyphs;
B
Behdad Esfahbod 已提交
948 949
    if (unlikely (!coverage.serialize (c, this).serialize (c, first_glyphs, num_first_glyphs))) return_trace (false);
    return_trace (true);
950 951
  }

952 953 954 955 956 957 958
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

B
Behdad Esfahbod 已提交
959 960
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
961
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
962
    return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
963 964
  }

965
  protected:
B
Behdad Esfahbod 已提交
966
  HBUINT16	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
967 968
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
969
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
970
  OffsetArrayOf<LigatureSet>
B
Behdad Esfahbod 已提交
971 972
		ligatureSet;		/* Array LigatureSet tables
					 * ordered by Coverage Index */
973
  public:
974
  DEFINE_SIZE_ARRAY (6, ligatureSet);
B
Behdad Esfahbod 已提交
975
};
976

B
Behdad Esfahbod 已提交
977 978
struct LigatureSubst
{
979 980 981 982 983 984 985 986
  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 已提交
987
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
988
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
989 990 991
    unsigned int format = 1;
    u.format.set (format);
    switch (u.format) {
B
Behdad Esfahbod 已提交
992 993 994 995 996 997 998 999
    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);
1000 1001 1002
    }
  }

B
Behdad Esfahbod 已提交
1003 1004 1005
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
  {
1006
    TRACE_DISPATCH (this, u.format);
1007
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
1008
    switch (u.format) {
B
Behdad Esfahbod 已提交
1009 1010
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
1011 1012 1013
    }
  }

1014
  protected:
1015
  union {
B
Behdad Esfahbod 已提交
1016
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1017
  LigatureSubstFormat1	format1;
1018 1019 1020
  } u;
};

B
Behdad Esfahbod 已提交
1021

B
Minor  
Behdad Esfahbod 已提交
1022
struct ContextSubst : Context {};
B
Behdad Esfahbod 已提交
1023

B
Minor  
Behdad Esfahbod 已提交
1024
struct ChainContextSubst : ChainContext {};
1025

B
Behdad Esfahbod 已提交
1026
struct ExtensionSubst : Extension<ExtensionSubst>
B
Behdad Esfahbod 已提交
1027
{
B
Behdad Esfahbod 已提交
1028
  typedef struct SubstLookupSubTable SubTable;
B
Behdad Esfahbod 已提交
1029

B
Behdad Esfahbod 已提交
1030
  inline bool is_reverse (void) const;
1031 1032 1033
};


B
Behdad Esfahbod 已提交
1034 1035
struct ReverseChainSingleSubstFormat1
{
1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057
  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 已提交
1058
  inline void closure (hb_closure_context_t *c) const
1059
  {
B
Behdad Esfahbod 已提交
1060
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
1061 1062 1063 1064 1065 1066 1067
    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 已提交
1068
        return;
B
Behdad Esfahbod 已提交
1069 1070 1071 1072

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

    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
1076
    count = substitute.len;
1077
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
1078 1079
    {
      if (unlikely (iter.get_coverage () >= count))
1080
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
B
Behdad Esfahbod 已提交
1081
      if (c->glyphs->has (iter.get_glyph ()))
1082
	c->out->add (substitute[iter.get_coverage ()]);
B
Behdad Esfahbod 已提交
1083
    }
1084 1085
  }

1086 1087
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1088
    TRACE_COLLECT_GLYPHS (this);
1089
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
1090 1091 1092 1093 1094

    unsigned int count;

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

1097
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1098 1099
    count = lookahead.len;
    for (unsigned int i = 0; i < count; i++)
1100
      if (unlikely (!(this+lookahead[i]).add_coverage (c->after))) return;
1101 1102 1103

    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
    count = substitute.len;
1104
    c->output->add_array (substitute.arrayZ, substitute.len);
1105 1106
  }

1107
  inline const Coverage &get_coverage (void) const
1108
  { return this+coverage; }
1109

1110 1111
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1112
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
1113
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
1114 1115
  }

1116
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1117
  {
B
Behdad Esfahbod 已提交
1118
    TRACE_APPLY (this);
1119
    if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
B
Behdad Esfahbod 已提交
1120
      return_trace (false); /* No chaining to this type */
1121

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

1125 1126
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
1127

1128
  unsigned int start_index = 0, end_index = 0;
B
Behdad Esfahbod 已提交
1129
    if (match_backtrack (c,
1130
			 backtrack.len, (HBUINT16 *) backtrack.arrayZ,
1131 1132
			 match_coverage, this,
			 &start_index) &&
B
Behdad Esfahbod 已提交
1133
        match_lookahead (c,
1134
			 lookahead.len, (HBUINT16 *) lookahead.arrayZ,
B
Behdad Esfahbod 已提交
1135
			 match_coverage, this,
1136
			 1, &end_index))
1137
    {
1138
      c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index);
B
Behdad Esfahbod 已提交
1139
      c->replace_glyph_inplace (substitute[index]);
1140 1141 1142
      /* 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 已提交
1143
      return_trace (true);
1144 1145
    }

B
Behdad Esfahbod 已提交
1146
    return_trace (false);
1147
  }
B
Behdad Esfahbod 已提交
1148

1149 1150 1151 1152 1153 1154 1155
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

B
Behdad Esfahbod 已提交
1156 1157
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1158
    TRACE_SANITIZE (this);
1159
    if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
B
Behdad Esfahbod 已提交
1160
      return_trace (false);
B
Behdad Esfahbod 已提交
1161
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
B
Behdad Esfahbod 已提交
1162
    if (!lookahead.sanitize (c, this))
B
Behdad Esfahbod 已提交
1163
      return_trace (false);
B
Behdad Esfahbod 已提交
1164
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
B
Behdad Esfahbod 已提交
1165
    return_trace (substitute.sanitize (c));
B
Behdad Esfahbod 已提交
1166 1167
  }

1168
  protected:
B
Behdad Esfahbod 已提交
1169
  HBUINT16	format;			/* Format identifier--format = 1 */
1170 1171 1172 1173 1174
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of table */
  OffsetArrayOf<Coverage>
		backtrack;		/* Array of coverage tables
1175
					 * in backtracking sequence, in glyph
B
Behdad Esfahbod 已提交
1176
					 * sequence order */
1177 1178 1179
  OffsetArrayOf<Coverage>
		lookaheadX;		/* Array of coverage tables
					 * in lookahead sequence, in glyph
B
Behdad Esfahbod 已提交
1180
					 * sequence order */
1181 1182 1183
  ArrayOf<GlyphID>
		substituteX;		/* Array of substitute
					 * GlyphIDs--ordered by Coverage Index */
1184
  public:
B
Behdad Esfahbod 已提交
1185
  DEFINE_SIZE_MIN (10);
B
Behdad Esfahbod 已提交
1186 1187
};

B
Behdad Esfahbod 已提交
1188 1189
struct ReverseChainSingleSubst
{
1190
  template <typename context_t>
1191
  inline typename context_t::return_t dispatch (context_t *c) const
1192
  {
1193
    TRACE_DISPATCH (this, u.format);
1194
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1195
    switch (u.format) {
B
Behdad Esfahbod 已提交
1196 1197
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
1198 1199 1200
    }
  }

1201
  protected:
1202
  union {
B
Behdad Esfahbod 已提交
1203
  HBUINT16				format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1204
  ReverseChainSingleSubstFormat1	format1;
1205 1206 1207 1208 1209
  } u;
};



B
Behdad Esfahbod 已提交
1210 1211 1212 1213
/*
 * SubstLookup
 */

B
Behdad Esfahbod 已提交
1214 1215
struct SubstLookupSubTable
{
B
Behdad Esfahbod 已提交
1216
  friend struct Lookup;
B
Behdad Esfahbod 已提交
1217 1218
  friend struct SubstLookup;

B
Behdad Esfahbod 已提交
1219
  enum Type {
1220 1221 1222 1223 1224 1225 1226
    Single		= 1,
    Multiple		= 2,
    Alternate		= 3,
    Ligature		= 4,
    Context		= 5,
    ChainContext	= 6,
    Extension		= 7,
1227
    ReverseChainSingle	= 8
1228 1229
  };

1230
  template <typename context_t>
1231
  inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
1232
  {
1233
    TRACE_DISPATCH (this, lookup_type);
1234
    if (unlikely (!c->may_dispatch (this, &u.sub_format))) return_trace (c->no_dispatch_return_value ());
1235
    switch (lookup_type) {
B
Behdad Esfahbod 已提交
1236 1237 1238 1239 1240 1241 1242 1243 1244
    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 ());
1245 1246 1247
    }
  }

1248
  protected:
B
Behdad Esfahbod 已提交
1249
  union {
B
Behdad Esfahbod 已提交
1250
  HBUINT16			sub_format;
B
Behdad Esfahbod 已提交
1251 1252 1253 1254
  SingleSubst			single;
  MultipleSubst			multiple;
  AlternateSubst		alternate;
  LigatureSubst			ligature;
1255
  ContextSubst			context;
B
Behdad Esfahbod 已提交
1256 1257 1258
  ChainContextSubst		chainContext;
  ExtensionSubst		extension;
  ReverseChainSingleSubst	reverseChainContextSingle;
B
Behdad Esfahbod 已提交
1259
  } u;
B
Behdad Esfahbod 已提交
1260
  public:
B
Minor  
Behdad Esfahbod 已提交
1261
  DEFINE_SIZE_UNION (2, sub_format);
B
Behdad Esfahbod 已提交
1262 1263
};

1264

B
Behdad Esfahbod 已提交
1265 1266
struct SubstLookup : Lookup
{
B
Behdad Esfahbod 已提交
1267 1268 1269 1270
  typedef SubstLookupSubTable SubTable;

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

B
Behdad Esfahbod 已提交
1272
  inline static bool lookup_type_is_reverse (unsigned int lookup_type)
B
Behdad Esfahbod 已提交
1273
  { return lookup_type == SubTable::ReverseChainSingle; }
B
Behdad Esfahbod 已提交
1274 1275

  inline bool is_reverse (void) const
B
Behdad Esfahbod 已提交
1276
  {
B
Behdad Esfahbod 已提交
1277
    unsigned int type = get_type ();
B
Behdad Esfahbod 已提交
1278
    if (unlikely (type == SubTable::Extension))
1279
      return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
B
Behdad Esfahbod 已提交
1280
    return lookup_type_is_reverse (type);
B
Behdad Esfahbod 已提交
1281
  }
1282

1283
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1284 1285
  {
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
1286
    return_trace (dispatch (c));
B
Behdad Esfahbod 已提交
1287 1288
  }

1289 1290 1291 1292 1293 1294
  inline bool intersects (const hb_set_t *glyphs) const
  {
    hb_intersects_context_t c (glyphs);
    return dispatch (&c);
  }

1295
  inline hb_closure_context_t::return_t closure (hb_closure_context_t *c, unsigned int this_index) const
1296
  {
B
Behdad Esfahbod 已提交
1297
    TRACE_CLOSURE (this);
1298
    if (!c->should_visit_lookup (this_index))
1299 1300 1301
      return_trace (HB_VOID);

    c->set_recurse_func (dispatch_closure_recurse_func);
1302 1303 1304 1305 1306 1307

    hb_closure_context_t::return_t ret = dispatch (c);

    c->flush ();

    return_trace (ret);
B
Behdad Esfahbod 已提交
1308 1309
  }

B
Behdad Esfahbod 已提交
1310
  inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
B
Behdad Esfahbod 已提交
1311 1312
  {
    TRACE_COLLECT_GLYPHS (this);
1313
    c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
B
Behdad Esfahbod 已提交
1314
    return_trace (dispatch (c));
1315 1316
  }

B
Behdad Esfahbod 已提交
1317 1318 1319
  template <typename set_t>
  inline void add_coverage (set_t *glyphs) const
  {
1320 1321
    hb_add_coverage_context_t<set_t> c (glyphs);
    dispatch (&c);
B
Behdad Esfahbod 已提交
1322 1323
  }

1324 1325
  inline bool would_apply (hb_would_apply_context_t *c,
			   const hb_ot_layout_lookup_accelerator_t *accel) const
B
Behdad Esfahbod 已提交
1326
  {
B
Behdad Esfahbod 已提交
1327
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
1328 1329 1330
    if (unlikely (!c->len))  return_trace (false);
    if (!accel->may_have (c->glyphs[0]))  return_trace (false);
      return_trace (dispatch (c));
B
Behdad Esfahbod 已提交
1331 1332
  }

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

B
Behdad Esfahbod 已提交
1335 1336 1337
  inline SubTable& serialize_subtable (hb_serialize_context_t *c,
				       unsigned int i)
  { return get_subtables<SubTable> ()[i].serialize (c, this); }
1338 1339 1340 1341 1342 1343 1344

  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 已提交
1345
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1346
    if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1347
    return_trace (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes, num_glyphs));
1348 1349 1350 1351 1352 1353 1354 1355 1356
  }

  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 已提交
1357
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1358
    if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1359 1360 1361 1362 1363
    return_trace (serialize_subtable (c, 0).u.multiple.serialize (c,
								  glyphs,
								  substitute_len_list,
								  num_glyphs,
								  substitute_glyphs_list));
1364 1365 1366 1367 1368 1369 1370 1371 1372
  }

  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 已提交
1373
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1374
    if (unlikely (!Lookup::serialize (c, SubTable::Alternate, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1375 1376 1377 1378 1379
    return_trace (serialize_subtable (c, 0).u.alternate.serialize (c,
								   glyphs,
								   alternate_len_list,
								   num_glyphs,
								   alternate_glyphs_list));
1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390
  }

  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 已提交
1391
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1392
    if (unlikely (!Lookup::serialize (c, SubTable::Ligature, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1393 1394 1395 1396 1397 1398 1399
    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));
1400 1401
  }

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

B
Behdad Esfahbod 已提交
1405
  static inline hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned int lookup_index)
1406
  {
1407
    if (!c->should_visit_lookup (lookup_index))
1408
      return HB_VOID;
1409 1410 1411 1412 1413 1414

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

    c->flush ();

    return ret;
1415 1416
  }

B
Behdad Esfahbod 已提交
1417 1418
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
B
Behdad Esfahbod 已提交
1419 1420 1421
  { return Lookup::dispatch<SubTable> (c); }

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

B
Behdad Esfahbod 已提交
1424
  inline bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
1425
  { return Lookup::sanitize<SubTable> (c); }
B
Behdad Esfahbod 已提交
1426 1427
};

B
Minor  
Behdad Esfahbod 已提交
1428
/*
1429 1430
 * GSUB -- Glyph Substitution
 * https://docs.microsoft.com/en-us/typography/opentype/spec/gsub
B
Minor  
Behdad Esfahbod 已提交
1431 1432
 */

B
Behdad Esfahbod 已提交
1433 1434
struct GSUB : GSUBGPOS
{
1435
  static const hb_tag_t tableTag	= HB_OT_TAG_GSUB;
B
Minor  
Behdad Esfahbod 已提交
1436

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

1440
  inline bool subset (hb_subset_context_t *c) const
1441
  { return GSUBGPOS::subset<SubstLookup> (c); }
1442

B
Behdad Esfahbod 已提交
1443
  inline bool sanitize (hb_sanitize_context_t *c) const
1444
  { return GSUBGPOS::sanitize<SubstLookup> (c); }
B
WIP  
Behdad Esfahbod 已提交
1445 1446

  typedef GSUBGPOS::accelerator_t<GSUB> accelerator_t;
B
Minor  
Behdad Esfahbod 已提交
1447
};
1448 1449


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

1452
/*static*/ inline bool ExtensionSubst::is_reverse (void) const
B
Behdad Esfahbod 已提交
1453 1454
{
  unsigned int type = get_type ();
B
Behdad Esfahbod 已提交
1455 1456
  if (unlikely (type == SubTable::Extension))
    return CastR<ExtensionSubst> (get_subtable<SubTable>()).is_reverse ();
B
Behdad Esfahbod 已提交
1457 1458 1459
  return SubstLookup::lookup_type_is_reverse (type);
}

1460
template <typename context_t>
1461
/*static*/ inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
1462
{
1463
  const SubstLookup &l = _get_gsub_relaxed (c->face).get_lookup (lookup_index);
1464
  return l.dispatch (c);
1465 1466
}

1467
/*static*/ inline bool SubstLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index)
B
Behdad Esfahbod 已提交
1468
{
1469
  const SubstLookup &l = _get_gsub_relaxed (c->face).get_lookup (lookup_index);
1470
  unsigned int saved_lookup_props = c->lookup_props;
1471 1472 1473
  unsigned int saved_lookup_index = c->lookup_index;
  c->set_lookup_index (lookup_index);
  c->set_lookup_props (l.get_props ());
1474
  bool ret = l.dispatch (c);
1475
  c->set_lookup_index (saved_lookup_index);
1476
  c->set_lookup_props (saved_lookup_props);
1477
  return ret;
1478 1479
}

1480
struct GSUB_accelerator_t : GSUB::accelerator_t {};
1481

B
Behdad Esfahbod 已提交
1482
} /* namespace OT */
1483

B
Behdad Esfahbod 已提交
1484

1485
#endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */