hb-ot-layout-gsub-table.hh 46.3 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

38 39 40 41 42
static inline void SingleSubst_serialize (hb_serialize_context_t *c,
					  Supplier<GlyphID> &glyphs,
					  Supplier<GlyphID> &substitutes,
					  unsigned int num_glyphs);

B
Behdad Esfahbod 已提交
43 44
struct SingleSubstFormat1
{
45 46 47
  inline bool intersects (const hb_set_t *glyphs) const
  { return (this+coverage).intersects (glyphs); }

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

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

74
  inline const Coverage &get_coverage (void) const
75
  { return this+coverage; }
76

77 78
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
79
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
80
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
81 82
  }

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

90 91
    /* According to the Adobe Annotated OpenType Suite, result is always
     * limited to 16bit. */
92
    glyph_id = (glyph_id + deltaGlyphID) & 0xFFFFu;
93
    c->replace_glyph (glyph_id);
B
Behdad Esfahbod 已提交
94

B
Behdad Esfahbod 已提交
95
    return_trace (true);
96
  }
B
Behdad Esfahbod 已提交
97

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

110 111 112
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
113
    const hb_map_t &glyph_map = *c->plan->glyph_map;
114 115
    hb_vector_t<GlyphID> from;
    hb_vector_t<GlyphID> to;
116
    hb_codepoint_t delta = deltaGlyphID;
117
    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
118
    {
119 120
      if (!c->plan->glyphset->has (iter.get_glyph ()))
        continue;
121 122
      from.push ()->set (glyph_map[iter.get_glyph ()]);
      to.push ()->set (glyph_map[(iter.get_glyph () + delta) & 0xFFFF]);
123
    }
124 125
    c->serializer->err (from.in_error () || to.in_error ());

B
Minor  
Behdad Esfahbod 已提交
126 127
    Supplier<GlyphID> from_supplier (from);
    Supplier<GlyphID> to_supplier (to);
128 129 130 131 132
    SingleSubst_serialize (c->serializer,
			   from_supplier,
			   to_supplier,
			   from.len);
    return_trace (from.len);
133 134
  }

B
Behdad Esfahbod 已提交
135 136
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
137
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
138
    return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
B
Behdad Esfahbod 已提交
139 140
  }

141
  protected:
B
Behdad Esfahbod 已提交
142
  HBUINT16	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
143 144
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
145
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
146
  HBINT16	deltaGlyphID;		/* Add to original GlyphID to get
B
Behdad Esfahbod 已提交
147
					 * substitute GlyphID */
148 149
  public:
  DEFINE_SIZE_STATIC (6);
B
Behdad Esfahbod 已提交
150 151
};

B
Behdad Esfahbod 已提交
152 153
struct SingleSubstFormat2
{
154 155 156
  inline bool intersects (const hb_set_t *glyphs) const
  { return (this+coverage).intersects (glyphs); }

B
Behdad Esfahbod 已提交
157
  inline void closure (hb_closure_context_t *c) const
158
  {
B
Behdad Esfahbod 已提交
159
    TRACE_CLOSURE (this);
160
    unsigned int count = substitute.len;
161
    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
162 163
    {
      if (unlikely (iter.get_coverage () >= count))
164
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
B
Behdad Esfahbod 已提交
165
      if (c->glyphs->has (iter.get_glyph ()))
166
	c->out->add (substitute[iter.get_coverage ()]);
B
Behdad Esfahbod 已提交
167
    }
168 169
  }

170 171
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
172
    TRACE_COLLECT_GLYPHS (this);
173
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
174
    unsigned int count = substitute.len;
175
    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
176 177
    {
      if (unlikely (iter.get_coverage () >= count))
178
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
B
Minor  
Behdad Esfahbod 已提交
179
      c->output->add (substitute[iter.get_coverage ()]);
180 181 182
    }
  }

183
  inline const Coverage &get_coverage (void) const
184
  { return this+coverage; }
185

186 187
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
188
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
189
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
190 191
  }

192
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
193
  {
B
Behdad Esfahbod 已提交
194
    TRACE_APPLY (this);
195
    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
B
Behdad Esfahbod 已提交
196
    if (likely (index == NOT_COVERED)) return_trace (false);
197

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

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

B
Behdad Esfahbod 已提交
202
    return_trace (true);
203
  }
B
Behdad Esfahbod 已提交
204

B
Behdad Esfahbod 已提交
205
  inline bool serialize (hb_serialize_context_t *c,
206 207
			 Supplier<GlyphID> &glyphs,
			 Supplier<GlyphID> &substitutes,
B
Behdad Esfahbod 已提交
208 209
			 unsigned int num_glyphs)
  {
B
Behdad Esfahbod 已提交
210
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
211 212 213 214
    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 已提交
215 216
  }

217 218 219
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
220
    const hb_map_t &glyph_map = *c->plan->glyph_map;
221 222
    hb_vector_t<GlyphID> from;
    hb_vector_t<GlyphID> to;
223
    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
224 225 226
    {
      if (!c->plan->glyphset->has (iter.get_glyph ()))
        continue;
227 228
      from.push ()->set (glyph_map[iter.get_glyph ()]);
      to.push ()->set (glyph_map[substitute[iter.get_coverage ()]]);
229 230 231
    }
    c->serializer->err (from.in_error () || to.in_error ());

B
Minor  
Behdad Esfahbod 已提交
232 233
    Supplier<GlyphID> from_supplier (from);
    Supplier<GlyphID> to_supplier (to);
234 235 236 237 238
    SingleSubst_serialize (c->serializer,
			   from_supplier,
			   to_supplier,
			   from.len);
    return_trace (from.len);
239 240
  }

B
Behdad Esfahbod 已提交
241 242
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
243
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
244
    return_trace (coverage.sanitize (c, this) && substitute.sanitize (c));
B
Behdad Esfahbod 已提交
245 246
  }

247
  protected:
B
Behdad Esfahbod 已提交
248
  HBUINT16	format;			/* Format identifier--format = 2 */
B
Behdad Esfahbod 已提交
249 250
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
251
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
252 253 254
  ArrayOf<GlyphID>
		substitute;		/* Array of substitute
					 * GlyphIDs--ordered by Coverage Index */
255
  public:
256
  DEFINE_SIZE_ARRAY (6, substitute);
B
Behdad Esfahbod 已提交
257 258
};

B
Behdad Esfahbod 已提交
259 260
struct SingleSubst
{
B
Behdad Esfahbod 已提交
261
  inline bool serialize (hb_serialize_context_t *c,
262 263
			 Supplier<GlyphID> &glyphs,
			 Supplier<GlyphID> &substitutes,
B
Behdad Esfahbod 已提交
264 265
			 unsigned int num_glyphs)
  {
B
Behdad Esfahbod 已提交
266
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
267
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
B
Behdad Esfahbod 已提交
268
    unsigned int format = 2;
B
Behdad Esfahbod 已提交
269
    int delta = 0;
B
Behdad Esfahbod 已提交
270 271
    if (num_glyphs) {
      format = 1;
B
Minor  
Behdad Esfahbod 已提交
272
      /* TODO(serialize) check for wrap-around */
B
Behdad Esfahbod 已提交
273 274
      delta = substitutes[0] - glyphs[0];
      for (unsigned int i = 1; i < num_glyphs; i++)
B
Minor  
Behdad Esfahbod 已提交
275
	if (delta != (int) (substitutes[i] - glyphs[i])) {
B
Behdad Esfahbod 已提交
276 277 278 279 280 281
	  format = 2;
	  break;
	}
    }
    u.format.set (format);
    switch (u.format) {
B
Behdad Esfahbod 已提交
282 283 284
    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 已提交
285 286 287
    }
  }

B
Behdad Esfahbod 已提交
288 289 290
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
  {
291
    TRACE_DISPATCH (this, u.format);
292
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
293
    switch (u.format) {
B
Behdad Esfahbod 已提交
294 295 296
    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 已提交
297 298 299
    }
  }

300
  protected:
301
  union {
B
Behdad Esfahbod 已提交
302
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
303 304
  SingleSubstFormat1	format1;
  SingleSubstFormat2	format2;
305
  } u;
B
Behdad Esfahbod 已提交
306
};
307

308 309 310 311 312 313 314 315 316 317 318
static inline void
SingleSubst_serialize (hb_serialize_context_t *c,
		       Supplier<GlyphID> &glyphs,
		       Supplier<GlyphID> &substitutes,
		       unsigned int num_glyphs)
{
  c->start_embed<SingleSubst> ()->serialize (c,
					     glyphs,
					     substitutes,
					     num_glyphs);
}
B
Behdad Esfahbod 已提交
319

B
Behdad Esfahbod 已提交
320 321
struct Sequence
{
B
Behdad Esfahbod 已提交
322
  inline void closure (hb_closure_context_t *c) const
323
  {
B
Behdad Esfahbod 已提交
324
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
325 326
    unsigned int count = substitute.len;
    for (unsigned int i = 0; i < count; i++)
327
      c->out->add (substitute[i]);
328 329
  }

330 331
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
332
    TRACE_COLLECT_GLYPHS (this);
333
    c->output->add_array (substitute.arrayZ, substitute.len);
334 335
  }

336
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
337
  {
B
Behdad Esfahbod 已提交
338
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
339
    unsigned int count = substitute.len;
340

B
Behdad Esfahbod 已提交
341 342 343
    /* Special-case to make it in-place and not consider this
     * as a "multiplied" substitution. */
    if (unlikely (count == 1))
344
    {
345
      c->replace_glyph (substitute.arrayZ[0]);
B
Behdad Esfahbod 已提交
346
      return_trace (true);
347
    }
348
    /* Spec disallows this, but Uniscribe allows it.
349
     * https://github.com/harfbuzz/harfbuzz/issues/253 */
350 351 352 353 354
    else if (unlikely (count == 0))
    {
      c->buffer->delete_glyph ();
      return_trace (true);
    }
B
Behdad Esfahbod 已提交
355 356 357 358 359 360

    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);
361
      c->output_glyph_for_component (substitute.arrayZ[i], klass);
362
    }
B
Behdad Esfahbod 已提交
363
    c->buffer->skip_glyph ();
B
Behdad Esfahbod 已提交
364

B
Behdad Esfahbod 已提交
365
    return_trace (true);
B
Behdad Esfahbod 已提交
366 367
  }

368
  inline bool serialize (hb_serialize_context_t *c,
369
			 Supplier<GlyphID> &glyphs,
370 371
			 unsigned int num_glyphs)
  {
B
Behdad Esfahbod 已提交
372
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
373 374 375
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    if (unlikely (!substitute.serialize (c, glyphs, num_glyphs))) return_trace (false);
    return_trace (true);
376 377
  }

B
Behdad Esfahbod 已提交
378 379
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
380
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
381
    return_trace (substitute.sanitize (c));
B
Behdad Esfahbod 已提交
382 383
  }

384
  protected:
B
Behdad Esfahbod 已提交
385 386
  ArrayOf<GlyphID>
		substitute;		/* String of GlyphIDs to substitute */
387
  public:
388
  DEFINE_SIZE_ARRAY (2, substitute);
B
Behdad Esfahbod 已提交
389 390
};

B
Behdad Esfahbod 已提交
391 392
struct MultipleSubstFormat1
{
393 394 395
  inline bool intersects (const hb_set_t *glyphs) const
  { return (this+coverage).intersects (glyphs); }

B
Behdad Esfahbod 已提交
396
  inline void closure (hb_closure_context_t *c) const
397
  {
B
Behdad Esfahbod 已提交
398
    TRACE_CLOSURE (this);
399
    unsigned int count = sequence.len;
400
    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
401 402
    {
      if (unlikely (iter.get_coverage () >= count))
403
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
B
Behdad Esfahbod 已提交
404
      if (c->glyphs->has (iter.get_glyph ()))
B
Behdad Esfahbod 已提交
405
	(this+sequence[iter.get_coverage ()]).closure (c);
B
Behdad Esfahbod 已提交
406
    }
407 408
  }

409 410
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
411
    TRACE_COLLECT_GLYPHS (this);
412
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
413 414
    unsigned int count = sequence.len;
    for (unsigned int i = 0; i < count; i++)
415
      (this+sequence[i]).collect_glyphs (c);
416 417
  }

418
  inline const Coverage &get_coverage (void) const
419
  { return this+coverage; }
420

421 422
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
423
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
424
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
425 426
  }

427
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
428
  {
B
Behdad Esfahbod 已提交
429
    TRACE_APPLY (this);
430

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

B
Behdad Esfahbod 已提交
434
    return_trace ((this+sequence[index]).apply (c));
435
  }
B
Behdad Esfahbod 已提交
436

437
  inline bool serialize (hb_serialize_context_t *c,
438 439
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &substitute_len_list,
440
			 unsigned int num_glyphs,
441
			 Supplier<GlyphID> &substitute_glyphs_list)
442
  {
B
Behdad Esfahbod 已提交
443
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
444 445
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    if (unlikely (!sequence.serialize (c, num_glyphs))) return_trace (false);
446 447 448
    for (unsigned int i = 0; i < num_glyphs; i++)
      if (unlikely (!sequence[i].serialize (c, this).serialize (c,
								substitute_glyphs_list,
B
Behdad Esfahbod 已提交
449
								substitute_len_list[i]))) return_trace (false);
450
    substitute_len_list += num_glyphs;
B
Behdad Esfahbod 已提交
451 452
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
    return_trace (true);
453 454
  }

455 456 457 458 459 460 461
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

B
Behdad Esfahbod 已提交
462 463
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
464
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
465
    return_trace (coverage.sanitize (c, this) && sequence.sanitize (c, this));
B
Behdad Esfahbod 已提交
466 467
  }

468
  protected:
B
Behdad Esfahbod 已提交
469
  HBUINT16	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
470 471
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
472
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
473 474 475
  OffsetArrayOf<Sequence>
		sequence;		/* Array of Sequence tables
					 * ordered by Coverage Index */
476
  public:
477
  DEFINE_SIZE_ARRAY (6, sequence);
B
Behdad Esfahbod 已提交
478
};
479

B
Behdad Esfahbod 已提交
480 481
struct MultipleSubst
{
482
  inline bool serialize (hb_serialize_context_t *c,
483 484
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &substitute_len_list,
485
			 unsigned int num_glyphs,
486
			 Supplier<GlyphID> &substitute_glyphs_list)
487
  {
B
Behdad Esfahbod 已提交
488
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
489
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
490 491 492
    unsigned int format = 1;
    u.format.set (format);
    switch (u.format) {
B
Behdad Esfahbod 已提交
493 494
    case 1: return_trace (u.format1.serialize (c, glyphs, substitute_len_list, num_glyphs, substitute_glyphs_list));
    default:return_trace (false);
495 496 497
    }
  }

B
Behdad Esfahbod 已提交
498 499 500
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
  {
501
    TRACE_DISPATCH (this, u.format);
502
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
503
    switch (u.format) {
B
Behdad Esfahbod 已提交
504 505
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
506 507 508
    }
  }

509
  protected:
510
  union {
B
Behdad Esfahbod 已提交
511
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
512
  MultipleSubstFormat1	format1;
513 514 515
  } u;
};

516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538
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);

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

542 543 544
    /* 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);
545

546 547
    /* If alt_index is MAX, randomize feature if it is the rand feature. */
    if (alt_index == HB_OT_MAP_MAX_VALUE && c->random)
B
Behdad Esfahbod 已提交
548
      alt_index = c->random_number () % count + 1;
B
Behdad Esfahbod 已提交
549

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

552 553
    c->replace_glyph (alternates[alt_index - 1]);

554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575
    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 已提交
576
					 * arbitrary order */
577 578 579
  public:
  DEFINE_SIZE_ARRAY (2, alternates);
};
B
Behdad Esfahbod 已提交
580

B
Behdad Esfahbod 已提交
581 582
struct AlternateSubstFormat1
{
583 584 585
  inline bool intersects (const hb_set_t *glyphs) const
  { return (this+coverage).intersects (glyphs); }

B
Behdad Esfahbod 已提交
586
  inline void closure (hb_closure_context_t *c) const
587
  {
B
Behdad Esfahbod 已提交
588
    TRACE_CLOSURE (this);
589
    unsigned int count = alternateSet.len;
590
    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
591 592
    {
      if (unlikely (iter.get_coverage () >= count))
E
Ebrahim Byagowi 已提交
593
	break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
594 595
      if (c->glyphs->has (iter.get_glyph ()))
	(this+alternateSet[iter.get_coverage ()]).closure (c);
B
Behdad Esfahbod 已提交
596
    }
597 598
  }

599 600
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
601
    TRACE_COLLECT_GLYPHS (this);
602
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
603
    unsigned int count = alternateSet.len;
604
    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
605 606
    {
      if (unlikely (iter.get_coverage () >= count))
E
Ebrahim Byagowi 已提交
607
	break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
608
      (this+alternateSet[iter.get_coverage ()]).collect_glyphs (c);
609 610 611
    }
  }

612
  inline const Coverage &get_coverage (void) const
613
  { return this+coverage; }
614

615 616
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
617
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
618
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
619 620
  }

621
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
622
  {
B
Behdad Esfahbod 已提交
623
    TRACE_APPLY (this);
624

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

628
    return_trace ((this+alternateSet[index]).apply (c));
629
  }
B
Behdad Esfahbod 已提交
630

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 639
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    if (unlikely (!alternateSet.serialize (c, num_glyphs))) return_trace (false);
640 641 642
    for (unsigned int i = 0; i < num_glyphs; i++)
      if (unlikely (!alternateSet[i].serialize (c, this).serialize (c,
								    alternate_glyphs_list,
B
Behdad Esfahbod 已提交
643
								    alternate_len_list[i]))) return_trace (false);
644
    alternate_len_list += num_glyphs;
B
Behdad Esfahbod 已提交
645 646
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
    return_trace (true);
647 648
  }

649 650 651 652 653 654 655
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

B
Behdad Esfahbod 已提交
656 657
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
658
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
659
    return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
660 661
  }

662
  protected:
B
Behdad Esfahbod 已提交
663
  HBUINT16	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
664 665
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
666
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
667 668 669
  OffsetArrayOf<AlternateSet>
		alternateSet;		/* Array of AlternateSet tables
					 * ordered by Coverage Index */
670
  public:
671
  DEFINE_SIZE_ARRAY (6, alternateSet);
B
Behdad Esfahbod 已提交
672
};
673

B
Behdad Esfahbod 已提交
674 675
struct AlternateSubst
{
676
  inline bool serialize (hb_serialize_context_t *c,
677 678
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &alternate_len_list,
679
			 unsigned int num_glyphs,
680
			 Supplier<GlyphID> &alternate_glyphs_list)
681
  {
B
Behdad Esfahbod 已提交
682
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
683
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
684 685 686
    unsigned int format = 1;
    u.format.set (format);
    switch (u.format) {
B
Behdad Esfahbod 已提交
687 688
    case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, num_glyphs, alternate_glyphs_list));
    default:return_trace (false);
689 690 691
    }
  }

B
Behdad Esfahbod 已提交
692 693 694
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
  {
695
    TRACE_DISPATCH (this, u.format);
696
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
697
    switch (u.format) {
B
Behdad Esfahbod 已提交
698 699
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
700 701 702
    }
  }

703
  protected:
704
  union {
B
Behdad Esfahbod 已提交
705
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
706
  AlternateSubstFormat1	format1;
707 708 709
  } u;
};

710

B
Behdad Esfahbod 已提交
711 712
struct Ligature
{
713 714
  inline bool intersects (const hb_set_t *glyphs) const
  {
715
    unsigned int count = component.lenP1;
716 717 718 719 720 721
    for (unsigned int i = 1; i < count; i++)
      if (!glyphs->has (component[i]))
        return false;
    return true;
  }

B
Behdad Esfahbod 已提交
722
  inline void closure (hb_closure_context_t *c) const
723
  {
B
Behdad Esfahbod 已提交
724
    TRACE_CLOSURE (this);
725
    unsigned int count = component.lenP1;
B
Behdad Esfahbod 已提交
726 727
    for (unsigned int i = 1; i < count; i++)
      if (!c->glyphs->has (component[i]))
B
Behdad Esfahbod 已提交
728
        return;
729
    c->out->add (ligGlyph);
730 731
  }

732 733
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
734
    TRACE_COLLECT_GLYPHS (this);
735
    c->input->add_array (component.arrayZ, component.lenP1 ? component.lenP1 - 1 : 0);
B
Minor  
Behdad Esfahbod 已提交
736
    c->output->add (ligGlyph);
737 738
  }

739
  inline bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
740
  {
B
Behdad Esfahbod 已提交
741
    TRACE_WOULD_APPLY (this);
742
    if (c->len != component.lenP1)
B
Behdad Esfahbod 已提交
743
      return_trace (false);
744 745 746

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

B
Behdad Esfahbod 已提交
749
    return_trace (true);
B
Behdad Esfahbod 已提交
750 751
  }

752
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
753
  {
B
Behdad Esfahbod 已提交
754
    TRACE_APPLY (this);
755
    unsigned int count = component.lenP1;
B
Behdad Esfahbod 已提交
756

B
Behdad Esfahbod 已提交
757
    if (unlikely (!count)) return_trace (false);
B
Behdad Esfahbod 已提交
758

759 760 761 762 763
    /* 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 已提交
764
      return_trace (true);
765 766
    }

B
Behdad Esfahbod 已提交
767
    unsigned int total_component_count = 0;
768

769
    unsigned int match_length = 0;
770
    unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
771

772 773 774
    if (likely (!match_input (c, count,
			      &component[1],
			      match_glyph,
B
Behdad Esfahbod 已提交
775
			      nullptr,
776 777
			      &match_length,
			      match_positions,
778
			      &total_component_count)))
B
Behdad Esfahbod 已提交
779
      return_trace (false);
780

781 782
    ligate_input (c,
		  count,
783 784
		  match_positions,
		  match_length,
785
		  ligGlyph,
786
		  total_component_count);
787

B
Behdad Esfahbod 已提交
788
    return_trace (true);
789
  }
790

791 792 793 794 795
  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 已提交
796
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
797
    if (unlikely (!c->extend_min (*this))) return_trace (false);
798
    ligGlyph = ligature;
B
Behdad Esfahbod 已提交
799 800
    if (unlikely (!component.serialize (c, components, num_components))) return_trace (false);
    return_trace (true);
801 802
  }

B
Behdad Esfahbod 已提交
803
  public:
B
Behdad Esfahbod 已提交
804 805
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
806
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
807
    return_trace (ligGlyph.sanitize (c) && component.sanitize (c));
B
Behdad Esfahbod 已提交
808 809
  }

810
  protected:
811
  GlyphID	ligGlyph;		/* GlyphID of ligature to substitute */
B
Behdad Esfahbod 已提交
812 813
  HeadlessArrayOf<GlyphID>
		component;		/* Array of component GlyphIDs--start
814 815
					 * with the second  component--ordered
					 * in writing direction */
816
  public:
817
  DEFINE_SIZE_ARRAY (4, component);
818
};
B
Behdad Esfahbod 已提交
819

B
Behdad Esfahbod 已提交
820 821
struct LigatureSet
{
822 823 824 825 826 827 828 829 830
  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 已提交
831
  inline void closure (hb_closure_context_t *c) const
832
  {
B
Behdad Esfahbod 已提交
833
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
834 835
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
B
Behdad Esfahbod 已提交
836
      (this+ligature[i]).closure (c);
837 838
  }

839 840
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
841
    TRACE_COLLECT_GLYPHS (this);
842 843 844 845 846
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
      (this+ligature[i]).collect_glyphs (c);
  }

847
  inline bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
848
  {
B
Behdad Esfahbod 已提交
849
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
850 851 852 853
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
    {
      const Ligature &lig = this+ligature[i];
854
      if (lig.would_apply (c))
B
Behdad Esfahbod 已提交
855
        return_trace (true);
B
Behdad Esfahbod 已提交
856
    }
B
Behdad Esfahbod 已提交
857
    return_trace (false);
B
Behdad Esfahbod 已提交
858 859
  }

860
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
861
  {
B
Behdad Esfahbod 已提交
862
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
863
    unsigned int num_ligs = ligature.len;
B
Behdad Esfahbod 已提交
864 865
    for (unsigned int i = 0; i < num_ligs; i++)
    {
B
Behdad Esfahbod 已提交
866
      const Ligature &lig = this+ligature[i];
B
Behdad Esfahbod 已提交
867
      if (lig.apply (c)) return_trace (true);
868 869
    }

B
Behdad Esfahbod 已提交
870
    return_trace (false);
871
  }
B
Behdad Esfahbod 已提交
872

873 874 875 876 877 878
  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 已提交
879
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
880 881
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    if (unlikely (!ligature.serialize (c, num_ligatures))) return_trace (false);
882 883 884 885
    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 已提交
886
								component_count_list[i]))) return_trace (false);
887 888
    ligatures += num_ligatures;
    component_count_list += num_ligatures;
B
Behdad Esfahbod 已提交
889
    return_trace (true);
890 891
  }

B
Behdad Esfahbod 已提交
892 893
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
894
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
895
    return_trace (ligature.sanitize (c, this));
B
Behdad Esfahbod 已提交
896 897
  }

898
  protected:
B
Behdad Esfahbod 已提交
899 900 901
  OffsetArrayOf<Ligature>
		ligature;		/* Array LigatureSet tables
					 * ordered by preference */
902
  public:
903
  DEFINE_SIZE_ARRAY (2, ligature);
B
Behdad Esfahbod 已提交
904 905
};

B
Behdad Esfahbod 已提交
906 907
struct LigatureSubstFormat1
{
908 909 910
  inline bool intersects (const hb_set_t *glyphs) const
  {
    unsigned int count = ligatureSet.len;
911
    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
912 913 914 915 916 917 918 919 920 921
    {
      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 已提交
922
  inline void closure (hb_closure_context_t *c) const
923
  {
B
Behdad Esfahbod 已提交
924
    TRACE_CLOSURE (this);
925
    unsigned int count = ligatureSet.len;
926
    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
927 928
    {
      if (unlikely (iter.get_coverage () >= count))
929
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
B
Behdad Esfahbod 已提交
930
      if (c->glyphs->has (iter.get_glyph ()))
B
Behdad Esfahbod 已提交
931
	(this+ligatureSet[iter.get_coverage ()]).closure (c);
B
Behdad Esfahbod 已提交
932
    }
933 934
  }

935 936
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
937
    TRACE_COLLECT_GLYPHS (this);
938
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
939
    unsigned int count = ligatureSet.len;
940
    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
941 942
    {
      if (unlikely (iter.get_coverage () >= count))
943
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
944 945 946 947
      (this+ligatureSet[iter.get_coverage ()]).collect_glyphs (c);
    }
  }

948
  inline const Coverage &get_coverage (void) const
949
  { return this+coverage; }
950

951
  inline bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
952
  {
B
Behdad Esfahbod 已提交
953
    TRACE_WOULD_APPLY (this);
954
    unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
B
Behdad Esfahbod 已提交
955
    if (likely (index == NOT_COVERED)) return_trace (false);
956 957

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

961
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
962
  {
B
Behdad Esfahbod 已提交
963
    TRACE_APPLY (this);
964

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

B
Behdad Esfahbod 已提交
968
    const LigatureSet &lig_set = this+ligatureSet[index];
B
Behdad Esfahbod 已提交
969
    return_trace (lig_set.apply (c));
970
  }
B
Behdad Esfahbod 已提交
971

972 973 974 975 976 977 978 979
  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 已提交
980
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
981 982
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    if (unlikely (!ligatureSet.serialize (c, num_first_glyphs))) return_trace (false);
983 984 985 986 987
    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 已提交
988
								   component_list))) return_trace (false);
989
    ligature_per_first_glyph_count_list += num_first_glyphs;
B
Behdad Esfahbod 已提交
990 991
    if (unlikely (!coverage.serialize (c, this).serialize (c, first_glyphs, num_first_glyphs))) return_trace (false);
    return_trace (true);
992 993
  }

994 995 996 997 998 999 1000
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

B
Behdad Esfahbod 已提交
1001 1002
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1003
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1004
    return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
1005 1006
  }

1007
  protected:
B
Behdad Esfahbod 已提交
1008
  HBUINT16	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
1009 1010
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
1011
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
1012
  OffsetArrayOf<LigatureSet>
B
Behdad Esfahbod 已提交
1013 1014
		ligatureSet;		/* Array LigatureSet tables
					 * ordered by Coverage Index */
1015
  public:
1016
  DEFINE_SIZE_ARRAY (6, ligatureSet);
B
Behdad Esfahbod 已提交
1017
};
1018

B
Behdad Esfahbod 已提交
1019 1020
struct LigatureSubst
{
1021 1022 1023 1024 1025 1026 1027 1028
  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 已提交
1029
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1030
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
1031 1032 1033
    unsigned int format = 1;
    u.format.set (format);
    switch (u.format) {
B
Behdad Esfahbod 已提交
1034 1035 1036 1037 1038 1039 1040 1041
    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);
1042 1043 1044
    }
  }

B
Behdad Esfahbod 已提交
1045 1046 1047
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
  {
1048
    TRACE_DISPATCH (this, u.format);
1049
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
1050
    switch (u.format) {
B
Behdad Esfahbod 已提交
1051 1052
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
1053 1054 1055
    }
  }

1056
  protected:
1057
  union {
B
Behdad Esfahbod 已提交
1058
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1059
  LigatureSubstFormat1	format1;
1060 1061 1062
  } u;
};

B
Behdad Esfahbod 已提交
1063

B
Minor  
Behdad Esfahbod 已提交
1064
struct ContextSubst : Context {};
B
Behdad Esfahbod 已提交
1065

B
Minor  
Behdad Esfahbod 已提交
1066
struct ChainContextSubst : ChainContext {};
1067

B
Behdad Esfahbod 已提交
1068
struct ExtensionSubst : Extension<ExtensionSubst>
B
Behdad Esfahbod 已提交
1069
{
B
Behdad Esfahbod 已提交
1070
  typedef struct SubstLookupSubTable SubTable;
B
Behdad Esfahbod 已提交
1071

B
Behdad Esfahbod 已提交
1072
  inline bool is_reverse (void) const;
1073 1074 1075
};


B
Behdad Esfahbod 已提交
1076 1077
struct ReverseChainSingleSubstFormat1
{
1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099
  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 已提交
1100
  inline void closure (hb_closure_context_t *c) const
1101
  {
B
Behdad Esfahbod 已提交
1102
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
1103 1104 1105 1106 1107 1108 1109
    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 已提交
1110
        return;
B
Behdad Esfahbod 已提交
1111 1112 1113 1114

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

    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
1118
    count = substitute.len;
1119
    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
1120 1121
    {
      if (unlikely (iter.get_coverage () >= count))
1122
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
B
Behdad Esfahbod 已提交
1123
      if (c->glyphs->has (iter.get_glyph ()))
1124
	c->out->add (substitute[iter.get_coverage ()]);
B
Behdad Esfahbod 已提交
1125
    }
1126 1127
  }

1128 1129
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1130
    TRACE_COLLECT_GLYPHS (this);
1131
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
1132 1133 1134 1135 1136

    unsigned int count;

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

1139
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1140 1141
    count = lookahead.len;
    for (unsigned int i = 0; i < count; i++)
1142
      if (unlikely (!(this+lookahead[i]).add_coverage (c->after))) return;
1143 1144 1145

    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
    count = substitute.len;
1146
    c->output->add_array (substitute.arrayZ, substitute.len);
1147 1148
  }

1149
  inline const Coverage &get_coverage (void) const
1150
  { return this+coverage; }
1151

1152 1153
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1154
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
1155
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
1156 1157
  }

1158
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1159
  {
B
Behdad Esfahbod 已提交
1160
    TRACE_APPLY (this);
1161
    if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
B
Behdad Esfahbod 已提交
1162
      return_trace (false); /* No chaining to this type */
1163

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

1167 1168
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
1169

1170
  unsigned int start_index = 0, end_index = 0;
B
Behdad Esfahbod 已提交
1171
    if (match_backtrack (c,
1172
			 backtrack.len, (HBUINT16 *) backtrack.arrayZ,
1173 1174
			 match_coverage, this,
			 &start_index) &&
B
Behdad Esfahbod 已提交
1175
        match_lookahead (c,
1176
			 lookahead.len, (HBUINT16 *) lookahead.arrayZ,
B
Behdad Esfahbod 已提交
1177
			 match_coverage, this,
1178
			 1, &end_index))
1179
    {
1180
      c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index);
B
Behdad Esfahbod 已提交
1181
      c->replace_glyph_inplace (substitute[index]);
1182 1183 1184
      /* 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 已提交
1185
      return_trace (true);
1186 1187
    }

B
Behdad Esfahbod 已提交
1188
    return_trace (false);
1189
  }
B
Behdad Esfahbod 已提交
1190

1191 1192 1193 1194 1195 1196 1197
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

B
Behdad Esfahbod 已提交
1198 1199
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1200
    TRACE_SANITIZE (this);
1201
    if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
B
Behdad Esfahbod 已提交
1202
      return_trace (false);
B
Behdad Esfahbod 已提交
1203
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
B
Behdad Esfahbod 已提交
1204
    if (!lookahead.sanitize (c, this))
B
Behdad Esfahbod 已提交
1205
      return_trace (false);
B
Behdad Esfahbod 已提交
1206
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
B
Behdad Esfahbod 已提交
1207
    return_trace (substitute.sanitize (c));
B
Behdad Esfahbod 已提交
1208 1209
  }

1210
  protected:
B
Behdad Esfahbod 已提交
1211
  HBUINT16	format;			/* Format identifier--format = 1 */
1212 1213 1214 1215 1216
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of table */
  OffsetArrayOf<Coverage>
		backtrack;		/* Array of coverage tables
1217
					 * in backtracking sequence, in glyph
B
Behdad Esfahbod 已提交
1218
					 * sequence order */
1219 1220 1221
  OffsetArrayOf<Coverage>
		lookaheadX;		/* Array of coverage tables
					 * in lookahead sequence, in glyph
B
Behdad Esfahbod 已提交
1222
					 * sequence order */
1223 1224 1225
  ArrayOf<GlyphID>
		substituteX;		/* Array of substitute
					 * GlyphIDs--ordered by Coverage Index */
1226
  public:
B
Behdad Esfahbod 已提交
1227
  DEFINE_SIZE_MIN (10);
B
Behdad Esfahbod 已提交
1228 1229
};

B
Behdad Esfahbod 已提交
1230 1231
struct ReverseChainSingleSubst
{
1232
  template <typename context_t>
1233
  inline typename context_t::return_t dispatch (context_t *c) const
1234
  {
1235
    TRACE_DISPATCH (this, u.format);
1236
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1237
    switch (u.format) {
B
Behdad Esfahbod 已提交
1238 1239
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
1240 1241 1242
    }
  }

1243
  protected:
1244
  union {
B
Behdad Esfahbod 已提交
1245
  HBUINT16				format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1246
  ReverseChainSingleSubstFormat1	format1;
1247 1248 1249 1250 1251
  } u;
};



B
Behdad Esfahbod 已提交
1252 1253 1254 1255
/*
 * SubstLookup
 */

B
Behdad Esfahbod 已提交
1256 1257
struct SubstLookupSubTable
{
B
Behdad Esfahbod 已提交
1258
  friend struct Lookup;
B
Behdad Esfahbod 已提交
1259 1260
  friend struct SubstLookup;

B
Behdad Esfahbod 已提交
1261
  enum Type {
1262 1263 1264 1265 1266 1267 1268
    Single		= 1,
    Multiple		= 2,
    Alternate		= 3,
    Ligature		= 4,
    Context		= 5,
    ChainContext	= 6,
    Extension		= 7,
1269
    ReverseChainSingle	= 8
1270 1271
  };

1272
  template <typename context_t>
1273
  inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
1274
  {
1275
    TRACE_DISPATCH (this, lookup_type);
1276
    switch (lookup_type) {
B
Behdad Esfahbod 已提交
1277 1278 1279 1280 1281 1282 1283 1284 1285
    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 ());
1286 1287 1288
    }
  }

1289
  protected:
B
Behdad Esfahbod 已提交
1290
  union {
B
Behdad Esfahbod 已提交
1291 1292 1293 1294
  SingleSubst			single;
  MultipleSubst			multiple;
  AlternateSubst		alternate;
  LigatureSubst			ligature;
1295
  ContextSubst			context;
B
Behdad Esfahbod 已提交
1296 1297 1298
  ChainContextSubst		chainContext;
  ExtensionSubst		extension;
  ReverseChainSingleSubst	reverseChainContextSingle;
B
Behdad Esfahbod 已提交
1299
  } u;
B
Behdad Esfahbod 已提交
1300
  public:
B
Behdad Esfahbod 已提交
1301
  DEFINE_SIZE_MIN (0);
B
Behdad Esfahbod 已提交
1302 1303
};

1304

B
Behdad Esfahbod 已提交
1305 1306
struct SubstLookup : Lookup
{
B
Behdad Esfahbod 已提交
1307 1308 1309 1310
  typedef SubstLookupSubTable SubTable;

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

B
Behdad Esfahbod 已提交
1312
  inline static bool lookup_type_is_reverse (unsigned int lookup_type)
B
Behdad Esfahbod 已提交
1313
  { return lookup_type == SubTable::ReverseChainSingle; }
B
Behdad Esfahbod 已提交
1314 1315

  inline bool is_reverse (void) const
B
Behdad Esfahbod 已提交
1316
  {
B
Behdad Esfahbod 已提交
1317
    unsigned int type = get_type ();
B
Behdad Esfahbod 已提交
1318
    if (unlikely (type == SubTable::Extension))
1319
      return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
B
Behdad Esfahbod 已提交
1320
    return lookup_type_is_reverse (type);
B
Behdad Esfahbod 已提交
1321
  }
1322

1323
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1324 1325
  {
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
1326
    return_trace (dispatch (c));
B
Behdad Esfahbod 已提交
1327 1328
  }

1329 1330 1331 1332 1333 1334
  inline bool intersects (const hb_set_t *glyphs) const
  {
    hb_intersects_context_t c (glyphs);
    return dispatch (&c);
  }

1335
  inline hb_closure_context_t::return_t closure (hb_closure_context_t *c, unsigned int this_index) const
1336
  {
B
Behdad Esfahbod 已提交
1337
    TRACE_CLOSURE (this);
1338
    if (!c->should_visit_lookup (this_index))
1339 1340 1341
      return_trace (HB_VOID);

    c->set_recurse_func (dispatch_closure_recurse_func);
1342 1343 1344 1345 1346 1347

    hb_closure_context_t::return_t ret = dispatch (c);

    c->flush ();

    return_trace (ret);
B
Behdad Esfahbod 已提交
1348 1349
  }

B
Behdad Esfahbod 已提交
1350
  inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
B
Behdad Esfahbod 已提交
1351 1352
  {
    TRACE_COLLECT_GLYPHS (this);
1353
    c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
B
Behdad Esfahbod 已提交
1354
    return_trace (dispatch (c));
1355 1356
  }

B
Behdad Esfahbod 已提交
1357 1358 1359
  template <typename set_t>
  inline void add_coverage (set_t *glyphs) const
  {
1360 1361
    hb_add_coverage_context_t<set_t> c (glyphs);
    dispatch (&c);
B
Behdad Esfahbod 已提交
1362 1363
  }

1364 1365
  inline bool would_apply (hb_would_apply_context_t *c,
			   const hb_ot_layout_lookup_accelerator_t *accel) const
B
Behdad Esfahbod 已提交
1366
  {
B
Behdad Esfahbod 已提交
1367
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
1368 1369 1370
    if (unlikely (!c->len))  return_trace (false);
    if (!accel->may_have (c->glyphs[0]))  return_trace (false);
      return_trace (dispatch (c));
B
Behdad Esfahbod 已提交
1371 1372
  }

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

B
Behdad Esfahbod 已提交
1375 1376 1377
  inline SubTable& serialize_subtable (hb_serialize_context_t *c,
				       unsigned int i)
  { return get_subtables<SubTable> ()[i].serialize (c, this); }
1378 1379 1380 1381 1382 1383 1384

  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 已提交
1385
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1386
    if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1387
    return_trace (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes, num_glyphs));
1388 1389 1390 1391 1392 1393 1394 1395 1396
  }

  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 已提交
1397
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1398
    if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1399 1400 1401 1402 1403
    return_trace (serialize_subtable (c, 0).u.multiple.serialize (c,
								  glyphs,
								  substitute_len_list,
								  num_glyphs,
								  substitute_glyphs_list));
1404 1405 1406 1407 1408 1409 1410 1411 1412
  }

  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 已提交
1413
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1414
    if (unlikely (!Lookup::serialize (c, SubTable::Alternate, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1415 1416 1417 1418 1419
    return_trace (serialize_subtable (c, 0).u.alternate.serialize (c,
								   glyphs,
								   alternate_len_list,
								   num_glyphs,
								   alternate_glyphs_list));
1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430
  }

  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 已提交
1431
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1432
    if (unlikely (!Lookup::serialize (c, SubTable::Ligature, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1433 1434 1435 1436 1437 1438 1439
    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));
1440 1441
  }

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

B
Behdad Esfahbod 已提交
1445
  static inline hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned int lookup_index)
1446
  {
1447
    if (!c->should_visit_lookup (lookup_index))
1448
      return HB_VOID;
1449 1450 1451

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

1452 1453 1454 1455
    /* While in theory we should flush here, it will cause timeouts because a recursive
     * lookup can keep growing the glyph set.  Skip, and outer loop will retry up to
     * HB_CLOSURE_MAX_STAGES time, which should be enough for every realistic font. */
    //c->flush ();
1456 1457

    return ret;
1458 1459
  }

B
Behdad Esfahbod 已提交
1460 1461
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
B
Behdad Esfahbod 已提交
1462 1463 1464
  { return Lookup::dispatch<SubTable> (c); }

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

B
Behdad Esfahbod 已提交
1467
  inline bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
1468
  { return Lookup::sanitize<SubTable> (c); }
B
Behdad Esfahbod 已提交
1469 1470
};

B
Minor  
Behdad Esfahbod 已提交
1471
/*
1472 1473
 * GSUB -- Glyph Substitution
 * https://docs.microsoft.com/en-us/typography/opentype/spec/gsub
B
Minor  
Behdad Esfahbod 已提交
1474 1475
 */

B
Behdad Esfahbod 已提交
1476 1477
struct GSUB : GSUBGPOS
{
1478
  enum { tableTag = HB_OT_TAG_GSUB };
B
Minor  
Behdad Esfahbod 已提交
1479

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

1483
  inline bool subset (hb_subset_context_t *c) const
1484
  { return GSUBGPOS::subset<SubstLookup> (c); }
1485

B
Behdad Esfahbod 已提交
1486
  inline bool sanitize (hb_sanitize_context_t *c) const
1487
  { return GSUBGPOS::sanitize<SubstLookup> (c); }
B
WIP  
Behdad Esfahbod 已提交
1488

1489 1490 1491
  HB_INTERNAL bool is_blacklisted (hb_blob_t *blob,
				   hb_face_t *face) const;

B
WIP  
Behdad Esfahbod 已提交
1492
  typedef GSUBGPOS::accelerator_t<GSUB> accelerator_t;
B
Minor  
Behdad Esfahbod 已提交
1493
};
1494 1495


B
Behdad Esfahbod 已提交
1496 1497 1498
struct GSUB_accelerator_t : GSUB::accelerator_t {};


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

1501
/*static*/ inline bool ExtensionSubst::is_reverse (void) const
B
Behdad Esfahbod 已提交
1502 1503
{
  unsigned int type = get_type ();
B
Behdad Esfahbod 已提交
1504 1505
  if (unlikely (type == SubTable::Extension))
    return CastR<ExtensionSubst> (get_subtable<SubTable>()).is_reverse ();
B
Behdad Esfahbod 已提交
1506 1507 1508
  return SubstLookup::lookup_type_is_reverse (type);
}

1509
template <typename context_t>
1510
/*static*/ inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
1511
{
B
Behdad Esfahbod 已提交
1512
  const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index);
1513
  return l.dispatch (c);
1514 1515
}

1516
/*static*/ inline bool SubstLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index)
B
Behdad Esfahbod 已提交
1517
{
B
Behdad Esfahbod 已提交
1518
  const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index);
1519
  unsigned int saved_lookup_props = c->lookup_props;
1520 1521 1522
  unsigned int saved_lookup_index = c->lookup_index;
  c->set_lookup_index (lookup_index);
  c->set_lookup_props (l.get_props ());
1523
  bool ret = l.dispatch (c);
1524
  c->set_lookup_index (saved_lookup_index);
1525
  c->set_lookup_props (saved_lookup_props);
1526
  return ret;
1527 1528
}

B
Behdad Esfahbod 已提交
1529
} /* namespace OT */
1530

B
Behdad Esfahbod 已提交
1531

1532
#endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */