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

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

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

B
Behdad Esfahbod 已提交
34

35 36
namespace OT {

37
typedef hb_pair_t<hb_codepoint_t, hb_codepoint_t> hb_codepoint_pair_t;
38

39
template<typename Iterator,
B
Behdad Esfahbod 已提交
40 41
	 hb_requires (hb_is_sorted_source_of (Iterator,
					      const hb_codepoint_pair_t))>
42
static inline void SingleSubst_serialize (hb_serialize_context_t *c,
43 44
					  Iterator it);

45

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

51
  void closure (hb_closure_context_t *c) const
52
  {
B
Behdad Esfahbod 已提交
53
    unsigned d = deltaGlyphID;
54 55
    + hb_iter (this+coverage)
    | hb_filter (*c->glyphs)
B
Behdad Esfahbod 已提交
56
    | hb_map ([d] (hb_codepoint_t g) { return (g + d) & 0xFFFFu; })
57 58
    | hb_sink (c->output)
    ;
59 60
  }

61
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
62
  {
63
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
B
Behdad Esfahbod 已提交
64
    unsigned d = deltaGlyphID;
65
    + hb_iter (this+coverage)
B
Behdad Esfahbod 已提交
66
    | hb_map ([d] (hb_codepoint_t g) { return (g + d) & 0xFFFFu; })
67 68
    | hb_sink (c->output)
    ;
69 70
  }

71
  const Coverage &get_coverage () const { return this+coverage; }
72

73
  bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
74
  { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
75

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

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

B
Behdad Esfahbod 已提交
88
    return_trace (true);
89
  }
B
Behdad Esfahbod 已提交
90

91
  template<typename Iterator,
B
Behdad Esfahbod 已提交
92 93
	   hb_requires (hb_is_sorted_source_of (Iterator,
						hb_codepoint_t))>
94
  bool serialize (hb_serialize_context_t *c,
95
		  Iterator glyphs,
96
		  unsigned delta)
97
  {
B
Behdad Esfahbod 已提交
98
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
99
    if (unlikely (!c->extend_min (*this))) return_trace (false);
B
Behdad Esfahbod 已提交
100
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs))) return_trace (false);
101
    c->check_assign (deltaGlyphID, delta);
B
Behdad Esfahbod 已提交
102
    return_trace (true);
103 104
  }

105
  bool subset (hb_subset_context_t *c) const
106 107
  {
    TRACE_SUBSET (this);
108
    const hb_set_t &glyphset = *c->plan->glyphset ();
109
    const hb_map_t &glyph_map = *c->plan->glyph_map;
110

111
    hb_codepoint_t delta = deltaGlyphID;
112

113
    auto it =
114 115
    + hb_iter (this+coverage)
    | hb_filter (glyphset)
116 117 118 119
    | hb_map_retains_sorting ([&] (hb_codepoint_t g) {
                                return hb_codepoint_pair_t (glyph_map[g],
                                                            glyph_map[(g + delta) & 0xFFFF]); })
    ;
120

121 122
    SingleSubst_serialize (c->serializer, it);
    return_trace (it.len ());
123 124
  }

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

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

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

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

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

165
  const Coverage &get_coverage () const { return this+coverage; }
166

167
  bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
168
  { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
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
  template<typename Iterator,
B
Behdad Esfahbod 已提交
184 185
	   hb_requires (hb_is_sorted_source_of (Iterator,
						const hb_codepoint_pair_t))>
186
  bool serialize (hb_serialize_context_t *c,
187
		  Iterator it)
B
Behdad Esfahbod 已提交
188
  {
B
Behdad Esfahbod 已提交
189
    TRACE_SERIALIZE (this);
190 191 192 193 194 195 196 197
    auto substitutes =
      + it
      | hb_map (hb_second)
      ;
    auto glyphs =
      + it
      | hb_map_retains_sorting (hb_first)
      ;
B
Behdad Esfahbod 已提交
198
    if (unlikely (!c->extend_min (*this))) return_trace (false);
B
Behdad Esfahbod 已提交
199 200
    if (unlikely (!substitute.serialize (c, substitutes))) return_trace (false);
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs))) return_trace (false);
B
Behdad Esfahbod 已提交
201
    return_trace (true);
B
Behdad Esfahbod 已提交
202 203
  }

204
  bool subset (hb_subset_context_t *c) const
205 206
  {
    TRACE_SUBSET (this);
207
    const hb_set_t &glyphset = *c->plan->glyphset ();
208
    const hb_map_t &glyph_map = *c->plan->glyph_map;
209

210
    auto it =
211 212
    + hb_zip (this+coverage, substitute)
    | hb_filter (glyphset, hb_first)
213 214 215
    | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const GlyphID &> p) -> hb_codepoint_pair_t
                              { return hb_pair (glyph_map[p.first], glyph_map[p.second]); })
    ;
216

217 218
    SingleSubst_serialize (c->serializer, it);
    return_trace (it.len ());
219 220
  }

221
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
222
  {
B
Behdad Esfahbod 已提交
223
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
224
    return_trace (coverage.sanitize (c, this) && substitute.sanitize (c));
B
Behdad Esfahbod 已提交
225 226
  }

227
  protected:
B
Behdad Esfahbod 已提交
228
  HBUINT16	format;			/* Format identifier--format = 2 */
B
Behdad Esfahbod 已提交
229 230
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
231
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
232 233 234
  ArrayOf<GlyphID>
		substitute;		/* Array of substitute
					 * GlyphIDs--ordered by Coverage Index */
235
  public:
236
  DEFINE_SIZE_ARRAY (6, substitute);
B
Behdad Esfahbod 已提交
237 238
};

B
Behdad Esfahbod 已提交
239 240
struct SingleSubst
{
241 242

  template<typename Iterator,
B
Behdad Esfahbod 已提交
243 244
	   hb_requires (hb_is_sorted_source_of (Iterator,
						const hb_codepoint_pair_t))>
245
  bool serialize (hb_serialize_context_t *c,
246
		  Iterator glyphs)
B
Behdad Esfahbod 已提交
247
  {
B
Behdad Esfahbod 已提交
248
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
249
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
B
Behdad Esfahbod 已提交
250 251
    unsigned format = 2;
    unsigned delta = 0;
252
    if (glyphs.len ())
B
Behdad Esfahbod 已提交
253
    {
B
Behdad Esfahbod 已提交
254
      format = 1;
255 256 257 258 259
      auto get_delta = [=] (hb_codepoint_pair_t _) {
			 return (unsigned) (_.second - _.first) & 0xFFFF;
		       };
      delta = get_delta (*glyphs);
      if (!hb_all (++(+glyphs), delta, get_delta)) format = 2;
B
Behdad Esfahbod 已提交
260
    }
261
    u.format = format;
B
Behdad Esfahbod 已提交
262
    switch (u.format) {
263 264 265 266 267
    case 1: return_trace (u.format1.serialize (c,
                                               + glyphs
                                               | hb_map_retains_sorting (hb_first),
                                               delta));
    case 2: return_trace (u.format2.serialize (c, glyphs));
B
Behdad Esfahbod 已提交
268
    default:return_trace (false);
B
Behdad Esfahbod 已提交
269 270 271
    }
  }

272
  template <typename context_t, typename ...Ts>
B
Behdad Esfahbod 已提交
273
  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
B
Behdad Esfahbod 已提交
274
  {
275
    TRACE_DISPATCH (this, u.format);
276
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
277
    switch (u.format) {
278 279
    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
    case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
B
Behdad Esfahbod 已提交
280
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
281 282 283
    }
  }

284
  protected:
285
  union {
B
Behdad Esfahbod 已提交
286
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
287 288
  SingleSubstFormat1	format1;
  SingleSubstFormat2	format2;
289
  } u;
B
Behdad Esfahbod 已提交
290
};
291

B
Behdad Esfahbod 已提交
292
template<typename Iterator>
293 294
static inline void
SingleSubst_serialize (hb_serialize_context_t *c,
295 296
		       Iterator it)
{ c->start_embed<SingleSubst> ()->serialize (c, it); }
B
Behdad Esfahbod 已提交
297

B
Behdad Esfahbod 已提交
298 299
struct Sequence
{
300
  void closure (hb_closure_context_t *c) const
301
  {
B
Behdad Esfahbod 已提交
302 303
    unsigned int count = substitute.len;
    for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
304
      c->output->add (substitute[i]);
305 306
  }

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

310
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
311
  {
B
Behdad Esfahbod 已提交
312
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
313
    unsigned int count = substitute.len;
314

B
Behdad Esfahbod 已提交
315 316 317
    /* Special-case to make it in-place and not consider this
     * as a "multiplied" substitution. */
    if (unlikely (count == 1))
318
    {
319
      c->replace_glyph (substitute.arrayZ[0]);
B
Behdad Esfahbod 已提交
320
      return_trace (true);
321
    }
322
    /* Spec disallows this, but Uniscribe allows it.
323
     * https://github.com/harfbuzz/harfbuzz/issues/253 */
324 325 326 327 328
    else if (unlikely (count == 0))
    {
      c->buffer->delete_glyph ();
      return_trace (true);
    }
B
Behdad Esfahbod 已提交
329 330 331 332 333 334

    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);
335
      c->output_glyph_for_component (substitute.arrayZ[i], klass);
336
    }
B
Behdad Esfahbod 已提交
337
    c->buffer->skip_glyph ();
B
Behdad Esfahbod 已提交
338

B
Behdad Esfahbod 已提交
339
    return_trace (true);
B
Behdad Esfahbod 已提交
340 341
  }

342
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
343
		  hb_array_t<const GlyphID> subst)
344
  {
B
Behdad Esfahbod 已提交
345
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
346
    return_trace (substitute.serialize (c, subst));
347 348
  }

349
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
350
  {
B
Behdad Esfahbod 已提交
351
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
352
    return_trace (substitute.sanitize (c));
B
Behdad Esfahbod 已提交
353 354
  }

355
  protected:
B
Behdad Esfahbod 已提交
356 357
  ArrayOf<GlyphID>
		substitute;		/* String of GlyphIDs to substitute */
358
  public:
359
  DEFINE_SIZE_ARRAY (2, substitute);
B
Behdad Esfahbod 已提交
360 361
};

B
Behdad Esfahbod 已提交
362 363
struct MultipleSubstFormat1
{
364
  bool intersects (const hb_set_t *glyphs) const
365 366
  { return (this+coverage).intersects (glyphs); }

367
  void closure (hb_closure_context_t *c) const
368
  {
369 370 371
    + hb_zip (this+coverage, sequence)
    | hb_filter (*c->glyphs, hb_first)
    | hb_map (hb_second)
B
Behdad Esfahbod 已提交
372
    | hb_apply ([c, this] (const OffsetTo<Sequence> &_) { (this+_).closure (c); })
373
    ;
374 375
  }

376
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
377
  {
378
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
379 380
    + hb_zip (this+coverage, sequence)
    | hb_map (hb_second)
B
Behdad Esfahbod 已提交
381
    | hb_apply ([c, this] (const OffsetTo<Sequence> &_) { (this+_).collect_glyphs (c); })
382
    ;
383 384
  }

385
  const Coverage &get_coverage () const { return this+coverage; }
386

387
  bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
388
  { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
389

390
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
391
  {
B
Behdad Esfahbod 已提交
392
    TRACE_APPLY (this);
393

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

B
Behdad Esfahbod 已提交
397
    return_trace ((this+sequence[index]).apply (c));
398
  }
B
Behdad Esfahbod 已提交
399

400
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
401
		  hb_sorted_array_t<const GlyphID> glyphs,
B
Behdad Esfahbod 已提交
402 403
		  hb_array_t<const unsigned int> substitute_len_list,
		  hb_array_t<const GlyphID> substitute_glyphs_list)
404
  {
B
Behdad Esfahbod 已提交
405
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
406
    if (unlikely (!c->extend_min (*this))) return_trace (false);
407 408
    if (unlikely (!sequence.serialize (c, glyphs.length))) return_trace (false);
    for (unsigned int i = 0; i < glyphs.length; i++)
B
Behdad Esfahbod 已提交
409 410 411 412 413 414 415 416
    {
      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));
417 418
  }

419
  bool subset (hb_subset_context_t *c) const
420 421 422 423 424 425
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

426
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
427
  {
B
Behdad Esfahbod 已提交
428
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
429
    return_trace (coverage.sanitize (c, this) && sequence.sanitize (c, this));
B
Behdad Esfahbod 已提交
430 431
  }

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

B
Behdad Esfahbod 已提交
444 445
struct MultipleSubst
{
446
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
447
		  hb_sorted_array_t<const GlyphID> glyphs,
B
Behdad Esfahbod 已提交
448 449
		  hb_array_t<const unsigned int> substitute_len_list,
		  hb_array_t<const GlyphID> substitute_glyphs_list)
450
  {
B
Behdad Esfahbod 已提交
451
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
452
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
453
    unsigned int format = 1;
454
    u.format = format;
455
    switch (u.format) {
B
Behdad Esfahbod 已提交
456
    case 1: return_trace (u.format1.serialize (c, glyphs, substitute_len_list, substitute_glyphs_list));
B
Behdad Esfahbod 已提交
457
    default:return_trace (false);
458 459 460
    }
  }

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

472
  protected:
473
  union {
B
Behdad Esfahbod 已提交
474
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
475
  MultipleSubstFormat1	format1;
476 477 478
  } u;
};

479 480
struct AlternateSet
{
481
  void closure (hb_closure_context_t *c) const
482 483 484
  {
    unsigned int count = alternates.len;
    for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
485
      c->output->add (alternates[i]);
486 487
  }

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

491
  bool apply (hb_ot_apply_context_t *c) const
492 493 494 495 496 497
  {
    TRACE_APPLY (this);
    unsigned int count = alternates.len;

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

498 499
    hb_mask_t glyph_mask = c->buffer->cur().mask;
    hb_mask_t lookup_mask = c->lookup_mask;
500

501 502 503
    /* 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);
504

505
    /* If alt_index is MAX_VALUE, randomize feature if it is the rand feature. */
506
    if (alt_index == HB_OT_MAP_MAX_VALUE && c->random)
B
Behdad Esfahbod 已提交
507
      alt_index = c->random_number () % count + 1;
B
Behdad Esfahbod 已提交
508

509 510
    if (unlikely (alt_index > count || alt_index == 0)) return_trace (false);

511 512
    c->replace_glyph (alternates[alt_index - 1]);

513 514 515
    return_trace (true);
  }

516
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
517
		  hb_array_t<const GlyphID> alts)
518 519
  {
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
520
    return_trace (alternates.serialize (c, alts));
521 522
  }

523
  bool sanitize (hb_sanitize_context_t *c) const
524 525 526 527 528 529 530 531
  {
    TRACE_SANITIZE (this);
    return_trace (alternates.sanitize (c));
  }

  protected:
  ArrayOf<GlyphID>
		alternates;		/* Array of alternate GlyphIDs--in
B
Behdad Esfahbod 已提交
532
					 * arbitrary order */
533 534 535
  public:
  DEFINE_SIZE_ARRAY (2, alternates);
};
B
Behdad Esfahbod 已提交
536

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

542
  void closure (hb_closure_context_t *c) const
543
  {
544 545
    + hb_zip (this+coverage, alternateSet)
    | hb_map (hb_second)
B
Behdad Esfahbod 已提交
546
    | hb_apply ([c, this] (const OffsetTo<AlternateSet> &_) { (this+_).closure (c); })
547
    ;
548 549
  }

550
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
551
  {
552
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
553 554
    + hb_zip (this+coverage, alternateSet)
    | hb_map (hb_second)
B
Behdad Esfahbod 已提交
555
    | hb_apply ([c, this] (const OffsetTo<AlternateSet> &_) { (this+_).collect_glyphs (c); })
556
    ;
557 558
  }

559
  const Coverage &get_coverage () const { return this+coverage; }
560

561
  bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
562
  { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
563

564
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
565
  {
B
Behdad Esfahbod 已提交
566
    TRACE_APPLY (this);
567

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

571
    return_trace ((this+alternateSet[index]).apply (c));
572
  }
B
Behdad Esfahbod 已提交
573

574
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
575
		  hb_sorted_array_t<const GlyphID> glyphs,
B
Behdad Esfahbod 已提交
576 577
		  hb_array_t<const unsigned int> alternate_len_list,
		  hb_array_t<const GlyphID> alternate_glyphs_list)
578
  {
B
Behdad Esfahbod 已提交
579
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
580
    if (unlikely (!c->extend_min (*this))) return_trace (false);
581 582
    if (unlikely (!alternateSet.serialize (c, glyphs.length))) return_trace (false);
    for (unsigned int i = 0; i < glyphs.length; i++)
B
Behdad Esfahbod 已提交
583 584 585 586 587 588 589 590
    {
      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));
591 592
  }

593
  bool subset (hb_subset_context_t *c) const
594 595 596 597 598 599
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

600
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
601
  {
B
Behdad Esfahbod 已提交
602
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
603
    return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
604 605
  }

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

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

635
  template <typename context_t, typename ...Ts>
B
Behdad Esfahbod 已提交
636
  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
B
Behdad Esfahbod 已提交
637
  {
638
    TRACE_DISPATCH (this, u.format);
639
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
640
    switch (u.format) {
641
    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
B
Behdad Esfahbod 已提交
642
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
643 644 645
    }
  }

646
  protected:
647
  union {
B
Behdad Esfahbod 已提交
648
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
649
  AlternateSubstFormat1	format1;
650 651 652
  } u;
};

653

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

665
  void closure (hb_closure_context_t *c) const
666
  {
B
Behdad Esfahbod 已提交
667
    if (!intersects (c->glyphs)) return;
B
Behdad Esfahbod 已提交
668
    c->output->add (ligGlyph);
669 670
  }

671
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
672
  {
673
    c->input->add_array (component.arrayZ, component.lenP1 ? component.lenP1 - 1 : 0);
B
Minor  
Behdad Esfahbod 已提交
674
    c->output->add (ligGlyph);
675 676
  }

677
  bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
678
  {
679
    if (c->len != component.lenP1)
B
Behdad Esfahbod 已提交
680
      return false;
681 682 683

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

B
Behdad Esfahbod 已提交
686
    return true;
B
Behdad Esfahbod 已提交
687 688
  }

689
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
690
  {
B
Behdad Esfahbod 已提交
691
    TRACE_APPLY (this);
692
    unsigned int count = component.lenP1;
B
Behdad Esfahbod 已提交
693

B
Behdad Esfahbod 已提交
694
    if (unlikely (!count)) return_trace (false);
B
Behdad Esfahbod 已提交
695

696 697 698 699 700
    /* 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 已提交
701
      return_trace (true);
702 703
    }

B
Behdad Esfahbod 已提交
704
    unsigned int total_component_count = 0;
705

706
    unsigned int match_length = 0;
707
    unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
708

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

718 719
    ligate_input (c,
		  count,
720 721
		  match_positions,
		  match_length,
722
		  ligGlyph,
723
		  total_component_count);
724

B
Behdad Esfahbod 已提交
725
    return_trace (true);
726
  }
727

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

B
Behdad Esfahbod 已提交
739
  public:
740
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
741
  {
B
Behdad Esfahbod 已提交
742
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
743
    return_trace (ligGlyph.sanitize (c) && component.sanitize (c));
B
Behdad Esfahbod 已提交
744 745
  }

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

B
Behdad Esfahbod 已提交
756 757
struct LigatureSet
{
758
  bool intersects (const hb_set_t *glyphs) const
759
  {
B
Behdad Esfahbod 已提交
760 761
    return
    + hb_iter (ligature)
B
Behdad Esfahbod 已提交
762
    | hb_map ([this, glyphs] (const OffsetTo<Ligature> &_) { return (this+_).intersects (glyphs); })
B
Behdad Esfahbod 已提交
763 764
    | hb_any
    ;
765 766
  }

767
  void closure (hb_closure_context_t *c) const
768
  {
B
Behdad Esfahbod 已提交
769
    + hb_iter (ligature)
B
Behdad Esfahbod 已提交
770
    | hb_apply ([this, c] (const OffsetTo<Ligature> &_) { (this+_).closure (c); })
B
Behdad Esfahbod 已提交
771
    ;
772 773
  }

774
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
775
  {
B
Behdad Esfahbod 已提交
776
    + hb_iter (ligature)
B
Behdad Esfahbod 已提交
777
    | hb_apply ([this, c] (const OffsetTo<Ligature> &_) { (this+_).collect_glyphs (c); })
B
Behdad Esfahbod 已提交
778
    ;
779 780
  }

781
  bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
782
  {
B
Behdad Esfahbod 已提交
783 784
    return
    + hb_iter (ligature)
B
Behdad Esfahbod 已提交
785
    | hb_map ([this, c] (const OffsetTo<Ligature> &_) { return (this+_).would_apply (c); })
B
Behdad Esfahbod 已提交
786 787
    | hb_any
    ;
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
      unsigned int component_count = (unsigned) hb_max ((int) component_count_list[i] - 1, 0);
B
Behdad Esfahbod 已提交
814 815 816 817 818 819 820
      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
    return
    + hb_zip (this+coverage, ligatureSet)
    | hb_filter (*glyphs, hb_first)
    | hb_map (hb_second)
B
Behdad Esfahbod 已提交
846
    | hb_map ([this, glyphs] (const OffsetTo<LigatureSet> &_)
847 848 849
	      { 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 ([this, c] (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 ([this, c] (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
  {
875
    unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
B
Behdad Esfahbod 已提交
876
    if (likely (index == NOT_COVERED)) return false;
877 878

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

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

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

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

893
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
894
		  hb_sorted_array_t<const GlyphID> first_glyphs,
B
Behdad Esfahbod 已提交
895 896 897 898
		  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 */)
899
  {
B
Behdad Esfahbod 已提交
900
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
901
    if (unlikely (!c->extend_min (*this))) return_trace (false);
902 903
    if (unlikely (!ligatureSet.serialize (c, first_glyphs.length))) return_trace (false);
    for (unsigned int i = 0; i < first_glyphs.length; i++)
B
Behdad Esfahbod 已提交
904 905 906 907 908 909 910 911 912 913 914
    {
      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));
915 916
  }

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

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

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

B
Behdad Esfahbod 已提交
942 943
struct LigatureSubst
{
944
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
945
		  hb_sorted_array_t<const GlyphID> first_glyphs,
B
Behdad Esfahbod 已提交
946 947 948 949
		  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 */)
950
  {
B
Behdad Esfahbod 已提交
951
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
952
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
953
    unsigned int format = 1;
954
    u.format = format;
955
    switch (u.format) {
B
Behdad Esfahbod 已提交
956 957 958 959 960 961 962
    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);
963 964 965
    }
  }

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

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

B
Behdad Esfahbod 已提交
984

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

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

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

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


B
Behdad Esfahbod 已提交
997 998
struct ReverseChainSingleSubstFormat1
{
999
  bool intersects (const hb_set_t *glyphs) const
1000 1001 1002 1003
  {
    if (!(this+coverage).intersects (glyphs))
      return false;

1004
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020

    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;
  }

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

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

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

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

    unsigned int count;

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

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

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

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

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

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

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

1069 1070
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID>> (lookahead);
1071

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

B
Behdad Esfahbod 已提交
1090
    return_trace (false);
1091
  }
B
Behdad Esfahbod 已提交
1092

1093
  bool subset (hb_subset_context_t *c) const
1094 1095 1096 1097 1098 1099
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

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

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

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

1145
  protected:
1146
  union {
B
Behdad Esfahbod 已提交
1147
  HBUINT16				format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1148
  ReverseChainSingleSubstFormat1	format1;
1149 1150 1151 1152 1153
  } u;
};



B
Behdad Esfahbod 已提交
1154 1155 1156 1157
/*
 * SubstLookup
 */

B
Behdad Esfahbod 已提交
1158 1159
struct SubstLookupSubTable
{
B
Behdad Esfahbod 已提交
1160
  friend struct Lookup;
B
Behdad Esfahbod 已提交
1161 1162
  friend struct SubstLookup;

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

1174
  template <typename context_t, typename ...Ts>
B
Behdad Esfahbod 已提交
1175
  typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type, Ts&&... ds) const
1176
  {
1177
    TRACE_DISPATCH (this, lookup_type);
1178
    switch (lookup_type) {
1179 1180 1181 1182 1183 1184 1185 1186
    case Single:		return_trace (u.single.dispatch (c, hb_forward<Ts> (ds)...));
    case Multiple:		return_trace (u.multiple.dispatch (c, hb_forward<Ts> (ds)...));
    case Alternate:		return_trace (u.alternate.dispatch (c, hb_forward<Ts> (ds)...));
    case Ligature:		return_trace (u.ligature.dispatch (c, hb_forward<Ts> (ds)...));
    case Context:		return_trace (u.context.dispatch (c, hb_forward<Ts> (ds)...));
    case ChainContext:		return_trace (u.chainContext.dispatch (c, hb_forward<Ts> (ds)...));
    case Extension:		return_trace (u.extension.dispatch (c, hb_forward<Ts> (ds)...));
    case ReverseChainSingle:	return_trace (u.reverseChainContextSingle.dispatch (c, hb_forward<Ts> (ds)...));
B
Behdad Esfahbod 已提交
1187
    default:			return_trace (c->default_return_value ());
1188 1189 1190
    }
  }

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

1206

B
Behdad Esfahbod 已提交
1207 1208
struct SubstLookup : Lookup
{
B
Behdad Esfahbod 已提交
1209 1210
  typedef SubstLookupSubTable SubTable;

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

B
Behdad Esfahbod 已提交
1214
  HB_INTERNAL static bool lookup_type_is_reverse (unsigned int lookup_type)
B
Behdad Esfahbod 已提交
1215
  { return lookup_type == SubTable::ReverseChainSingle; }
B
Behdad Esfahbod 已提交
1216

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

1225
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1226 1227
  {
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
1228
    return_trace (dispatch (c));
B
Behdad Esfahbod 已提交
1229 1230
  }

1231
  bool intersects (const hb_set_t *glyphs) const
1232 1233 1234 1235 1236
  {
    hb_intersects_context_t c (glyphs);
    return dispatch (&c);
  }

1237
  hb_closure_context_t::return_t closure (hb_closure_context_t *c, unsigned int this_index) const
1238
  {
1239
    if (!c->should_visit_lookup (this_index))
B
Behdad Esfahbod 已提交
1240
      return hb_closure_context_t::default_return_value ();
1241 1242

    c->set_recurse_func (dispatch_closure_recurse_func);
1243 1244 1245 1246 1247

    hb_closure_context_t::return_t ret = dispatch (c);

    c->flush ();

B
Behdad Esfahbod 已提交
1248
    return ret;
B
Behdad Esfahbod 已提交
1249 1250
  }

1251
  hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
B
Behdad Esfahbod 已提交
1252
  {
1253
    c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
B
Behdad Esfahbod 已提交
1254
    return dispatch (c);
1255 1256
  }

B
Behdad Esfahbod 已提交
1257
  template <typename set_t>
1258
  void add_coverage (set_t *glyphs) const
B
Behdad Esfahbod 已提交
1259
  {
1260 1261
    hb_add_coverage_context_t<set_t> c (glyphs);
    dispatch (&c);
B
Behdad Esfahbod 已提交
1262 1263
  }

1264 1265
  bool would_apply (hb_would_apply_context_t *c,
		    const hb_ot_layout_lookup_accelerator_t *accel) const
B
Behdad Esfahbod 已提交
1266
  {
B
Behdad Esfahbod 已提交
1267 1268 1269
    if (unlikely (!c->len)) return false;
    if (!accel->may_have (c->glyphs[0])) return false;
      return dispatch (c);
B
Behdad Esfahbod 已提交
1270 1271
  }

B
Behdad Esfahbod 已提交
1272
  HB_INTERNAL static bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index);
B
Behdad Esfahbod 已提交
1273

1274
  SubTable& serialize_subtable (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
1275 1276
				       unsigned int i)
  { return get_subtables<SubTable> ()[i].serialize (c, this); }
1277

1278 1279
  bool serialize_single (hb_serialize_context_t *c,
			 uint32_t lookup_props,
B
Behdad Esfahbod 已提交
1280
		         hb_sorted_array_t<const GlyphID> glyphs,
B
Behdad Esfahbod 已提交
1281
		         hb_array_t<const GlyphID> substitutes)
1282
  {
B
Behdad Esfahbod 已提交
1283
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1284
    if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false);
1285 1286 1287

    return_trace (serialize_subtable (c, 0).u.single
		  .serialize (c, hb_zip (glyphs, substitutes)));
1288 1289
  }

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

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

1318 1319
  bool serialize_ligature (hb_serialize_context_t *c,
			   uint32_t lookup_props,
B
Behdad Esfahbod 已提交
1320
			   hb_sorted_array_t<const GlyphID> first_glyphs,
B
Behdad Esfahbod 已提交
1321 1322 1323 1324
			   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 */)
1325
  {
B
Behdad Esfahbod 已提交
1326
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1327
    if (unlikely (!Lookup::serialize (c, SubTable::Ligature, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1328 1329 1330 1331 1332 1333
    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));
1334 1335
  }

B
Behdad Esfahbod 已提交
1336
  template <typename context_t>
B
Behdad Esfahbod 已提交
1337
  HB_INTERNAL static typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
B
Behdad Esfahbod 已提交
1338

B
Behdad Esfahbod 已提交
1339
  HB_INTERNAL static hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned int lookup_index)
1340
  {
1341
    if (!c->should_visit_lookup (lookup_index))
B
Behdad Esfahbod 已提交
1342
      return hb_empty_t ();
1343 1344 1345

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

1346 1347 1348 1349
    /* 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 ();
1350 1351

    return ret;
1352 1353
  }

1354
  template <typename context_t, typename ...Ts>
B
Behdad Esfahbod 已提交
1355
  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
1356
  { return Lookup::dispatch<SubTable> (c, hb_forward<Ts> (ds)...); }
B
Behdad Esfahbod 已提交
1357

1358
  bool subset (hb_subset_context_t *c) const
1359
  { return Lookup::subset<SubTable> (c); }
B
Behdad Esfahbod 已提交
1360

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

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

B
Behdad Esfahbod 已提交
1370 1371
struct GSUB : GSUBGPOS
{
1372
  static constexpr hb_tag_t tableTag = HB_OT_TAG_GSUB;
B
Minor  
Behdad Esfahbod 已提交
1373

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

1377
  bool subset (hb_subset_context_t *c) const
1378
  { return GSUBGPOS::subset<SubstLookup> (c); }
1379

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

1383 1384 1385
  HB_INTERNAL bool is_blacklisted (hb_blob_t *blob,
				   hb_face_t *face) const;

B
WIP  
Behdad Esfahbod 已提交
1386
  typedef GSUBGPOS::accelerator_t<GSUB> accelerator_t;
B
Minor  
Behdad Esfahbod 已提交
1387
};
1388 1389


B
Behdad Esfahbod 已提交
1390 1391 1392
struct GSUB_accelerator_t : GSUB::accelerator_t {};


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

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

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

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

B
Behdad Esfahbod 已提交
1423
} /* namespace OT */
1424

B
Behdad Esfahbod 已提交
1425

1426
#endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */