hb-ot-layout-gsub-table.hh 41.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,
B
Behdad Esfahbod 已提交
39
					  hb_sorted_array_t<const GlyphID> glyphs,
B
Behdad Esfahbod 已提交
40
					  hb_array_t<const GlyphID> substitutes);
41

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

47
  void closure (hb_closure_context_t *c) const
48
  {
49 50 51 52 53
    + hb_iter (this+coverage)
    | hb_filter (*c->glyphs)
    | hb_map ([&] (hb_codepoint_t g) -> hb_codepoint_t { return (g + deltaGlyphID) & 0xFFFFu; })
    | hb_sink (c->output)
    ;
54 55
  }

56
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
57
  {
58
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
B
Behdad Esfahbod 已提交
59

60 61 62 63
    + hb_iter (this+coverage)
    | hb_map ([&] (hb_codepoint_t g) -> hb_codepoint_t { return (g + deltaGlyphID) & 0xFFFFu; })
    | hb_sink (c->output)
    ;
64 65
  }

66
  const Coverage &get_coverage () const { return this+coverage; }
67

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

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

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

B
Behdad Esfahbod 已提交
86
    return_trace (true);
87
  }
B
Behdad Esfahbod 已提交
88

89
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
90
		  hb_sorted_array_t<const GlyphID> glyphs,
91
		  int delta)
92
  {
B
Behdad Esfahbod 已提交
93
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
94
    if (unlikely (!c->extend_min (*this))) return_trace (false);
B
Behdad Esfahbod 已提交
95
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs))) return_trace (false);
96
    deltaGlyphID = delta; /* TODO(serialize) overflow? */
B
Behdad Esfahbod 已提交
97
    return_trace (true);
98 99
  }

100
  bool subset (hb_subset_context_t *c) const
101 102
  {
    TRACE_SUBSET (this);
103
    const hb_set_t &glyphset = *c->plan->glyphset ();
104
    const hb_map_t &glyph_map = *c->plan->glyph_map;
105

B
Behdad Esfahbod 已提交
106
    hb_sorted_vector_t<GlyphID> from;
107
    hb_vector_t<GlyphID> to;
108
    hb_codepoint_t delta = deltaGlyphID;
109 110 111 112 113 114 115 116

    + hb_iter (this+coverage)
    | hb_filter (glyphset)
    | hb_map ([&] (hb_codepoint_t g) -> hb_pair_t<hb_codepoint_t, hb_codepoint_t>
	      { return hb_pair<hb_codepoint_t, hb_codepoint_t> (glyph_map[g],
								glyph_map[(g + delta) & 0xFFFF]); })
    | hb_unzip (from, to);

117
    c->serializer->propagate_error (from, to);
B
Behdad Esfahbod 已提交
118
    SingleSubst_serialize (c->serializer, from, to);
119
    return_trace (from.length);
120 121
  }

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

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

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

144
  void closure (hb_closure_context_t *c) const
145
  {
B
Behdad Esfahbod 已提交
146 147 148
    + hb_zip (this+coverage, substitute)
    | hb_filter (*c->glyphs, hb_first)
    | hb_map (hb_second)
149
    | hb_sink (c->output)
150
    ;
151 152
  }

153
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
154
  {
155
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
B
Behdad Esfahbod 已提交
156 157
    + hb_zip (this+coverage, substitute)
    | hb_map (hb_second)
158
    | hb_sink (c->output)
159
    ;
160 161
  }

162
  const Coverage &get_coverage () const { return this+coverage; }
163

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

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

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

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

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

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

194
  bool subset (hb_subset_context_t *c) const
195 196
  {
    TRACE_SUBSET (this);
197
    const hb_set_t &glyphset = *c->plan->glyphset ();
198
    const hb_map_t &glyph_map = *c->plan->glyph_map;
199

B
Behdad Esfahbod 已提交
200
    hb_sorted_vector_t<GlyphID> from;
201
    hb_vector_t<GlyphID> to;
202 203 204 205 206 207 208

    + hb_zip (this+coverage, substitute)
    | hb_filter (glyphset, hb_first)
    | hb_map ([&] (hb_pair_t<hb_codepoint_t, const GlyphID &> p) -> hb_pair_t<hb_codepoint_t, hb_codepoint_t>
	      { return hb_pair (glyph_map[p.first], glyph_map[p.second]); })
    | hb_unzip (from, to);

209
    c->serializer->propagate_error (from, to);
B
Behdad Esfahbod 已提交
210
    SingleSubst_serialize (c->serializer, from, to);
211
    return_trace (from.length);
212 213
  }

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

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

B
Behdad Esfahbod 已提交
232 233
struct SingleSubst
{
234
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
235
		  hb_sorted_array_t<const GlyphID> glyphs,
B
Behdad Esfahbod 已提交
236
		  hb_array_t<const GlyphID> substitutes)
B
Behdad Esfahbod 已提交
237
  {
B
Behdad Esfahbod 已提交
238
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
239
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
B
Behdad Esfahbod 已提交
240
    unsigned int format = 2;
B
Behdad Esfahbod 已提交
241
    int delta = 0;
242
    if (glyphs.length)
B
Behdad Esfahbod 已提交
243
    {
B
Behdad Esfahbod 已提交
244
      format = 1;
B
Minor  
Behdad Esfahbod 已提交
245
      /* TODO(serialize) check for wrap-around */
B
Behdad Esfahbod 已提交
246
      delta = substitutes[0] - glyphs[0];
247
      for (unsigned int i = 1; i < glyphs.length; i++)
B
Minor  
Behdad Esfahbod 已提交
248
	if (delta != (int) (substitutes[i] - glyphs[i])) {
B
Behdad Esfahbod 已提交
249 250 251 252
	  format = 2;
	  break;
	}
    }
253
    u.format = format;
B
Behdad Esfahbod 已提交
254
    switch (u.format) {
B
Behdad Esfahbod 已提交
255 256
    case 1: return_trace (u.format1.serialize (c, glyphs, delta));
    case 2: return_trace (u.format2.serialize (c, glyphs, substitutes));
B
Behdad Esfahbod 已提交
257
    default:return_trace (false);
B
Behdad Esfahbod 已提交
258 259 260
    }
  }

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

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

281 282
static inline void
SingleSubst_serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
283
		       hb_sorted_array_t<const GlyphID> glyphs,
B
Behdad Esfahbod 已提交
284 285
		       hb_array_t<const GlyphID> substitutes)
{ c->start_embed<SingleSubst> ()->serialize (c, glyphs, substitutes); }
B
Behdad Esfahbod 已提交
286

B
Behdad Esfahbod 已提交
287 288
struct Sequence
{
289
  void closure (hb_closure_context_t *c) const
290
  {
B
Behdad Esfahbod 已提交
291 292
    unsigned int count = substitute.len;
    for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
293
      c->output->add (substitute[i]);
294 295
  }

296
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
B
Behdad Esfahbod 已提交
297
  { c->output->add_array (substitute.arrayZ, substitute.len); }
298

299
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
300
  {
B
Behdad Esfahbod 已提交
301
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
302
    unsigned int count = substitute.len;
303

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

    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);
324
      c->output_glyph_for_component (substitute.arrayZ[i], klass);
325
    }
B
Behdad Esfahbod 已提交
326
    c->buffer->skip_glyph ();
B
Behdad Esfahbod 已提交
327

B
Behdad Esfahbod 已提交
328
    return_trace (true);
B
Behdad Esfahbod 已提交
329 330
  }

331
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
332
		  hb_array_t<const GlyphID> subst)
333
  {
B
Behdad Esfahbod 已提交
334
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
335
    return_trace (substitute.serialize (c, subst));
336 337
  }

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

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

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

356
  void closure (hb_closure_context_t *c) const
357
  {
358 359 360
    + hb_zip (this+coverage, sequence)
    | hb_filter (*c->glyphs, hb_first)
    | hb_map (hb_second)
B
Behdad Esfahbod 已提交
361
    | hb_apply ([&] (const OffsetTo<Sequence> &_) { (this+_).closure (c); })
362
    ;
363 364
  }

365
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
366
  {
367
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
368 369
    + hb_zip (this+coverage, sequence)
    | hb_map (hb_second)
B
Behdad Esfahbod 已提交
370
    | hb_apply ([&] (const OffsetTo<Sequence> &_) { (this+_).collect_glyphs (c); })
371
    ;
372 373
  }

374
  const Coverage &get_coverage () const { return this+coverage; }
375

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

382
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
383
  {
B
Behdad Esfahbod 已提交
384
    TRACE_APPLY (this);
385

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

B
Behdad Esfahbod 已提交
389
    return_trace ((this+sequence[index]).apply (c));
390
  }
B
Behdad Esfahbod 已提交
391

392
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
393
		  hb_sorted_array_t<const GlyphID> glyphs,
B
Behdad Esfahbod 已提交
394 395
		  hb_array_t<const unsigned int> substitute_len_list,
		  hb_array_t<const GlyphID> substitute_glyphs_list)
396
  {
B
Behdad Esfahbod 已提交
397
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
398
    if (unlikely (!c->extend_min (*this))) return_trace (false);
399 400
    if (unlikely (!sequence.serialize (c, glyphs.length))) return_trace (false);
    for (unsigned int i = 0; i < glyphs.length; i++)
B
Behdad Esfahbod 已提交
401 402 403 404 405 406 407 408
    {
      unsigned int substitute_len = substitute_len_list[i];
      if (unlikely (!sequence[i].serialize (c, this)
				.serialize (c, substitute_glyphs_list.sub_array (0, substitute_len))))
	return_trace (false);
      substitute_glyphs_list += substitute_len;
    }
    return_trace (coverage.serialize (c, this).serialize (c, glyphs));
409 410
  }

411
  bool subset (hb_subset_context_t *c) const
412 413 414 415 416 417
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

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

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

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

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

464
  protected:
465
  union {
B
Behdad Esfahbod 已提交
466
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
467
  MultipleSubstFormat1	format1;
468 469 470
  } u;
};

471 472
struct AlternateSet
{
473
  void closure (hb_closure_context_t *c) const
474 475 476
  {
    unsigned int count = alternates.len;
    for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
477
      c->output->add (alternates[i]);
478 479
  }

480
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
B
Behdad Esfahbod 已提交
481
  { c->output->add_array (alternates.arrayZ, alternates.len); }
482

483
  bool apply (hb_ot_apply_context_t *c) const
484 485 486 487 488 489
  {
    TRACE_APPLY (this);
    unsigned int count = alternates.len;

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

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

493 494 495
    /* 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);
496

497 498
    /* 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 已提交
499
      alt_index = c->random_number () % count + 1;
B
Behdad Esfahbod 已提交
500

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

503 504
    c->replace_glyph (alternates[alt_index - 1]);

505 506 507
    return_trace (true);
  }

508
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
509
		  hb_array_t<const GlyphID> alts)
510 511
  {
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
512
    return_trace (alternates.serialize (c, alts));
513 514
  }

515
  bool sanitize (hb_sanitize_context_t *c) const
516 517 518 519 520 521 522 523
  {
    TRACE_SANITIZE (this);
    return_trace (alternates.sanitize (c));
  }

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

B
Behdad Esfahbod 已提交
529 530
struct AlternateSubstFormat1
{
531
  bool intersects (const hb_set_t *glyphs) const
532 533
  { return (this+coverage).intersects (glyphs); }

534
  void closure (hb_closure_context_t *c) const
535
  {
536 537
    + hb_zip (this+coverage, alternateSet)
    | hb_map (hb_second)
B
Behdad Esfahbod 已提交
538
    | hb_apply ([&] (const OffsetTo<AlternateSet> &_) { (this+_).closure (c); })
539
    ;
540 541
  }

542
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
543
  {
544
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
545 546
    + hb_zip (this+coverage, alternateSet)
    | hb_map (hb_second)
B
Behdad Esfahbod 已提交
547
    | hb_apply ([&] (const OffsetTo<AlternateSet> &_) { (this+_).collect_glyphs (c); })
548
    ;
549 550
  }

551
  const Coverage &get_coverage () const { return this+coverage; }
552

553
  bool would_apply (hb_would_apply_context_t *c) const
554
  {
B
Behdad Esfahbod 已提交
555
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
556
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
557 558
  }

559
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
560
  {
B
Behdad Esfahbod 已提交
561
    TRACE_APPLY (this);
562

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

566
    return_trace ((this+alternateSet[index]).apply (c));
567
  }
B
Behdad Esfahbod 已提交
568

569
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
570
		  hb_sorted_array_t<const GlyphID> glyphs,
B
Behdad Esfahbod 已提交
571 572
		  hb_array_t<const unsigned int> alternate_len_list,
		  hb_array_t<const GlyphID> alternate_glyphs_list)
573
  {
B
Behdad Esfahbod 已提交
574
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
575
    if (unlikely (!c->extend_min (*this))) return_trace (false);
576 577
    if (unlikely (!alternateSet.serialize (c, glyphs.length))) return_trace (false);
    for (unsigned int i = 0; i < glyphs.length; i++)
B
Behdad Esfahbod 已提交
578 579 580 581 582 583 584 585
    {
      unsigned int alternate_len = alternate_len_list[i];
      if (unlikely (!alternateSet[i].serialize (c, this)
				    .serialize (c, alternate_glyphs_list.sub_array (0, alternate_len))))
	return_trace (false);
      alternate_glyphs_list += alternate_len;
    }
    return_trace (coverage.serialize (c, this).serialize (c, glyphs));
586 587
  }

588
  bool subset (hb_subset_context_t *c) const
589 590 591 592 593 594
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

595
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
596
  {
B
Behdad Esfahbod 已提交
597
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
598
    return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
599 600
  }

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

B
Behdad Esfahbod 已提交
613 614
struct AlternateSubst
{
615
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
616
		  hb_sorted_array_t<const GlyphID> glyphs,
B
Behdad Esfahbod 已提交
617 618
		  hb_array_t<const unsigned int> alternate_len_list,
		  hb_array_t<const GlyphID> alternate_glyphs_list)
619
  {
B
Behdad Esfahbod 已提交
620
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
621
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
622
    unsigned int format = 1;
623
    u.format = format;
624
    switch (u.format) {
B
Behdad Esfahbod 已提交
625
    case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, alternate_glyphs_list));
B
Behdad Esfahbod 已提交
626
    default:return_trace (false);
627 628 629
    }
  }

B
Behdad Esfahbod 已提交
630
  template <typename context_t>
631
  typename context_t::return_t dispatch (context_t *c) const
B
Behdad Esfahbod 已提交
632
  {
633
    TRACE_DISPATCH (this, u.format);
634
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
635
    switch (u.format) {
B
Behdad Esfahbod 已提交
636 637
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
638 639 640
    }
  }

641
  protected:
642
  union {
B
Behdad Esfahbod 已提交
643
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
644
  AlternateSubstFormat1	format1;
645 646 647
  } u;
};

648

B
Behdad Esfahbod 已提交
649 650
struct Ligature
{
651
  bool intersects (const hb_set_t *glyphs) const
652
  {
653
    unsigned int count = component.lenP1;
654 655 656 657 658 659
    for (unsigned int i = 1; i < count; i++)
      if (!glyphs->has (component[i]))
        return false;
    return true;
  }

660
  void closure (hb_closure_context_t *c) const
661
  {
B
Behdad Esfahbod 已提交
662
    if (!intersects (c->glyphs)) return;
B
Behdad Esfahbod 已提交
663
    c->output->add (ligGlyph);
664 665
  }

666
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
667
  {
668
    c->input->add_array (component.arrayZ, component.lenP1 ? component.lenP1 - 1 : 0);
B
Minor  
Behdad Esfahbod 已提交
669
    c->output->add (ligGlyph);
670 671
  }

672
  bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
673
  {
B
Behdad Esfahbod 已提交
674
    TRACE_WOULD_APPLY (this);
675
    if (c->len != component.lenP1)
B
Behdad Esfahbod 已提交
676
      return_trace (false);
677 678 679

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

B
Behdad Esfahbod 已提交
682
    return_trace (true);
B
Behdad Esfahbod 已提交
683 684
  }

685
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
686
  {
B
Behdad Esfahbod 已提交
687
    TRACE_APPLY (this);
688
    unsigned int count = component.lenP1;
B
Behdad Esfahbod 已提交
689

B
Behdad Esfahbod 已提交
690
    if (unlikely (!count)) return_trace (false);
B
Behdad Esfahbod 已提交
691

692 693 694 695 696
    /* 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 已提交
697
      return_trace (true);
698 699
    }

B
Behdad Esfahbod 已提交
700
    unsigned int total_component_count = 0;
701

702
    unsigned int match_length = 0;
703
    unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
704

705 706 707
    if (likely (!match_input (c, count,
			      &component[1],
			      match_glyph,
B
Behdad Esfahbod 已提交
708
			      nullptr,
709 710
			      &match_length,
			      match_positions,
711
			      &total_component_count)))
B
Behdad Esfahbod 已提交
712
      return_trace (false);
713

714 715
    ligate_input (c,
		  count,
716 717
		  match_positions,
		  match_length,
718
		  ligGlyph,
719
		  total_component_count);
720

B
Behdad Esfahbod 已提交
721
    return_trace (true);
722
  }
723

724 725
  bool serialize (hb_serialize_context_t *c,
		  GlyphID ligature,
B
Behdad Esfahbod 已提交
726
		  hb_array_t<const GlyphID> components /* Starting from second */)
727
  {
B
Behdad Esfahbod 已提交
728
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
729
    if (unlikely (!c->extend_min (*this))) return_trace (false);
730
    ligGlyph = ligature;
B
Behdad Esfahbod 已提交
731
    if (unlikely (!component.serialize (c, components))) return_trace (false);
B
Behdad Esfahbod 已提交
732
    return_trace (true);
733 734
  }

B
Behdad Esfahbod 已提交
735
  public:
736
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
737
  {
B
Behdad Esfahbod 已提交
738
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
739
    return_trace (ligGlyph.sanitize (c) && component.sanitize (c));
B
Behdad Esfahbod 已提交
740 741
  }

742
  protected:
743
  GlyphID	ligGlyph;		/* GlyphID of ligature to substitute */
B
Behdad Esfahbod 已提交
744 745
  HeadlessArrayOf<GlyphID>
		component;		/* Array of component GlyphIDs--start
746 747
					 * with the second  component--ordered
					 * in writing direction */
748
  public:
749
  DEFINE_SIZE_ARRAY (4, component);
750
};
B
Behdad Esfahbod 已提交
751

B
Behdad Esfahbod 已提交
752 753
struct LigatureSet
{
754
  bool intersects (const hb_set_t *glyphs) const
755 756 757 758 759 760 761 762
  {
    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;
  }

763
  void closure (hb_closure_context_t *c) const
764
  {
B
Behdad Esfahbod 已提交
765 766
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
B
Behdad Esfahbod 已提交
767
      (this+ligature[i]).closure (c);
768 769
  }

770
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
771 772 773 774 775 776
  {
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
      (this+ligature[i]).collect_glyphs (c);
  }

777
  bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
778
  {
B
Behdad Esfahbod 已提交
779
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
780 781 782 783
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
    {
      const Ligature &lig = this+ligature[i];
784
      if (lig.would_apply (c))
B
Behdad Esfahbod 已提交
785
        return_trace (true);
B
Behdad Esfahbod 已提交
786
    }
B
Behdad Esfahbod 已提交
787
    return_trace (false);
B
Behdad Esfahbod 已提交
788 789
  }

790
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
791
  {
B
Behdad Esfahbod 已提交
792
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
793
    unsigned int num_ligs = ligature.len;
B
Behdad Esfahbod 已提交
794 795
    for (unsigned int i = 0; i < num_ligs; i++)
    {
B
Behdad Esfahbod 已提交
796
      const Ligature &lig = this+ligature[i];
B
Behdad Esfahbod 已提交
797
      if (lig.apply (c)) return_trace (true);
798 799
    }

B
Behdad Esfahbod 已提交
800
    return_trace (false);
801
  }
B
Behdad Esfahbod 已提交
802

803
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
804 805
		  hb_array_t<const GlyphID> ligatures,
		  hb_array_t<const unsigned int> component_count_list,
806
		  hb_array_t<const GlyphID> &component_list /* Starting from second for each ligature */)
807
  {
B
Behdad Esfahbod 已提交
808
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
809
    if (unlikely (!c->extend_min (*this))) return_trace (false);
810 811
    if (unlikely (!ligature.serialize (c, ligatures.length))) return_trace (false);
    for (unsigned int i = 0; i < ligatures.length; i++)
B
Behdad Esfahbod 已提交
812 813 814 815 816 817 818 819 820
    {
      unsigned int component_count = MAX<int> (component_count_list[i] - 1, 0);
      if (unlikely (!ligature[i].serialize (c, this)
				.serialize (c,
					    ligatures[i],
					    component_list.sub_array (0, component_count))))
	return_trace (false);
      component_list += component_count;
    }
B
Behdad Esfahbod 已提交
821
    return_trace (true);
822 823
  }

824
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
825
  {
B
Behdad Esfahbod 已提交
826
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
827
    return_trace (ligature.sanitize (c, this));
B
Behdad Esfahbod 已提交
828 829
  }

830
  protected:
B
Behdad Esfahbod 已提交
831 832 833
  OffsetArrayOf<Ligature>
		ligature;		/* Array LigatureSet tables
					 * ordered by preference */
834
  public:
835
  DEFINE_SIZE_ARRAY (2, ligature);
B
Behdad Esfahbod 已提交
836 837
};

B
Behdad Esfahbod 已提交
838 839
struct LigatureSubstFormat1
{
840
  bool intersects (const hb_set_t *glyphs) const
841
  {
842 843 844 845 846 847 848 849
    return
    + hb_zip (this+coverage, ligatureSet)
    | hb_filter (*glyphs, hb_first)
    | hb_map (hb_second)
    | hb_map ([&] (const OffsetTo<LigatureSet> &_) -> bool
	      { return (this+_).intersects (glyphs); })
    | hb_any
    ;
850 851
  }

852
  void closure (hb_closure_context_t *c) const
853
  {
854 855 856
    + hb_zip (this+coverage, ligatureSet)
    | hb_filter (*c->glyphs, hb_first)
    | hb_map (hb_second)
B
Behdad Esfahbod 已提交
857
    | hb_apply ([&] (const OffsetTo<LigatureSet> &_) { (this+_).closure (c); })
858
    ;
859 860
  }

861
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
862
  {
863
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
B
Behdad Esfahbod 已提交
864

865 866
    + hb_zip (this+coverage, ligatureSet)
    | hb_map (hb_second)
B
Behdad Esfahbod 已提交
867
    | hb_apply ([&] (const OffsetTo<LigatureSet> &_) { (this+_).collect_glyphs (c); })
868
    ;
869 870
  }

871
  const Coverage &get_coverage () const { return this+coverage; }
872

873
  bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
874
  {
B
Behdad Esfahbod 已提交
875
    TRACE_WOULD_APPLY (this);
876
    unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
B
Behdad Esfahbod 已提交
877
    if (likely (index == NOT_COVERED)) return_trace (false);
878 879

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

883
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
884
  {
B
Behdad Esfahbod 已提交
885
    TRACE_APPLY (this);
886

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

B
Behdad Esfahbod 已提交
890
    const LigatureSet &lig_set = this+ligatureSet[index];
B
Behdad Esfahbod 已提交
891
    return_trace (lig_set.apply (c));
892
  }
B
Behdad Esfahbod 已提交
893

894
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
895
		  hb_sorted_array_t<const GlyphID> first_glyphs,
B
Behdad Esfahbod 已提交
896 897 898 899
		  hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
		  hb_array_t<const GlyphID> ligatures_list,
		  hb_array_t<const unsigned int> component_count_list,
		  hb_array_t<const GlyphID> component_list /* Starting from second for each ligature */)
900
  {
B
Behdad Esfahbod 已提交
901
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
902
    if (unlikely (!c->extend_min (*this))) return_trace (false);
903 904
    if (unlikely (!ligatureSet.serialize (c, first_glyphs.length))) return_trace (false);
    for (unsigned int i = 0; i < first_glyphs.length; i++)
B
Behdad Esfahbod 已提交
905 906 907 908 909 910 911 912 913 914 915
    {
      unsigned int ligature_count = ligature_per_first_glyph_count_list[i];
      if (unlikely (!ligatureSet[i].serialize (c, this)
				   .serialize (c,
					       ligatures_list.sub_array (0, ligature_count),
					       component_count_list.sub_array (0, ligature_count),
					       component_list))) return_trace (false);
      ligatures_list += ligature_count;
      component_count_list += ligature_count;
    }
    return_trace (coverage.serialize (c, this).serialize (c, first_glyphs));
916 917
  }

918
  bool subset (hb_subset_context_t *c) const
919 920 921 922 923 924
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

925
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
926
  {
B
Behdad Esfahbod 已提交
927
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
928
    return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
929 930
  }

931
  protected:
B
Behdad Esfahbod 已提交
932
  HBUINT16	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
933 934
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
935
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
936
  OffsetArrayOf<LigatureSet>
B
Behdad Esfahbod 已提交
937 938
		ligatureSet;		/* Array LigatureSet tables
					 * ordered by Coverage Index */
939
  public:
940
  DEFINE_SIZE_ARRAY (6, ligatureSet);
B
Behdad Esfahbod 已提交
941
};
942

B
Behdad Esfahbod 已提交
943 944
struct LigatureSubst
{
945
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
946
		  hb_sorted_array_t<const GlyphID> first_glyphs,
B
Behdad Esfahbod 已提交
947 948 949 950
		  hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
		  hb_array_t<const GlyphID> ligatures_list,
		  hb_array_t<const unsigned int> component_count_list,
		  hb_array_t<const GlyphID> component_list /* Starting from second for each ligature */)
951
  {
B
Behdad Esfahbod 已提交
952
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
953
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
954
    unsigned int format = 1;
955
    u.format = format;
956
    switch (u.format) {
B
Behdad Esfahbod 已提交
957 958 959 960 961 962 963
    case 1: return_trace (u.format1.serialize (c,
					       first_glyphs,
					       ligature_per_first_glyph_count_list,
					       ligatures_list,
					       component_count_list,
					       component_list));
    default:return_trace (false);
964 965 966
    }
  }

B
Behdad Esfahbod 已提交
967
  template <typename context_t>
968
  typename context_t::return_t dispatch (context_t *c) const
B
Behdad Esfahbod 已提交
969
  {
970
    TRACE_DISPATCH (this, u.format);
971
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
972
    switch (u.format) {
B
Behdad Esfahbod 已提交
973 974
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
975 976 977
    }
  }

978
  protected:
979
  union {
B
Behdad Esfahbod 已提交
980
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
981
  LigatureSubstFormat1	format1;
982 983 984
  } u;
};

B
Behdad Esfahbod 已提交
985

B
Minor  
Behdad Esfahbod 已提交
986
struct ContextSubst : Context {};
B
Behdad Esfahbod 已提交
987

B
Minor  
Behdad Esfahbod 已提交
988
struct ChainContextSubst : ChainContext {};
989

B
Behdad Esfahbod 已提交
990
struct ExtensionSubst : Extension<ExtensionSubst>
B
Behdad Esfahbod 已提交
991
{
B
Behdad Esfahbod 已提交
992
  typedef struct SubstLookupSubTable SubTable;
B
Behdad Esfahbod 已提交
993

994
  bool is_reverse () const;
995 996 997
};


B
Behdad Esfahbod 已提交
998 999
struct ReverseChainSingleSubstFormat1
{
1000
  bool intersects (const hb_set_t *glyphs) const
1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021
  {
    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;
  }

1022
  void closure (hb_closure_context_t *c) const
1023
  {
B
Behdad Esfahbod 已提交
1024
    if (!intersects (c->glyphs)) return;
B
Behdad Esfahbod 已提交
1025

B
Behdad Esfahbod 已提交
1026
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
B
Behdad Esfahbod 已提交
1027
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
B
Behdad Esfahbod 已提交
1028

B
Behdad Esfahbod 已提交
1029 1030 1031
    + hb_zip (this+coverage, substitute)
    | hb_filter (*c->glyphs, hb_first)
    | hb_map (hb_second)
1032
    | hb_sink (c->output)
1033
    ;
1034 1035
  }

1036
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
1037
  {
1038
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
1039 1040 1041 1042 1043

    unsigned int count;

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

1046
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1047 1048
    count = lookahead.len;
    for (unsigned int i = 0; i < count; i++)
1049
      if (unlikely (!(this+lookahead[i]).add_coverage (c->after))) return;
1050 1051 1052

    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
    count = substitute.len;
1053
    c->output->add_array (substitute.arrayZ, substitute.len);
1054 1055
  }

1056
  const Coverage &get_coverage () const { return this+coverage; }
1057

1058
  bool would_apply (hb_would_apply_context_t *c) const
1059
  {
B
Behdad Esfahbod 已提交
1060
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
1061
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
1062 1063
  }

1064
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1065
  {
B
Behdad Esfahbod 已提交
1066
    TRACE_APPLY (this);
1067
    if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
B
Behdad Esfahbod 已提交
1068
      return_trace (false); /* No chaining to this type */
1069

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

1073 1074
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
1075

1076
  unsigned int start_index = 0, end_index = 0;
B
Behdad Esfahbod 已提交
1077
    if (match_backtrack (c,
1078
			 backtrack.len, (HBUINT16 *) backtrack.arrayZ,
1079 1080
			 match_coverage, this,
			 &start_index) &&
B
Behdad Esfahbod 已提交
1081
        match_lookahead (c,
1082
			 lookahead.len, (HBUINT16 *) lookahead.arrayZ,
B
Behdad Esfahbod 已提交
1083
			 match_coverage, this,
1084
			 1, &end_index))
1085
    {
1086
      c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index);
B
Behdad Esfahbod 已提交
1087
      c->replace_glyph_inplace (substitute[index]);
1088 1089 1090
      /* 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 已提交
1091
      return_trace (true);
1092 1093
    }

B
Behdad Esfahbod 已提交
1094
    return_trace (false);
1095
  }
B
Behdad Esfahbod 已提交
1096

1097
  bool subset (hb_subset_context_t *c) const
1098 1099 1100 1101 1102 1103
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

1104
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
1105
  {
B
Behdad Esfahbod 已提交
1106
    TRACE_SANITIZE (this);
1107
    if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
B
Behdad Esfahbod 已提交
1108
      return_trace (false);
B
Behdad Esfahbod 已提交
1109
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
B
Behdad Esfahbod 已提交
1110
    if (!lookahead.sanitize (c, this))
B
Behdad Esfahbod 已提交
1111
      return_trace (false);
B
Behdad Esfahbod 已提交
1112
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
B
Behdad Esfahbod 已提交
1113
    return_trace (substitute.sanitize (c));
B
Behdad Esfahbod 已提交
1114 1115
  }

1116
  protected:
B
Behdad Esfahbod 已提交
1117
  HBUINT16	format;			/* Format identifier--format = 1 */
1118 1119 1120 1121 1122
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of table */
  OffsetArrayOf<Coverage>
		backtrack;		/* Array of coverage tables
1123
					 * in backtracking sequence, in glyph
B
Behdad Esfahbod 已提交
1124
					 * sequence order */
1125 1126 1127
  OffsetArrayOf<Coverage>
		lookaheadX;		/* Array of coverage tables
					 * in lookahead sequence, in glyph
B
Behdad Esfahbod 已提交
1128
					 * sequence order */
1129 1130 1131
  ArrayOf<GlyphID>
		substituteX;		/* Array of substitute
					 * GlyphIDs--ordered by Coverage Index */
1132
  public:
B
Behdad Esfahbod 已提交
1133
  DEFINE_SIZE_MIN (10);
B
Behdad Esfahbod 已提交
1134 1135
};

B
Behdad Esfahbod 已提交
1136 1137
struct ReverseChainSingleSubst
{
1138
  template <typename context_t>
1139
  typename context_t::return_t dispatch (context_t *c) const
1140
  {
1141
    TRACE_DISPATCH (this, u.format);
1142
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1143
    switch (u.format) {
B
Behdad Esfahbod 已提交
1144 1145
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
1146 1147 1148
    }
  }

1149
  protected:
1150
  union {
B
Behdad Esfahbod 已提交
1151
  HBUINT16				format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1152
  ReverseChainSingleSubstFormat1	format1;
1153 1154 1155 1156 1157
  } u;
};



B
Behdad Esfahbod 已提交
1158 1159 1160 1161
/*
 * SubstLookup
 */

B
Behdad Esfahbod 已提交
1162 1163
struct SubstLookupSubTable
{
B
Behdad Esfahbod 已提交
1164
  friend struct Lookup;
B
Behdad Esfahbod 已提交
1165 1166
  friend struct SubstLookup;

B
Behdad Esfahbod 已提交
1167
  enum Type {
1168 1169 1170 1171 1172 1173 1174
    Single		= 1,
    Multiple		= 2,
    Alternate		= 3,
    Ligature		= 4,
    Context		= 5,
    ChainContext	= 6,
    Extension		= 7,
1175
    ReverseChainSingle	= 8
1176 1177
  };

1178
  template <typename context_t>
1179
  typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
1180
  {
1181
    TRACE_DISPATCH (this, lookup_type);
1182
    switch (lookup_type) {
B
Behdad Esfahbod 已提交
1183 1184 1185 1186 1187 1188 1189 1190 1191
    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 ());
1192 1193 1194
    }
  }

1195
  protected:
B
Behdad Esfahbod 已提交
1196
  union {
B
Behdad Esfahbod 已提交
1197 1198 1199 1200
  SingleSubst			single;
  MultipleSubst			multiple;
  AlternateSubst		alternate;
  LigatureSubst			ligature;
1201
  ContextSubst			context;
B
Behdad Esfahbod 已提交
1202 1203 1204
  ChainContextSubst		chainContext;
  ExtensionSubst		extension;
  ReverseChainSingleSubst	reverseChainContextSingle;
B
Behdad Esfahbod 已提交
1205
  } u;
B
Behdad Esfahbod 已提交
1206
  public:
B
Behdad Esfahbod 已提交
1207
  DEFINE_SIZE_MIN (0);
B
Behdad Esfahbod 已提交
1208 1209
};

1210

B
Behdad Esfahbod 已提交
1211 1212
struct SubstLookup : Lookup
{
B
Behdad Esfahbod 已提交
1213 1214
  typedef SubstLookupSubTable SubTable;

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

1218
  static bool lookup_type_is_reverse (unsigned int lookup_type)
B
Behdad Esfahbod 已提交
1219
  { return lookup_type == SubTable::ReverseChainSingle; }
B
Behdad Esfahbod 已提交
1220

1221
  bool is_reverse () const
B
Behdad Esfahbod 已提交
1222
  {
B
Behdad Esfahbod 已提交
1223
    unsigned int type = get_type ();
B
Behdad Esfahbod 已提交
1224
    if (unlikely (type == SubTable::Extension))
1225
      return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
B
Behdad Esfahbod 已提交
1226
    return lookup_type_is_reverse (type);
B
Behdad Esfahbod 已提交
1227
  }
1228

1229
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1230 1231
  {
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
1232
    return_trace (dispatch (c));
B
Behdad Esfahbod 已提交
1233 1234
  }

1235
  bool intersects (const hb_set_t *glyphs) const
1236 1237 1238 1239 1240
  {
    hb_intersects_context_t c (glyphs);
    return dispatch (&c);
  }

1241
  hb_closure_context_t::return_t closure (hb_closure_context_t *c, unsigned int this_index) const
1242
  {
1243
    if (!c->should_visit_lookup (this_index))
B
Behdad Esfahbod 已提交
1244
      return hb_closure_context_t::default_return_value ();
1245 1246

    c->set_recurse_func (dispatch_closure_recurse_func);
1247 1248 1249 1250 1251

    hb_closure_context_t::return_t ret = dispatch (c);

    c->flush ();

B
Behdad Esfahbod 已提交
1252
    return ret;
B
Behdad Esfahbod 已提交
1253 1254
  }

1255
  hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
B
Behdad Esfahbod 已提交
1256
  {
1257
    c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
B
Behdad Esfahbod 已提交
1258
    return dispatch (c);
1259 1260
  }

B
Behdad Esfahbod 已提交
1261
  template <typename set_t>
1262
  void add_coverage (set_t *glyphs) const
B
Behdad Esfahbod 已提交
1263
  {
1264 1265
    hb_add_coverage_context_t<set_t> c (glyphs);
    dispatch (&c);
B
Behdad Esfahbod 已提交
1266 1267
  }

1268 1269
  bool would_apply (hb_would_apply_context_t *c,
		    const hb_ot_layout_lookup_accelerator_t *accel) const
B
Behdad Esfahbod 已提交
1270
  {
B
Behdad Esfahbod 已提交
1271
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
1272 1273 1274
    if (unlikely (!c->len))  return_trace (false);
    if (!accel->may_have (c->glyphs[0]))  return_trace (false);
      return_trace (dispatch (c));
B
Behdad Esfahbod 已提交
1275 1276
  }

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

1279
  SubTable& serialize_subtable (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
1280 1281
				       unsigned int i)
  { return get_subtables<SubTable> ()[i].serialize (c, this); }
1282

1283 1284
  bool serialize_single (hb_serialize_context_t *c,
			 uint32_t lookup_props,
B
Behdad Esfahbod 已提交
1285
		         hb_sorted_array_t<const GlyphID> glyphs,
B
Behdad Esfahbod 已提交
1286
		         hb_array_t<const GlyphID> substitutes)
1287
  {
B
Behdad Esfahbod 已提交
1288
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1289
    if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1290
    return_trace (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes));
1291 1292
  }

1293 1294
  bool serialize_multiple (hb_serialize_context_t *c,
			   uint32_t lookup_props,
B
Behdad Esfahbod 已提交
1295
			   hb_sorted_array_t<const GlyphID> glyphs,
B
Behdad Esfahbod 已提交
1296 1297
			   hb_array_t<const unsigned int> substitute_len_list,
			   hb_array_t<const GlyphID> substitute_glyphs_list)
1298
  {
B
Behdad Esfahbod 已提交
1299
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1300
    if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1301 1302 1303 1304
    return_trace (serialize_subtable (c, 0).u.multiple.serialize (c,
								  glyphs,
								  substitute_len_list,
								  substitute_glyphs_list));
1305 1306
  }

1307 1308
  bool serialize_alternate (hb_serialize_context_t *c,
			    uint32_t lookup_props,
B
Behdad Esfahbod 已提交
1309
			    hb_sorted_array_t<const GlyphID> glyphs,
B
Behdad Esfahbod 已提交
1310 1311
			    hb_array_t<const unsigned int> alternate_len_list,
			    hb_array_t<const GlyphID> alternate_glyphs_list)
1312
  {
B
Behdad Esfahbod 已提交
1313
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1314
    if (unlikely (!Lookup::serialize (c, SubTable::Alternate, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1315 1316 1317 1318
    return_trace (serialize_subtable (c, 0).u.alternate.serialize (c,
								   glyphs,
								   alternate_len_list,
								   alternate_glyphs_list));
1319 1320
  }

1321 1322
  bool serialize_ligature (hb_serialize_context_t *c,
			   uint32_t lookup_props,
B
Behdad Esfahbod 已提交
1323
			   hb_sorted_array_t<const GlyphID> first_glyphs,
B
Behdad Esfahbod 已提交
1324 1325 1326 1327
			   hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
			   hb_array_t<const GlyphID> ligatures_list,
			   hb_array_t<const unsigned int> component_count_list,
			   hb_array_t<const GlyphID> component_list /* Starting from second for each ligature */)
1328
  {
B
Behdad Esfahbod 已提交
1329
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1330
    if (unlikely (!Lookup::serialize (c, SubTable::Ligature, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1331 1332 1333 1334 1335 1336
    return_trace (serialize_subtable (c, 0).u.ligature.serialize (c,
								  first_glyphs,
								  ligature_per_first_glyph_count_list,
								  ligatures_list,
								  component_count_list,
								  component_list));
1337 1338
  }

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

1342
  static hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned int lookup_index)
1343
  {
1344
    if (!c->should_visit_lookup (lookup_index))
1345
      return hb_void_t ();
1346 1347 1348

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

1349 1350 1351 1352
    /* 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 ();
1353 1354

    return ret;
1355 1356
  }

B
Behdad Esfahbod 已提交
1357
  template <typename context_t>
1358
  typename context_t::return_t dispatch (context_t *c) const
B
Behdad Esfahbod 已提交
1359 1360
  { return Lookup::dispatch<SubTable> (c); }

1361
  bool subset (hb_subset_context_t *c) const
1362
  { return Lookup::subset<SubTable> (c); }
B
Behdad Esfahbod 已提交
1363

1364
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
1365
  { return Lookup::sanitize<SubTable> (c); }
B
Behdad Esfahbod 已提交
1366 1367
};

B
Minor  
Behdad Esfahbod 已提交
1368
/*
1369 1370
 * GSUB -- Glyph Substitution
 * https://docs.microsoft.com/en-us/typography/opentype/spec/gsub
B
Minor  
Behdad Esfahbod 已提交
1371 1372
 */

B
Behdad Esfahbod 已提交
1373 1374
struct GSUB : GSUBGPOS
{
1375
  static constexpr hb_tag_t tableTag = HB_OT_TAG_GSUB;
B
Minor  
Behdad Esfahbod 已提交
1376

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

1380
  bool subset (hb_subset_context_t *c) const
1381
  { return GSUBGPOS::subset<SubstLookup> (c); }
1382

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

1386 1387 1388
  HB_INTERNAL bool is_blacklisted (hb_blob_t *blob,
				   hb_face_t *face) const;

B
WIP  
Behdad Esfahbod 已提交
1389
  typedef GSUBGPOS::accelerator_t<GSUB> accelerator_t;
B
Minor  
Behdad Esfahbod 已提交
1390
};
1391 1392


B
Behdad Esfahbod 已提交
1393 1394 1395
struct GSUB_accelerator_t : GSUB::accelerator_t {};


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

1398
/*static*/ inline bool ExtensionSubst::is_reverse () const
B
Behdad Esfahbod 已提交
1399 1400
{
  unsigned int type = get_type ();
B
Behdad Esfahbod 已提交
1401 1402
  if (unlikely (type == SubTable::Extension))
    return CastR<ExtensionSubst> (get_subtable<SubTable>()).is_reverse ();
B
Behdad Esfahbod 已提交
1403 1404 1405
  return SubstLookup::lookup_type_is_reverse (type);
}

1406
template <typename context_t>
1407
/*static*/ inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
1408
{
B
Behdad Esfahbod 已提交
1409
  const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index);
1410
  return l.dispatch (c);
1411 1412
}

1413
/*static*/ inline bool SubstLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index)
B
Behdad Esfahbod 已提交
1414
{
B
Behdad Esfahbod 已提交
1415
  const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index);
1416
  unsigned int saved_lookup_props = c->lookup_props;
1417 1418 1419
  unsigned int saved_lookup_index = c->lookup_index;
  c->set_lookup_index (lookup_index);
  c->set_lookup_props (l.get_props ());
1420
  bool ret = l.dispatch (c);
1421
  c->set_lookup_index (saved_lookup_index);
1422
  c->set_lookup_props (saved_lookup_props);
1423
  return ret;
1424 1425
}

B
Behdad Esfahbod 已提交
1426
} /* namespace OT */
1427

B
Behdad Esfahbod 已提交
1428

1429
#endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */