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

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

32
#include "hb-ot-layout-gsubgpos.hh"
B
Behdad Esfahbod 已提交
33

B
Behdad Esfahbod 已提交
34

35 36
namespace OT {

37

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

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

48
  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
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
62
  {
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
  const Coverage &get_coverage () const { return this+coverage; }
75

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

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

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

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

97
  bool serialize (hb_serialize_context_t *c,
98
		  hb_supplier_t<GlyphID> &glyphs,
99 100
		  unsigned int num_glyphs,
		  int delta)
101
  {
B
Behdad Esfahbod 已提交
102
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
103 104
    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 已提交
105
    deltaGlyphID.set (delta); /* TODO(serialize) overflow? */
B
Behdad Esfahbod 已提交
106
    return_trace (true);
107 108
  }

109
  bool subset (hb_subset_context_t *c) const
110 111
  {
    TRACE_SUBSET (this);
B
Behdad Esfahbod 已提交
112
    const hb_set_t &glyphset = *c->plan->glyphset;
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
    {
B
Behdad Esfahbod 已提交
119
      if (!glyphset.has (iter.get_glyph ())) continue;
120 121
      from.push ()->set (glyph_map[iter.get_glyph ()]);
      to.push ()->set (glyph_map[(iter.get_glyph () + delta) & 0xFFFF]);
122
    }
123
    c->serializer->propagate_error (from, to);
124

125 126
    hb_supplier_t<GlyphID> from_supplier (from);
    hb_supplier_t<GlyphID> to_supplier (to);
127 128 129 130 131
    SingleSubst_serialize (c->serializer,
			   from_supplier,
			   to_supplier,
			   from.len);
    return_trace (from.len);
132 133
  }

134
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
135
  {
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
  bool intersects (const hb_set_t *glyphs) const
154 155
  { return (this+coverage).intersects (glyphs); }

156
  void closure (hb_closure_context_t *c) const
157
  {
B
Behdad Esfahbod 已提交
158
    TRACE_CLOSURE (this);
159
    unsigned int count = substitute.len;
160
    for (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
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
170
  {
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 (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
  const Coverage &get_coverage () const { return this+coverage; }
183

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

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

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

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

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

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

215
  bool subset (hb_subset_context_t *c) const
216 217
  {
    TRACE_SUBSET (this);
B
Behdad Esfahbod 已提交
218
    const hb_set_t &glyphset = *c->plan->glyphset;
219
    const hb_map_t &glyph_map = *c->plan->glyph_map;
220 221
    hb_vector_t<GlyphID> from;
    hb_vector_t<GlyphID> to;
222
    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
223
    {
B
Behdad Esfahbod 已提交
224
      if (!glyphset.has (iter.get_glyph ())) continue;
225 226
      from.push ()->set (glyph_map[iter.get_glyph ()]);
      to.push ()->set (glyph_map[substitute[iter.get_coverage ()]]);
227
    }
228
    c->serializer->propagate_error (from, to);
229

230 231
    hb_supplier_t<GlyphID> from_supplier (from);
    hb_supplier_t<GlyphID> to_supplier (to);
232 233 234 235 236
    SingleSubst_serialize (c->serializer,
			   from_supplier,
			   to_supplier,
			   from.len);
    return_trace (from.len);
237 238
  }

239
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
240
  {
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
{
259
  bool serialize (hb_serialize_context_t *c,
260 261
		  hb_supplier_t<GlyphID> &glyphs,
		  hb_supplier_t<GlyphID> &substitutes,
262
		  unsigned int num_glyphs)
B
Behdad Esfahbod 已提交
263
  {
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
      delta = substitutes[0] - glyphs[0];
      for (unsigned int i = 1; i < num_glyphs; i++)
B
Minor  
Behdad Esfahbod 已提交
273
	if (delta != (int) (substitutes[i] - glyphs[i])) {
B
Behdad Esfahbod 已提交
274 275 276 277 278 279
	  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
  template <typename context_t>
287
  typename context_t::return_t dispatch (context_t *c) const
B
Behdad Esfahbod 已提交
288
  {
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
static inline void
SingleSubst_serialize (hb_serialize_context_t *c,
308 309
		       hb_supplier_t<GlyphID> &glyphs,
		       hb_supplier_t<GlyphID> &substitutes,
310 311 312 313 314 315 316
		       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
{
320
  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
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
329
  {
B
Behdad Esfahbod 已提交
330
    TRACE_COLLECT_GLYPHS (this);
331
    c->output->add_array (substitute.arrayZ, substitute.len);
332 333
  }

334
  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
  bool serialize (hb_serialize_context_t *c,
367
		  hb_supplier_t<GlyphID> &glyphs,
368
		  unsigned int num_glyphs)
369
  {
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
  }

376
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
377
  {
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
  bool intersects (const hb_set_t *glyphs) const
392 393
  { return (this+coverage).intersects (glyphs); }

394
  void closure (hb_closure_context_t *c) const
395
  {
B
Behdad Esfahbod 已提交
396
    TRACE_CLOSURE (this);
397
    unsigned int count = sequence.len;
398
    for (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
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
408
  {
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
  const Coverage &get_coverage () const { return this+coverage; }
417

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

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

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

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

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

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

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

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

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

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

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

513 514
struct AlternateSet
{
515
  void closure (hb_closure_context_t *c) const
516 517 518 519 520 521 522
  {
    TRACE_CLOSURE (this);
    unsigned int count = alternates.len;
    for (unsigned int i = 0; i < count; i++)
      c->out->add (alternates[i]);
  }

523
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
524 525 526 527 528
  {
    TRACE_COLLECT_GLYPHS (this);
    c->output->add_array (alternates.arrayZ, alternates.len);
  }

529
  bool apply (hb_ot_apply_context_t *c) const
530 531 532 533 534 535
  {
    TRACE_APPLY (this);
    unsigned int count = alternates.len;

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

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

539 540 541
    /* 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);
542

543 544
    /* 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 已提交
545
      alt_index = c->random_number () % count + 1;
B
Behdad Esfahbod 已提交
546

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

549 550
    c->replace_glyph (alternates[alt_index - 1]);

551 552 553
    return_trace (true);
  }

554
  bool serialize (hb_serialize_context_t *c,
555
		  hb_supplier_t<GlyphID> &glyphs,
556
		  unsigned int num_glyphs)
557 558 559 560 561 562 563
  {
    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);
  }

564
  bool sanitize (hb_sanitize_context_t *c) const
565 566 567 568 569 570 571 572
  {
    TRACE_SANITIZE (this);
    return_trace (alternates.sanitize (c));
  }

  protected:
  ArrayOf<GlyphID>
		alternates;		/* Array of alternate GlyphIDs--in
B
Behdad Esfahbod 已提交
573
					 * arbitrary order */
574 575 576
  public:
  DEFINE_SIZE_ARRAY (2, alternates);
};
B
Behdad Esfahbod 已提交
577

B
Behdad Esfahbod 已提交
578 579
struct AlternateSubstFormat1
{
580
  bool intersects (const hb_set_t *glyphs) const
581 582
  { return (this+coverage).intersects (glyphs); }

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

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

609
  const Coverage &get_coverage () const { return this+coverage; }
610

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

617
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
618
  {
B
Behdad Esfahbod 已提交
619
    TRACE_APPLY (this);
620

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

624
    return_trace ((this+alternateSet[index]).apply (c));
625
  }
B
Behdad Esfahbod 已提交
626

627
  bool serialize (hb_serialize_context_t *c,
628 629
		  hb_supplier_t<GlyphID> &glyphs,
		  hb_supplier_t<unsigned int> &alternate_len_list,
630
		  unsigned int num_glyphs,
631
		  hb_supplier_t<GlyphID> &alternate_glyphs_list)
632
  {
B
Behdad Esfahbod 已提交
633
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
634 635
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    if (unlikely (!alternateSet.serialize (c, num_glyphs))) return_trace (false);
636 637 638
    for (unsigned int i = 0; i < num_glyphs; i++)
      if (unlikely (!alternateSet[i].serialize (c, this).serialize (c,
								    alternate_glyphs_list,
B
Behdad Esfahbod 已提交
639
								    alternate_len_list[i]))) return_trace (false);
640
    alternate_len_list += num_glyphs;
B
Behdad Esfahbod 已提交
641 642
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
    return_trace (true);
643 644
  }

645
  bool subset (hb_subset_context_t *c) const
646 647 648 649 650 651
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

652
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
653
  {
B
Behdad Esfahbod 已提交
654
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
655
    return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
656 657
  }

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

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

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

699
  protected:
700
  union {
B
Behdad Esfahbod 已提交
701
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
702
  AlternateSubstFormat1	format1;
703 704 705
  } u;
};

706

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

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

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

735
  bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
736
  {
B
Behdad Esfahbod 已提交
737
    TRACE_WOULD_APPLY (this);
738
    if (c->len != component.lenP1)
B
Behdad Esfahbod 已提交
739
      return_trace (false);
740 741 742

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

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

748
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
749
  {
B
Behdad Esfahbod 已提交
750
    TRACE_APPLY (this);
751
    unsigned int count = component.lenP1;
B
Behdad Esfahbod 已提交
752

B
Behdad Esfahbod 已提交
753
    if (unlikely (!count)) return_trace (false);
B
Behdad Esfahbod 已提交
754

755 756 757 758 759
    /* 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 已提交
760
      return_trace (true);
761 762
    }

B
Behdad Esfahbod 已提交
763
    unsigned int total_component_count = 0;
764

765
    unsigned int match_length = 0;
766
    unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
767

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

777 778
    ligate_input (c,
		  count,
779 780
		  match_positions,
		  match_length,
781
		  ligGlyph,
782
		  total_component_count);
783

B
Behdad Esfahbod 已提交
784
    return_trace (true);
785
  }
786

787 788
  bool serialize (hb_serialize_context_t *c,
		  GlyphID ligature,
789
		  hb_supplier_t<GlyphID> &components, /* Starting from second */
790
		  unsigned int num_components /* Including first component */)
791
  {
B
Behdad Esfahbod 已提交
792
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
793
    if (unlikely (!c->extend_min (*this))) return_trace (false);
794
    ligGlyph = ligature;
B
Behdad Esfahbod 已提交
795 796
    if (unlikely (!component.serialize (c, components, num_components))) return_trace (false);
    return_trace (true);
797 798
  }

B
Behdad Esfahbod 已提交
799
  public:
800
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
801
  {
B
Behdad Esfahbod 已提交
802
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
803
    return_trace (ligGlyph.sanitize (c) && component.sanitize (c));
B
Behdad Esfahbod 已提交
804 805
  }

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

B
Behdad Esfahbod 已提交
816 817
struct LigatureSet
{
818
  bool intersects (const hb_set_t *glyphs) const
819 820 821 822 823 824 825 826
  {
    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;
  }

827
  void closure (hb_closure_context_t *c) const
828
  {
B
Behdad Esfahbod 已提交
829
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
830 831
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
B
Behdad Esfahbod 已提交
832
      (this+ligature[i]).closure (c);
833 834
  }

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

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

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

B
Behdad Esfahbod 已提交
866
    return_trace (false);
867
  }
B
Behdad Esfahbod 已提交
868

869
  bool serialize (hb_serialize_context_t *c,
870 871
		  hb_supplier_t<GlyphID> &ligatures,
		  hb_supplier_t<unsigned int> &component_count_list,
872
		  unsigned int num_ligatures,
873
		  hb_supplier_t<GlyphID> &component_list /* Starting from second for each ligature */)
874
  {
B
Behdad Esfahbod 已提交
875
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
876 877
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    if (unlikely (!ligature.serialize (c, num_ligatures))) return_trace (false);
878 879 880 881
    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 已提交
882
								component_count_list[i]))) return_trace (false);
883 884
    ligatures += num_ligatures;
    component_count_list += num_ligatures;
B
Behdad Esfahbod 已提交
885
    return_trace (true);
886 887
  }

888
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
889
  {
B
Behdad Esfahbod 已提交
890
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
891
    return_trace (ligature.sanitize (c, this));
B
Behdad Esfahbod 已提交
892 893
  }

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

B
Behdad Esfahbod 已提交
902 903
struct LigatureSubstFormat1
{
904
  bool intersects (const hb_set_t *glyphs) const
905 906
  {
    unsigned int count = ligatureSet.len;
907
    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
908 909 910 911 912 913 914 915 916 917
    {
      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;
  }

918
  void closure (hb_closure_context_t *c) const
919
  {
B
Behdad Esfahbod 已提交
920
    TRACE_CLOSURE (this);
921
    unsigned int count = ligatureSet.len;
922
    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
923 924
    {
      if (unlikely (iter.get_coverage () >= count))
925
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
B
Behdad Esfahbod 已提交
926
      if (c->glyphs->has (iter.get_glyph ()))
B
Behdad Esfahbod 已提交
927
	(this+ligatureSet[iter.get_coverage ()]).closure (c);
B
Behdad Esfahbod 已提交
928
    }
929 930
  }

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

944
  const Coverage &get_coverage () const { return this+coverage; }
945

946
  bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
947
  {
B
Behdad Esfahbod 已提交
948
    TRACE_WOULD_APPLY (this);
949
    unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
B
Behdad Esfahbod 已提交
950
    if (likely (index == NOT_COVERED)) return_trace (false);
951 952

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

956
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
957
  {
B
Behdad Esfahbod 已提交
958
    TRACE_APPLY (this);
959

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

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

967
  bool serialize (hb_serialize_context_t *c,
968 969
		  hb_supplier_t<GlyphID> &first_glyphs,
		  hb_supplier_t<unsigned int> &ligature_per_first_glyph_count_list,
970
		  unsigned int num_first_glyphs,
971 972 973
		  hb_supplier_t<GlyphID> &ligatures_list,
		  hb_supplier_t<unsigned int> &component_count_list,
		  hb_supplier_t<GlyphID> &component_list /* Starting from second for each ligature */)
974
  {
B
Behdad Esfahbod 已提交
975
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
976 977
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    if (unlikely (!ligatureSet.serialize (c, num_first_glyphs))) return_trace (false);
978 979 980 981 982
    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 已提交
983
								   component_list))) return_trace (false);
984
    ligature_per_first_glyph_count_list += num_first_glyphs;
B
Behdad Esfahbod 已提交
985 986
    if (unlikely (!coverage.serialize (c, this).serialize (c, first_glyphs, num_first_glyphs))) return_trace (false);
    return_trace (true);
987 988
  }

989
  bool subset (hb_subset_context_t *c) const
990 991 992 993 994 995
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

996
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
997
  {
B
Behdad Esfahbod 已提交
998
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
999
    return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
1000 1001
  }

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

B
Behdad Esfahbod 已提交
1014 1015
struct LigatureSubst
{
1016
  bool serialize (hb_serialize_context_t *c,
1017 1018
		  hb_supplier_t<GlyphID> &first_glyphs,
		  hb_supplier_t<unsigned int> &ligature_per_first_glyph_count_list,
1019
		  unsigned int num_first_glyphs,
1020 1021 1022
		  hb_supplier_t<GlyphID> &ligatures_list,
		  hb_supplier_t<unsigned int> &component_count_list,
		  hb_supplier_t<GlyphID> &component_list /* Starting from second for each ligature */)
1023
  {
B
Behdad Esfahbod 已提交
1024
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1025
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
1026 1027 1028
    unsigned int format = 1;
    u.format.set (format);
    switch (u.format) {
B
Behdad Esfahbod 已提交
1029 1030 1031 1032 1033 1034 1035 1036
    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);
1037 1038 1039
    }
  }

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

1051
  protected:
1052
  union {
B
Behdad Esfahbod 已提交
1053
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1054
  LigatureSubstFormat1	format1;
1055 1056 1057
  } u;
};

B
Behdad Esfahbod 已提交
1058

B
Minor  
Behdad Esfahbod 已提交
1059
struct ContextSubst : Context {};
B
Behdad Esfahbod 已提交
1060

B
Minor  
Behdad Esfahbod 已提交
1061
struct ChainContextSubst : ChainContext {};
1062

B
Behdad Esfahbod 已提交
1063
struct ExtensionSubst : Extension<ExtensionSubst>
B
Behdad Esfahbod 已提交
1064
{
B
Behdad Esfahbod 已提交
1065
  typedef struct SubstLookupSubTable SubTable;
B
Behdad Esfahbod 已提交
1066

1067
  bool is_reverse () const;
1068 1069 1070
};


B
Behdad Esfahbod 已提交
1071 1072
struct ReverseChainSingleSubstFormat1
{
1073
  bool intersects (const hb_set_t *glyphs) const
1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094
  {
    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;
  }

1095
  void closure (hb_closure_context_t *c) const
1096
  {
B
Behdad Esfahbod 已提交
1097
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
1098 1099 1100 1101 1102 1103 1104
    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 已提交
1105
        return;
B
Behdad Esfahbod 已提交
1106 1107 1108 1109

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

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

1123
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
1124
  {
B
Behdad Esfahbod 已提交
1125
    TRACE_COLLECT_GLYPHS (this);
1126
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
1127 1128 1129 1130 1131

    unsigned int count;

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

1134
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1135 1136
    count = lookahead.len;
    for (unsigned int i = 0; i < count; i++)
1137
      if (unlikely (!(this+lookahead[i]).add_coverage (c->after))) return;
1138 1139 1140

    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
    count = substitute.len;
1141
    c->output->add_array (substitute.arrayZ, substitute.len);
1142 1143
  }

1144
  const Coverage &get_coverage () const { return this+coverage; }
1145

1146
  bool would_apply (hb_would_apply_context_t *c) const
1147
  {
B
Behdad Esfahbod 已提交
1148
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
1149
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
1150 1151
  }

1152
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1153
  {
B
Behdad Esfahbod 已提交
1154
    TRACE_APPLY (this);
1155
    if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
B
Behdad Esfahbod 已提交
1156
      return_trace (false); /* No chaining to this type */
1157

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

1161 1162
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
1163

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

B
Behdad Esfahbod 已提交
1182
    return_trace (false);
1183
  }
B
Behdad Esfahbod 已提交
1184

1185
  bool subset (hb_subset_context_t *c) const
1186 1187 1188 1189 1190 1191
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

1192
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
1193
  {
B
Behdad Esfahbod 已提交
1194
    TRACE_SANITIZE (this);
1195
    if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
B
Behdad Esfahbod 已提交
1196
      return_trace (false);
B
Behdad Esfahbod 已提交
1197
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
B
Behdad Esfahbod 已提交
1198
    if (!lookahead.sanitize (c, this))
B
Behdad Esfahbod 已提交
1199
      return_trace (false);
B
Behdad Esfahbod 已提交
1200
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
B
Behdad Esfahbod 已提交
1201
    return_trace (substitute.sanitize (c));
B
Behdad Esfahbod 已提交
1202 1203
  }

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

B
Behdad Esfahbod 已提交
1224 1225
struct ReverseChainSingleSubst
{
1226
  template <typename context_t>
1227
  typename context_t::return_t dispatch (context_t *c) const
1228
  {
1229
    TRACE_DISPATCH (this, u.format);
1230
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1231
    switch (u.format) {
B
Behdad Esfahbod 已提交
1232 1233
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
1234 1235 1236
    }
  }

1237
  protected:
1238
  union {
B
Behdad Esfahbod 已提交
1239
  HBUINT16				format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1240
  ReverseChainSingleSubstFormat1	format1;
1241 1242 1243 1244 1245
  } u;
};



B
Behdad Esfahbod 已提交
1246 1247 1248 1249
/*
 * SubstLookup
 */

B
Behdad Esfahbod 已提交
1250 1251
struct SubstLookupSubTable
{
B
Behdad Esfahbod 已提交
1252
  friend struct Lookup;
B
Behdad Esfahbod 已提交
1253 1254
  friend struct SubstLookup;

B
Behdad Esfahbod 已提交
1255
  enum Type {
1256 1257 1258 1259 1260 1261 1262
    Single		= 1,
    Multiple		= 2,
    Alternate		= 3,
    Ligature		= 4,
    Context		= 5,
    ChainContext	= 6,
    Extension		= 7,
1263
    ReverseChainSingle	= 8
1264 1265
  };

1266
  template <typename context_t>
1267
  typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
1268
  {
1269
    TRACE_DISPATCH (this, lookup_type);
1270
    switch (lookup_type) {
B
Behdad Esfahbod 已提交
1271 1272 1273 1274 1275 1276 1277 1278 1279
    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 ());
1280 1281 1282
    }
  }

1283
  protected:
B
Behdad Esfahbod 已提交
1284
  union {
B
Behdad Esfahbod 已提交
1285 1286 1287 1288
  SingleSubst			single;
  MultipleSubst			multiple;
  AlternateSubst		alternate;
  LigatureSubst			ligature;
1289
  ContextSubst			context;
B
Behdad Esfahbod 已提交
1290 1291 1292
  ChainContextSubst		chainContext;
  ExtensionSubst		extension;
  ReverseChainSingleSubst	reverseChainContextSingle;
B
Behdad Esfahbod 已提交
1293
  } u;
B
Behdad Esfahbod 已提交
1294
  public:
B
Behdad Esfahbod 已提交
1295
  DEFINE_SIZE_MIN (0);
B
Behdad Esfahbod 已提交
1296 1297
};

1298

B
Behdad Esfahbod 已提交
1299 1300
struct SubstLookup : Lookup
{
B
Behdad Esfahbod 已提交
1301 1302
  typedef SubstLookupSubTable SubTable;

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

1306
  static bool lookup_type_is_reverse (unsigned int lookup_type)
B
Behdad Esfahbod 已提交
1307
  { return lookup_type == SubTable::ReverseChainSingle; }
B
Behdad Esfahbod 已提交
1308

1309
  bool is_reverse () const
B
Behdad Esfahbod 已提交
1310
  {
B
Behdad Esfahbod 已提交
1311
    unsigned int type = get_type ();
B
Behdad Esfahbod 已提交
1312
    if (unlikely (type == SubTable::Extension))
1313
      return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
B
Behdad Esfahbod 已提交
1314
    return lookup_type_is_reverse (type);
B
Behdad Esfahbod 已提交
1315
  }
1316

1317
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1318 1319
  {
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
1320
    return_trace (dispatch (c));
B
Behdad Esfahbod 已提交
1321 1322
  }

1323
  bool intersects (const hb_set_t *glyphs) const
1324 1325 1326 1327 1328
  {
    hb_intersects_context_t c (glyphs);
    return dispatch (&c);
  }

1329
  hb_closure_context_t::return_t closure (hb_closure_context_t *c, unsigned int this_index) const
1330
  {
B
Behdad Esfahbod 已提交
1331
    TRACE_CLOSURE (this);
1332
    if (!c->should_visit_lookup (this_index))
1333 1334 1335
      return_trace (HB_VOID);

    c->set_recurse_func (dispatch_closure_recurse_func);
1336 1337 1338 1339 1340 1341

    hb_closure_context_t::return_t ret = dispatch (c);

    c->flush ();

    return_trace (ret);
B
Behdad Esfahbod 已提交
1342 1343
  }

1344
  hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
B
Behdad Esfahbod 已提交
1345 1346
  {
    TRACE_COLLECT_GLYPHS (this);
1347
    c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
B
Behdad Esfahbod 已提交
1348
    return_trace (dispatch (c));
1349 1350
  }

B
Behdad Esfahbod 已提交
1351
  template <typename set_t>
1352
  void add_coverage (set_t *glyphs) const
B
Behdad Esfahbod 已提交
1353
  {
1354 1355
    hb_add_coverage_context_t<set_t> c (glyphs);
    dispatch (&c);
B
Behdad Esfahbod 已提交
1356 1357
  }

1358 1359
  bool would_apply (hb_would_apply_context_t *c,
		    const hb_ot_layout_lookup_accelerator_t *accel) const
B
Behdad Esfahbod 已提交
1360
  {
B
Behdad Esfahbod 已提交
1361
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
1362 1363 1364
    if (unlikely (!c->len))  return_trace (false);
    if (!accel->may_have (c->glyphs[0]))  return_trace (false);
      return_trace (dispatch (c));
B
Behdad Esfahbod 已提交
1365 1366
  }

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

1369
  SubTable& serialize_subtable (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
1370 1371
				       unsigned int i)
  { return get_subtables<SubTable> ()[i].serialize (c, this); }
1372

1373 1374
  bool serialize_single (hb_serialize_context_t *c,
			 uint32_t lookup_props,
1375 1376
		         hb_supplier_t<GlyphID> &glyphs,
		         hb_supplier_t<GlyphID> &substitutes,
1377
		         unsigned int num_glyphs)
1378
  {
B
Behdad Esfahbod 已提交
1379
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1380
    if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1381
    return_trace (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes, num_glyphs));
1382 1383
  }

1384 1385
  bool serialize_multiple (hb_serialize_context_t *c,
			   uint32_t lookup_props,
1386 1387
			   hb_supplier_t<GlyphID> &glyphs,
			   hb_supplier_t<unsigned int> &substitute_len_list,
1388
			   unsigned int num_glyphs,
1389
			   hb_supplier_t<GlyphID> &substitute_glyphs_list)
1390
  {
B
Behdad Esfahbod 已提交
1391
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1392
    if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1393 1394 1395 1396 1397
    return_trace (serialize_subtable (c, 0).u.multiple.serialize (c,
								  glyphs,
								  substitute_len_list,
								  num_glyphs,
								  substitute_glyphs_list));
1398 1399
  }

1400 1401
  bool serialize_alternate (hb_serialize_context_t *c,
			    uint32_t lookup_props,
1402 1403
			    hb_supplier_t<GlyphID> &glyphs,
			    hb_supplier_t<unsigned int> &alternate_len_list,
1404
			    unsigned int num_glyphs,
1405
			    hb_supplier_t<GlyphID> &alternate_glyphs_list)
1406
  {
B
Behdad Esfahbod 已提交
1407
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1408
    if (unlikely (!Lookup::serialize (c, SubTable::Alternate, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1409 1410 1411 1412 1413
    return_trace (serialize_subtable (c, 0).u.alternate.serialize (c,
								   glyphs,
								   alternate_len_list,
								   num_glyphs,
								   alternate_glyphs_list));
1414 1415
  }

1416 1417
  bool serialize_ligature (hb_serialize_context_t *c,
			   uint32_t lookup_props,
1418 1419
			   hb_supplier_t<GlyphID> &first_glyphs,
			   hb_supplier_t<unsigned int> &ligature_per_first_glyph_count_list,
1420
			   unsigned int num_first_glyphs,
1421 1422 1423
			   hb_supplier_t<GlyphID> &ligatures_list,
			   hb_supplier_t<unsigned int> &component_count_list,
			   hb_supplier_t<GlyphID> &component_list /* Starting from second for each ligature */)
1424
  {
B
Behdad Esfahbod 已提交
1425
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1426
    if (unlikely (!Lookup::serialize (c, SubTable::Ligature, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1427 1428 1429 1430 1431 1432 1433
    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));
1434 1435
  }

B
Behdad Esfahbod 已提交
1436
  template <typename context_t>
1437
  static typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
B
Behdad Esfahbod 已提交
1438

1439
  static hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned int lookup_index)
1440
  {
1441
    if (!c->should_visit_lookup (lookup_index))
1442
      return HB_VOID;
1443 1444 1445

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

1446 1447 1448 1449
    /* 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 ();
1450 1451

    return ret;
1452 1453
  }

B
Behdad Esfahbod 已提交
1454
  template <typename context_t>
1455
  typename context_t::return_t dispatch (context_t *c) const
B
Behdad Esfahbod 已提交
1456 1457
  { return Lookup::dispatch<SubTable> (c); }

1458
  bool subset (hb_subset_context_t *c) const
1459
  { return Lookup::subset<SubTable> (c); }
B
Behdad Esfahbod 已提交
1460

1461
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
1462
  { return Lookup::sanitize<SubTable> (c); }
B
Behdad Esfahbod 已提交
1463 1464
};

B
Minor  
Behdad Esfahbod 已提交
1465
/*
1466 1467
 * GSUB -- Glyph Substitution
 * https://docs.microsoft.com/en-us/typography/opentype/spec/gsub
B
Minor  
Behdad Esfahbod 已提交
1468 1469
 */

B
Behdad Esfahbod 已提交
1470 1471
struct GSUB : GSUBGPOS
{
1472
  enum { tableTag = HB_OT_TAG_GSUB };
B
Minor  
Behdad Esfahbod 已提交
1473

1474
  const SubstLookup& get_lookup (unsigned int i) const
1475
  { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
B
Behdad Esfahbod 已提交
1476

1477
  bool subset (hb_subset_context_t *c) const
1478
  { return GSUBGPOS::subset<SubstLookup> (c); }
1479

1480
  bool sanitize (hb_sanitize_context_t *c) const
1481
  { return GSUBGPOS::sanitize<SubstLookup> (c); }
B
WIP  
Behdad Esfahbod 已提交
1482

1483 1484 1485
  HB_INTERNAL bool is_blacklisted (hb_blob_t *blob,
				   hb_face_t *face) const;

B
WIP  
Behdad Esfahbod 已提交
1486
  typedef GSUBGPOS::accelerator_t<GSUB> accelerator_t;
B
Minor  
Behdad Esfahbod 已提交
1487
};
1488 1489


B
Behdad Esfahbod 已提交
1490 1491 1492
struct GSUB_accelerator_t : GSUB::accelerator_t {};


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

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

1503
template <typename context_t>
1504
/*static*/ inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
1505
{
B
Behdad Esfahbod 已提交
1506
  const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index);
1507
  return l.dispatch (c);
1508 1509
}

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

B
Behdad Esfahbod 已提交
1523
} /* namespace OT */
1524

B
Behdad Esfahbod 已提交
1525

1526
#endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */