hb-ot-layout-gsub-table.hh 46.2 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 (hb_auto_t<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 (hb_auto_t<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
Minor  
Behdad Esfahbod 已提交
106
    deltaGlyphID.set (delta); /* TODO(serilaize) 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 114
    hb_auto_t<hb_vector_t<GlyphID> > from;
    hb_auto_t<hb_vector_t<GlyphID> > to;
115 116 117
    hb_codepoint_t delta = deltaGlyphID;
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
    {
118 119 120 121
      if (!c->plan->glyphset->has (iter.get_glyph ()))
        continue;
      from.push ()->set (iter.get_glyph ());
      to.push ()->set ((iter.get_glyph () + delta) & 0xFFFF);
122
    }
123 124 125 126 127 128 129 130 131
    c->serializer->err (from.in_error () || to.in_error ());

    Supplier<GlyphID> from_supplier (&from);
    Supplier<GlyphID> to_supplier (&to);
    SingleSubst_serialize (c->serializer,
			   from_supplier,
			   to_supplier,
			   from.len);
    return_trace (from.len);
132 133
  }

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

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

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

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

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

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

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

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

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

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

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

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

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

    Supplier<GlyphID> from_supplier (&from);
    Supplier<GlyphID> to_supplier (&to);
    SingleSubst_serialize (c->serializer,
			   from_supplier,
			   to_supplier,
			   from.len);
    return_trace (from.len);
237 238
  }

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

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

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

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

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

306 307 308 309 310 311 312 313 314 315 316
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 已提交
317

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

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

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

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

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

B
Behdad Esfahbod 已提交
363
    return_trace (true);
B
Behdad Esfahbod 已提交
364 365
  }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

537 538
    if (c->random)
    {
D
David Corbett 已提交
539 540
      c->random_state = (0x5DEECE66Dull * c->random_state + 11) & (((uint64_t) 1 << 48) - 1);
      c->replace_glyph (alternates[(c->random_state >> 32) % count]);
541 542 543
    }
    else
    {
D
David Corbett 已提交
544 545
      hb_mask_t glyph_mask = c->buffer->cur().mask;
      hb_mask_t lookup_mask = c->lookup_mask;
546

D
David Corbett 已提交
547 548 549
      /* 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);
550

D
David Corbett 已提交
551
      if (unlikely (alt_index > count || alt_index == 0)) return_trace (false);
552

D
David Corbett 已提交
553 554
      c->replace_glyph (alternates[alt_index - 1]);
    }
B
Behdad Esfahbod 已提交
555

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

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

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

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

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

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

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

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

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

633
  inline bool serialize (hb_serialize_context_t *c,
634 635
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &alternate_len_list,
636
			 unsigned int num_glyphs,
637
			 Supplier<GlyphID> &alternate_glyphs_list)
638
  {
B
Behdad Esfahbod 已提交
639
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
640 641
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    if (unlikely (!alternateSet.serialize (c, num_glyphs))) return_trace (false);
642 643 644
    for (unsigned int i = 0; i < num_glyphs; i++)
      if (unlikely (!alternateSet[i].serialize (c, this).serialize (c,
								    alternate_glyphs_list,
B
Behdad Esfahbod 已提交
645
								    alternate_len_list[i]))) return_trace (false);
646
    alternate_len_list += num_glyphs;
B
Behdad Esfahbod 已提交
647 648
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
    return_trace (true);
649 650
  }

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

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

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

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

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

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

712

B
Behdad Esfahbod 已提交
713 714
struct Ligature
{
715 716 717 718 719 720 721 722 723
  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 已提交
724
  inline void closure (hb_closure_context_t *c) const
725
  {
B
Behdad Esfahbod 已提交
726
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
727 728 729
    unsigned int count = component.len;
    for (unsigned int i = 1; i < count; i++)
      if (!c->glyphs->has (component[i]))
B
Behdad Esfahbod 已提交
730
        return;
731
    c->out->add (ligGlyph);
732 733
  }

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

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

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

B
Behdad Esfahbod 已提交
751
    return_trace (true);
B
Behdad Esfahbod 已提交
752 753
  }

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

B
Behdad Esfahbod 已提交
759
    if (unlikely (!count)) return_trace (false);
B
Behdad Esfahbod 已提交
760

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

B
Behdad Esfahbod 已提交
769 770
    bool is_mark_ligature = false;
    unsigned int total_component_count = 0;
771

772
    unsigned int match_length = 0;
773
    unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
774

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

785 786
    ligate_input (c,
		  count,
787 788
		  match_positions,
		  match_length,
789
		  ligGlyph,
790 791
		  is_mark_ligature,
		  total_component_count);
792

B
Behdad Esfahbod 已提交
793
    return_trace (true);
794
  }
795

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

B
Behdad Esfahbod 已提交
808
  public:
B
Behdad Esfahbod 已提交
809 810
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
811
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
812
    return_trace (ligGlyph.sanitize (c) && component.sanitize (c));
B
Behdad Esfahbod 已提交
813 814
  }

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

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

844 845
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
846
    TRACE_COLLECT_GLYPHS (this);
847 848 849 850 851
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
      (this+ligature[i]).collect_glyphs (c);
  }

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

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

B
Behdad Esfahbod 已提交
875
    return_trace (false);
876
  }
B
Behdad Esfahbod 已提交
877

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

B
Behdad Esfahbod 已提交
897 898
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
899
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
900
    return_trace (ligature.sanitize (c, this));
B
Behdad Esfahbod 已提交
901 902
  }

903
  protected:
B
Behdad Esfahbod 已提交
904 905 906
  OffsetArrayOf<Ligature>
		ligature;		/* Array LigatureSet tables
					 * ordered by preference */
907
  public:
908
  DEFINE_SIZE_ARRAY (2, ligature);
B
Behdad Esfahbod 已提交
909 910
};

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

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

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

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

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

966
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
967
  {
B
Behdad Esfahbod 已提交
968
    TRACE_APPLY (this);
969

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

B
Behdad Esfahbod 已提交
973
    const LigatureSet &lig_set = this+ligatureSet[index];
B
Behdad Esfahbod 已提交
974
    return_trace (lig_set.apply (c));
975
  }
B
Behdad Esfahbod 已提交
976

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

999 1000 1001 1002 1003 1004 1005
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

B
Behdad Esfahbod 已提交
1006 1007
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1008
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1009
    return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
1010 1011
  }

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

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

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

1061
  protected:
1062
  union {
B
Behdad Esfahbod 已提交
1063
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1064
  LigatureSubstFormat1	format1;
1065 1066 1067
  } u;
};

B
Behdad Esfahbod 已提交
1068

B
Minor  
Behdad Esfahbod 已提交
1069
struct ContextSubst : Context {};
B
Behdad Esfahbod 已提交
1070

B
Minor  
Behdad Esfahbod 已提交
1071
struct ChainContextSubst : ChainContext {};
1072

B
Behdad Esfahbod 已提交
1073
struct ExtensionSubst : Extension<ExtensionSubst>
B
Behdad Esfahbod 已提交
1074
{
B
Behdad Esfahbod 已提交
1075
  typedef struct SubstLookupSubTable SubTable;
B
Behdad Esfahbod 已提交
1076

B
Behdad Esfahbod 已提交
1077
  inline bool is_reverse (void) const;
1078 1079 1080
};


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

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

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

1133 1134
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1135
    TRACE_COLLECT_GLYPHS (this);
1136
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
1137 1138 1139 1140 1141

    unsigned int count;

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

1144
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1145 1146
    count = lookahead.len;
    for (unsigned int i = 0; i < count; i++)
1147
      if (unlikely (!(this+lookahead[i]).add_coverage (c->after))) return;
1148 1149 1150

    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
    count = substitute.len;
1151
    c->output->add_array (substitute.arrayZ, substitute.len);
1152 1153
  }

1154
  inline const Coverage &get_coverage (void) const
1155
  { return this+coverage; }
1156

1157 1158
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1159
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
1160
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
1161 1162
  }

1163
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1164
  {
B
Behdad Esfahbod 已提交
1165
    TRACE_APPLY (this);
1166
    if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
B
Behdad Esfahbod 已提交
1167
      return_trace (false); /* No chaining to this type */
1168

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

1172 1173
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
1174

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

B
Behdad Esfahbod 已提交
1193
    return_trace (false);
1194
  }
B
Behdad Esfahbod 已提交
1195

1196 1197 1198 1199 1200 1201 1202
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

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

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

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

1248
  protected:
1249
  union {
B
Behdad Esfahbod 已提交
1250
  HBUINT16				format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1251
  ReverseChainSingleSubstFormat1	format1;
1252 1253 1254 1255 1256
  } u;
};



B
Behdad Esfahbod 已提交
1257 1258 1259 1260
/*
 * SubstLookup
 */

B
Behdad Esfahbod 已提交
1261 1262
struct SubstLookupSubTable
{
B
Behdad Esfahbod 已提交
1263
  friend struct Lookup;
B
Behdad Esfahbod 已提交
1264 1265
  friend struct SubstLookup;

B
Behdad Esfahbod 已提交
1266
  enum Type {
1267 1268 1269 1270 1271 1272 1273
    Single		= 1,
    Multiple		= 2,
    Alternate		= 3,
    Ligature		= 4,
    Context		= 5,
    ChainContext	= 6,
    Extension		= 7,
1274
    ReverseChainSingle	= 8
1275 1276
  };

1277
  template <typename context_t>
1278
  inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
1279
  {
1280
    TRACE_DISPATCH (this, lookup_type);
1281
    if (unlikely (!c->may_dispatch (this, &u.sub_format))) return_trace (c->no_dispatch_return_value ());
1282
    switch (lookup_type) {
B
Behdad Esfahbod 已提交
1283 1284 1285 1286 1287 1288 1289 1290 1291
    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 ());
1292 1293 1294
    }
  }

1295
  protected:
B
Behdad Esfahbod 已提交
1296
  union {
B
Behdad Esfahbod 已提交
1297
  HBUINT16			sub_format;
B
Behdad Esfahbod 已提交
1298 1299 1300 1301
  SingleSubst			single;
  MultipleSubst			multiple;
  AlternateSubst		alternate;
  LigatureSubst			ligature;
1302
  ContextSubst			context;
B
Behdad Esfahbod 已提交
1303 1304 1305
  ChainContextSubst		chainContext;
  ExtensionSubst		extension;
  ReverseChainSingleSubst	reverseChainContextSingle;
B
Behdad Esfahbod 已提交
1306
  } u;
B
Behdad Esfahbod 已提交
1307
  public:
B
Minor  
Behdad Esfahbod 已提交
1308
  DEFINE_SIZE_UNION (2, sub_format);
B
Behdad Esfahbod 已提交
1309 1310
};

1311

B
Behdad Esfahbod 已提交
1312 1313
struct SubstLookup : Lookup
{
B
Behdad Esfahbod 已提交
1314 1315 1316 1317
  typedef SubstLookupSubTable SubTable;

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

B
Behdad Esfahbod 已提交
1319
  inline static bool lookup_type_is_reverse (unsigned int lookup_type)
B
Behdad Esfahbod 已提交
1320
  { return lookup_type == SubTable::ReverseChainSingle; }
B
Behdad Esfahbod 已提交
1321 1322

  inline bool is_reverse (void) const
B
Behdad Esfahbod 已提交
1323
  {
B
Behdad Esfahbod 已提交
1324
    unsigned int type = get_type ();
B
Behdad Esfahbod 已提交
1325
    if (unlikely (type == SubTable::Extension))
1326
      return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
B
Behdad Esfahbod 已提交
1327
    return lookup_type_is_reverse (type);
B
Behdad Esfahbod 已提交
1328
  }
1329

1330
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1331 1332
  {
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
1333
    return_trace (dispatch (c));
B
Behdad Esfahbod 已提交
1334 1335
  }

1336 1337 1338 1339 1340 1341
  inline bool intersects (const hb_set_t *glyphs) const
  {
    hb_intersects_context_t c (glyphs);
    return dispatch (&c);
  }

1342
  inline hb_closure_context_t::return_t closure (hb_closure_context_t *c, unsigned int this_index) const
1343
  {
B
Behdad Esfahbod 已提交
1344
    TRACE_CLOSURE (this);
1345
    if (!c->should_visit_lookup (this_index))
1346 1347 1348
      return_trace (HB_VOID);

    c->set_recurse_func (dispatch_closure_recurse_func);
1349 1350 1351 1352 1353 1354

    hb_closure_context_t::return_t ret = dispatch (c);

    c->flush ();

    return_trace (ret);
B
Behdad Esfahbod 已提交
1355 1356
  }

B
Behdad Esfahbod 已提交
1357
  inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
B
Behdad Esfahbod 已提交
1358 1359
  {
    TRACE_COLLECT_GLYPHS (this);
1360
    c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
B
Behdad Esfahbod 已提交
1361
    return_trace (dispatch (c));
1362 1363
  }

B
Behdad Esfahbod 已提交
1364 1365 1366
  template <typename set_t>
  inline void add_coverage (set_t *glyphs) const
  {
1367 1368
    hb_add_coverage_context_t<set_t> c (glyphs);
    dispatch (&c);
B
Behdad Esfahbod 已提交
1369 1370
  }

1371 1372
  inline bool would_apply (hb_would_apply_context_t *c,
			   const hb_ot_layout_lookup_accelerator_t *accel) const
B
Behdad Esfahbod 已提交
1373
  {
B
Behdad Esfahbod 已提交
1374
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
1375 1376 1377
    if (unlikely (!c->len))  return_trace (false);
    if (!accel->may_have (c->glyphs[0]))  return_trace (false);
      return_trace (dispatch (c));
B
Behdad Esfahbod 已提交
1378 1379
  }

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

B
Behdad Esfahbod 已提交
1382 1383 1384
  inline SubTable& serialize_subtable (hb_serialize_context_t *c,
				       unsigned int i)
  { return get_subtables<SubTable> ()[i].serialize (c, this); }
1385 1386 1387 1388 1389 1390 1391

  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 已提交
1392
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1393
    if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1394
    return_trace (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes, num_glyphs));
1395 1396 1397 1398 1399 1400 1401 1402 1403
  }

  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 已提交
1404
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1405
    if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1406 1407 1408 1409 1410
    return_trace (serialize_subtable (c, 0).u.multiple.serialize (c,
								  glyphs,
								  substitute_len_list,
								  num_glyphs,
								  substitute_glyphs_list));
1411 1412 1413 1414 1415 1416 1417 1418 1419
  }

  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 已提交
1420
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1421
    if (unlikely (!Lookup::serialize (c, SubTable::Alternate, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1422 1423 1424 1425 1426
    return_trace (serialize_subtable (c, 0).u.alternate.serialize (c,
								   glyphs,
								   alternate_len_list,
								   num_glyphs,
								   alternate_glyphs_list));
1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437
  }

  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 已提交
1438
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1439
    if (unlikely (!Lookup::serialize (c, SubTable::Ligature, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1440 1441 1442 1443 1444 1445 1446
    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));
1447 1448
  }

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

B
Behdad Esfahbod 已提交
1452
  static inline hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned int lookup_index)
1453
  {
1454
    if (!c->should_visit_lookup (lookup_index))
1455
      return HB_VOID;
1456 1457 1458 1459 1460 1461

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

    c->flush ();

    return ret;
1462 1463
  }

B
Behdad Esfahbod 已提交
1464 1465
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
B
Behdad Esfahbod 已提交
1466 1467 1468
  { return Lookup::dispatch<SubTable> (c); }

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

B
Behdad Esfahbod 已提交
1471
  inline bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
1472
  { return Lookup::sanitize<SubTable> (c); }
B
Behdad Esfahbod 已提交
1473 1474
};

B
Minor  
Behdad Esfahbod 已提交
1475
/*
1476 1477
 * GSUB -- Glyph Substitution
 * https://docs.microsoft.com/en-us/typography/opentype/spec/gsub
B
Minor  
Behdad Esfahbod 已提交
1478 1479
 */

B
Behdad Esfahbod 已提交
1480 1481
struct GSUB : GSUBGPOS
{
1482
  static const hb_tag_t tableTag	= HB_OT_TAG_GSUB;
B
Minor  
Behdad Esfahbod 已提交
1483

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

1487
  inline bool subset (hb_subset_context_t *c) const
1488
  { return GSUBGPOS::subset<SubstLookup> (c); }
1489

B
Behdad Esfahbod 已提交
1490
  inline bool sanitize (hb_sanitize_context_t *c) const
1491
  { return GSUBGPOS::sanitize<SubstLookup> (c); }
B
WIP  
Behdad Esfahbod 已提交
1492 1493

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


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

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

1507
template <typename context_t>
1508
/*static*/ inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
1509
{
1510
  const SubstLookup &l = _get_gsub_relaxed (c->face).get_lookup (lookup_index);
1511
  return l.dispatch (c);
1512 1513
}

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

1527
struct GSUB_accelerator_t : GSUB::accelerator_t {};
1528

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

B
Behdad Esfahbod 已提交
1531

1532
#endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */