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

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

43

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

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

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

69
  const Coverage &get_coverage () const { return this+coverage; }
70

71
  bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
72
  { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
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
  template<typename Iterator,
90
	   hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_t))>
91
  bool serialize (hb_serialize_context_t *c,
92
		  Iterator glyphs,
93
		  unsigned delta)
94
  {
B
Behdad Esfahbod 已提交
95
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
96
    if (unlikely (!c->extend_min (*this))) return_trace (false);
B
Behdad Esfahbod 已提交
97
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs))) return_trace (false);
98
    c->check_assign (deltaGlyphID, delta);
B
Behdad Esfahbod 已提交
99
    return_trace (true);
100 101
  }

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

108
    hb_codepoint_t delta = deltaGlyphID;
109

110
    auto it =
111 112
    + hb_iter (this+coverage)
    | hb_filter (glyphset)
113
    | hb_map_retains_sorting ([&] (hb_codepoint_t g) {
B
Behdad Esfahbod 已提交
114 115
				return hb_codepoint_pair_t (glyph_map[g],
							    glyph_map[(g + delta) & 0xFFFF]); })
116
    ;
117

118
    bool ret = bool (it);
119
    SingleSubst_serialize (c->serializer, it);
120
    return_trace (ret);
121 122
  }

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

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

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

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

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

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

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

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

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

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

B
Behdad Esfahbod 已提交
178
    return_trace (true);
179
  }
B
Behdad Esfahbod 已提交
180

181
  template<typename Iterator,
B
Behdad Esfahbod 已提交
182
	   hb_requires (hb_is_sorted_source_of (Iterator,
B
Behdad Esfahbod 已提交
183
						hb_codepoint_pair_t))>
184
  bool serialize (hb_serialize_context_t *c,
185
		  Iterator it)
B
Behdad Esfahbod 已提交
186
  {
B
Behdad Esfahbod 已提交
187
    TRACE_SERIALIZE (this);
188 189 190 191 192 193 194 195
    auto substitutes =
      + it
      | hb_map (hb_second)
      ;
    auto glyphs =
      + it
      | hb_map_retains_sorting (hb_first)
      ;
B
Behdad Esfahbod 已提交
196
    if (unlikely (!c->extend_min (*this))) return_trace (false);
B
Behdad Esfahbod 已提交
197 198
    if (unlikely (!substitute.serialize (c, substitutes))) return_trace (false);
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs))) return_trace (false);
B
Behdad Esfahbod 已提交
199
    return_trace (true);
B
Behdad Esfahbod 已提交
200 201
  }

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

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

215
    bool ret = bool (it);
216
    SingleSubst_serialize (c->serializer, it);
217
    return_trace (ret);
218 219
  }

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

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

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

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

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

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

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

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

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

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

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

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

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

341 342
  template <typename Iterator,
	    hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
343
  bool serialize (hb_serialize_context_t *c,
344
		  Iterator subst)
345
  {
B
Behdad Esfahbod 已提交
346
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
347
    return_trace (substitute.serialize (c, subst));
348 349
  }

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

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

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

368
  void closure (hb_closure_context_t *c) const
369
  {
370 371 372
    + hb_zip (this+coverage, sequence)
    | hb_filter (*c->glyphs, hb_first)
    | hb_map (hb_second)
373 374
    | hb_map (hb_add (this))
    | hb_apply ([c] (const Sequence &_) { _.closure (c); })
375
    ;
376 377
  }

378
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
379
  {
380
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
381 382
    + hb_zip (this+coverage, sequence)
    | hb_map (hb_second)
383 384
    | hb_map (hb_add (this))
    | hb_apply ([c] (const Sequence &_) { _.collect_glyphs (c); })
385
    ;
386 387
  }

388
  const Coverage &get_coverage () const { return this+coverage; }
389

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

393
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
394
  {
B
Behdad Esfahbod 已提交
395
    TRACE_APPLY (this);
396

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

B
Behdad Esfahbod 已提交
400
    return_trace ((this+sequence[index]).apply (c));
401
  }
B
Behdad Esfahbod 已提交
402

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

422
  bool subset (hb_subset_context_t *c) const
423 424 425 426 427 428
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

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

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

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

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

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

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

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

494
  bool apply (hb_ot_apply_context_t *c) const
495 496 497 498 499 500
  {
    TRACE_APPLY (this);
    unsigned int count = alternates.len;

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

501 502
    hb_mask_t glyph_mask = c->buffer->cur().mask;
    hb_mask_t lookup_mask = c->lookup_mask;
503

504 505 506
    /* 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);
507

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

512 513
    if (unlikely (alt_index > count || alt_index == 0)) return_trace (false);

514 515
    c->replace_glyph (alternates[alt_index - 1]);

516 517 518
    return_trace (true);
  }

519 520
  template <typename Iterator,
	    hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
521
  bool serialize (hb_serialize_context_t *c,
522
		  Iterator alts)
523 524
  {
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
525
    return_trace (alternates.serialize (c, alts));
526 527
  }

528
  bool sanitize (hb_sanitize_context_t *c) const
529 530 531 532 533 534 535 536
  {
    TRACE_SANITIZE (this);
    return_trace (alternates.sanitize (c));
  }

  protected:
  ArrayOf<GlyphID>
		alternates;		/* Array of alternate GlyphIDs--in
B
Behdad Esfahbod 已提交
537
					 * arbitrary order */
538 539 540
  public:
  DEFINE_SIZE_ARRAY (2, alternates);
};
B
Behdad Esfahbod 已提交
541

B
Behdad Esfahbod 已提交
542 543
struct AlternateSubstFormat1
{
544
  bool intersects (const hb_set_t *glyphs) const
545 546
  { return (this+coverage).intersects (glyphs); }

547
  void closure (hb_closure_context_t *c) const
548
  {
549 550
    + hb_zip (this+coverage, alternateSet)
    | hb_map (hb_second)
551 552
    | hb_map (hb_add (this))
    | hb_apply ([c] (const AlternateSet &_) { _.closure (c); })
553
    ;
554 555
  }

556
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
557
  {
558
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
559 560
    + hb_zip (this+coverage, alternateSet)
    | hb_map (hb_second)
561 562
    | hb_map (hb_add (this))
    | hb_apply ([c] (const AlternateSet &_) { _.collect_glyphs (c); })
563
    ;
564 565
  }

566
  const Coverage &get_coverage () const { return this+coverage; }
567

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

571
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
572
  {
B
Behdad Esfahbod 已提交
573
    TRACE_APPLY (this);
574

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

578
    return_trace ((this+alternateSet[index]).apply (c));
579
  }
B
Behdad Esfahbod 已提交
580

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

600
  bool subset (hb_subset_context_t *c) const
601 602 603 604 605 606
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

607
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
608
  {
B
Behdad Esfahbod 已提交
609
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
610
    return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
611 612
  }

613
  protected:
B
Behdad Esfahbod 已提交
614
  HBUINT16	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
615 616
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
617
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
618 619 620
  OffsetArrayOf<AlternateSet>
		alternateSet;		/* Array of AlternateSet tables
					 * ordered by Coverage Index */
621
  public:
622
  DEFINE_SIZE_ARRAY (6, alternateSet);
B
Behdad Esfahbod 已提交
623
};
624

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

642
  template <typename context_t, typename ...Ts>
B
Behdad Esfahbod 已提交
643
  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
B
Behdad Esfahbod 已提交
644
  {
645
    TRACE_DISPATCH (this, u.format);
646
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
647
    switch (u.format) {
648
    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
B
Behdad Esfahbod 已提交
649
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
650 651 652
    }
  }

653
  protected:
654
  union {
B
Behdad Esfahbod 已提交
655
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
656
  AlternateSubstFormat1	format1;
657 658 659
  } u;
};

660

B
Behdad Esfahbod 已提交
661 662
struct Ligature
{
663
  bool intersects (const hb_set_t *glyphs) const
664
  {
665
    unsigned int count = component.lenP1;
666 667
    for (unsigned int i = 1; i < count; i++)
      if (!glyphs->has (component[i]))
B
Behdad Esfahbod 已提交
668
	return false;
669 670 671
    return true;
  }

672
  void closure (hb_closure_context_t *c) const
673
  {
B
Behdad Esfahbod 已提交
674
    if (!intersects (c->glyphs)) return;
B
Behdad Esfahbod 已提交
675
    c->output->add (ligGlyph);
676 677
  }

678
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
679
  {
680
    c->input->add_array (component.arrayZ, component.lenP1 ? component.lenP1 - 1 : 0);
B
Minor  
Behdad Esfahbod 已提交
681
    c->output->add (ligGlyph);
682 683
  }

684
  bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
685
  {
686
    if (c->len != component.lenP1)
B
Behdad Esfahbod 已提交
687
      return false;
688 689 690

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

B
Behdad Esfahbod 已提交
693
    return true;
B
Behdad Esfahbod 已提交
694 695
  }

696
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
697
  {
B
Behdad Esfahbod 已提交
698
    TRACE_APPLY (this);
699
    unsigned int count = component.lenP1;
B
Behdad Esfahbod 已提交
700

B
Behdad Esfahbod 已提交
701
    if (unlikely (!count)) return_trace (false);
B
Behdad Esfahbod 已提交
702

703 704 705 706 707
    /* 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 已提交
708
      return_trace (true);
709 710
    }

B
Behdad Esfahbod 已提交
711
    unsigned int total_component_count = 0;
712

713
    unsigned int match_length = 0;
714
    unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
715

716 717 718
    if (likely (!match_input (c, count,
			      &component[1],
			      match_glyph,
B
Behdad Esfahbod 已提交
719
			      nullptr,
720 721
			      &match_length,
			      match_positions,
722
			      &total_component_count)))
B
Behdad Esfahbod 已提交
723
      return_trace (false);
724

725 726
    ligate_input (c,
		  count,
727 728
		  match_positions,
		  match_length,
729
		  ligGlyph,
730
		  total_component_count);
731

B
Behdad Esfahbod 已提交
732
    return_trace (true);
733
  }
734

735 736
  template <typename Iterator,
	    hb_requires (hb_is_source_of (Iterator, hb_codepoint_t))>
737 738
  bool serialize (hb_serialize_context_t *c,
		  GlyphID ligature,
739
		  Iterator components /* Starting from second */)
740
  {
B
Behdad Esfahbod 已提交
741
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
742
    if (unlikely (!c->extend_min (*this))) return_trace (false);
743
    ligGlyph = ligature;
B
Behdad Esfahbod 已提交
744
    if (unlikely (!component.serialize (c, components))) return_trace (false);
B
Behdad Esfahbod 已提交
745
    return_trace (true);
746 747
  }

B
Behdad Esfahbod 已提交
748
  public:
749
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
750
  {
B
Behdad Esfahbod 已提交
751
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
752
    return_trace (ligGlyph.sanitize (c) && component.sanitize (c));
B
Behdad Esfahbod 已提交
753 754
  }

755
  protected:
756
  GlyphID	ligGlyph;		/* GlyphID of ligature to substitute */
B
Behdad Esfahbod 已提交
757 758
  HeadlessArrayOf<GlyphID>
		component;		/* Array of component GlyphIDs--start
759 760
					 * with the second  component--ordered
					 * in writing direction */
761
  public:
762
  DEFINE_SIZE_ARRAY (4, component);
763
};
B
Behdad Esfahbod 已提交
764

B
Behdad Esfahbod 已提交
765 766
struct LigatureSet
{
767
  bool intersects (const hb_set_t *glyphs) const
768
  {
B
Behdad Esfahbod 已提交
769 770
    return
    + hb_iter (ligature)
771 772
    | hb_map (hb_add (this))
    | hb_map ([glyphs] (const Ligature &_) { return _.intersects (glyphs); })
B
Behdad Esfahbod 已提交
773 774
    | hb_any
    ;
775 776
  }

777
  void closure (hb_closure_context_t *c) const
778
  {
B
Behdad Esfahbod 已提交
779
    + hb_iter (ligature)
780 781
    | hb_map (hb_add (this))
    | hb_apply ([c] (const Ligature &_) { _.closure (c); })
B
Behdad Esfahbod 已提交
782
    ;
783 784
  }

785
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
786
  {
B
Behdad Esfahbod 已提交
787
    + hb_iter (ligature)
788 789
    | hb_map (hb_add (this))
    | hb_apply ([c] (const Ligature &_) { _.collect_glyphs (c); })
B
Behdad Esfahbod 已提交
790
    ;
791 792
  }

793
  bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
794
  {
B
Behdad Esfahbod 已提交
795 796
    return
    + hb_iter (ligature)
797 798
    | hb_map (hb_add (this))
    | hb_map ([c] (const Ligature &_) { return _.would_apply (c); })
B
Behdad Esfahbod 已提交
799 800
    | hb_any
    ;
B
Behdad Esfahbod 已提交
801 802
  }

803
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
804
  {
B
Behdad Esfahbod 已提交
805
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
806
    unsigned int num_ligs = ligature.len;
B
Behdad Esfahbod 已提交
807 808
    for (unsigned int i = 0; i < num_ligs; i++)
    {
B
Behdad Esfahbod 已提交
809
      const Ligature &lig = this+ligature[i];
B
Behdad Esfahbod 已提交
810
      if (lig.apply (c)) return_trace (true);
811 812
    }

B
Behdad Esfahbod 已提交
813
    return_trace (false);
814
  }
B
Behdad Esfahbod 已提交
815

816
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
817 818
		  hb_array_t<const GlyphID> ligatures,
		  hb_array_t<const unsigned int> component_count_list,
819
		  hb_array_t<const GlyphID> &component_list /* Starting from second for each ligature */)
820
  {
B
Behdad Esfahbod 已提交
821
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
822
    if (unlikely (!c->extend_min (*this))) return_trace (false);
823 824
    if (unlikely (!ligature.serialize (c, ligatures.length))) return_trace (false);
    for (unsigned int i = 0; i < ligatures.length; i++)
B
Behdad Esfahbod 已提交
825
    {
826
      unsigned int component_count = (unsigned) hb_max ((int) component_count_list[i] - 1, 0);
B
Behdad Esfahbod 已提交
827 828 829 830 831 832 833
      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 已提交
834
    return_trace (true);
835 836
  }

837
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
838
  {
B
Behdad Esfahbod 已提交
839
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
840
    return_trace (ligature.sanitize (c, this));
B
Behdad Esfahbod 已提交
841 842
  }

843
  protected:
B
Behdad Esfahbod 已提交
844 845 846
  OffsetArrayOf<Ligature>
		ligature;		/* Array LigatureSet tables
					 * ordered by preference */
847
  public:
848
  DEFINE_SIZE_ARRAY (2, ligature);
B
Behdad Esfahbod 已提交
849 850
};

B
Behdad Esfahbod 已提交
851 852
struct LigatureSubstFormat1
{
853
  bool intersects (const hb_set_t *glyphs) const
854
  {
855 856 857 858
    return
    + hb_zip (this+coverage, ligatureSet)
    | hb_filter (*glyphs, hb_first)
    | hb_map (hb_second)
B
Behdad Esfahbod 已提交
859
    | hb_map ([this, glyphs] (const OffsetTo<LigatureSet> &_)
860 861 862
	      { return (this+_).intersects (glyphs); })
    | hb_any
    ;
863 864
  }

865
  void closure (hb_closure_context_t *c) const
866
  {
867 868 869
    + hb_zip (this+coverage, ligatureSet)
    | hb_filter (*c->glyphs, hb_first)
    | hb_map (hb_second)
870 871
    | hb_map (hb_add (this))
    | hb_apply ([c] (const LigatureSet &_) { _.closure (c); })
872
    ;
873 874
  }

875
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
876
  {
877
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
B
Behdad Esfahbod 已提交
878

879 880
    + hb_zip (this+coverage, ligatureSet)
    | hb_map (hb_second)
881 882
    | hb_map (hb_add (this))
    | hb_apply ([c] (const LigatureSet &_) { _.collect_glyphs (c); })
883
    ;
884 885
  }

886
  const Coverage &get_coverage () const { return this+coverage; }
887

888
  bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
889
  {
890
    unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
B
Behdad Esfahbod 已提交
891
    if (likely (index == NOT_COVERED)) return false;
892 893

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

897
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
898
  {
B
Behdad Esfahbod 已提交
899
    TRACE_APPLY (this);
900

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

B
Behdad Esfahbod 已提交
904
    const LigatureSet &lig_set = this+ligatureSet[index];
B
Behdad Esfahbod 已提交
905
    return_trace (lig_set.apply (c));
906
  }
B
Behdad Esfahbod 已提交
907

908
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
909
		  hb_sorted_array_t<const GlyphID> first_glyphs,
B
Behdad Esfahbod 已提交
910 911 912 913
		  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 */)
914
  {
B
Behdad Esfahbod 已提交
915
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
916
    if (unlikely (!c->extend_min (*this))) return_trace (false);
917 918
    if (unlikely (!ligatureSet.serialize (c, first_glyphs.length))) return_trace (false);
    for (unsigned int i = 0; i < first_glyphs.length; i++)
B
Behdad Esfahbod 已提交
919 920 921 922 923 924 925 926 927 928 929
    {
      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));
930 931
  }

932
  bool subset (hb_subset_context_t *c) const
933 934 935 936 937 938
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

939
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
940
  {
B
Behdad Esfahbod 已提交
941
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
942
    return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
943 944
  }

945
  protected:
B
Behdad Esfahbod 已提交
946
  HBUINT16	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
947 948
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
949
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
950
  OffsetArrayOf<LigatureSet>
B
Behdad Esfahbod 已提交
951 952
		ligatureSet;		/* Array LigatureSet tables
					 * ordered by Coverage Index */
953
  public:
954
  DEFINE_SIZE_ARRAY (6, ligatureSet);
B
Behdad Esfahbod 已提交
955
};
956

B
Behdad Esfahbod 已提交
957 958
struct LigatureSubst
{
959
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
960
		  hb_sorted_array_t<const GlyphID> first_glyphs,
B
Behdad Esfahbod 已提交
961 962 963 964
		  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 */)
965
  {
B
Behdad Esfahbod 已提交
966
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
967
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
968
    unsigned int format = 1;
969
    u.format = format;
970
    switch (u.format) {
B
Behdad Esfahbod 已提交
971 972 973 974 975 976 977
    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);
978 979 980
    }
  }

981
  template <typename context_t, typename ...Ts>
B
Behdad Esfahbod 已提交
982
  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
B
Behdad Esfahbod 已提交
983
  {
984
    TRACE_DISPATCH (this, u.format);
985
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
986
    switch (u.format) {
987
    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
B
Behdad Esfahbod 已提交
988
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
989 990 991
    }
  }

992
  protected:
993
  union {
B
Behdad Esfahbod 已提交
994
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
995
  LigatureSubstFormat1	format1;
996 997 998
  } u;
};

B
Behdad Esfahbod 已提交
999

B
Minor  
Behdad Esfahbod 已提交
1000
struct ContextSubst : Context {};
B
Behdad Esfahbod 已提交
1001

B
Minor  
Behdad Esfahbod 已提交
1002
struct ChainContextSubst : ChainContext {};
1003

B
Behdad Esfahbod 已提交
1004
struct ExtensionSubst : Extension<ExtensionSubst>
B
Behdad Esfahbod 已提交
1005
{
B
Behdad Esfahbod 已提交
1006
  typedef struct SubstLookupSubTable SubTable;
B
Behdad Esfahbod 已提交
1007

1008
  bool is_reverse () const;
1009 1010 1011
};


B
Behdad Esfahbod 已提交
1012 1013
struct ReverseChainSingleSubstFormat1
{
1014
  bool intersects (const hb_set_t *glyphs) const
1015 1016 1017 1018
  {
    if (!(this+coverage).intersects (glyphs))
      return false;

1019
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
1020 1021 1022 1023 1024 1025

    unsigned int count;

    count = backtrack.len;
    for (unsigned int i = 0; i < count; i++)
      if (!(this+backtrack[i]).intersects (glyphs))
B
Behdad Esfahbod 已提交
1026
	return false;
1027 1028 1029 1030

    count = lookahead.len;
    for (unsigned int i = 0; i < count; i++)
      if (!(this+lookahead[i]).intersects (glyphs))
B
Behdad Esfahbod 已提交
1031
	return false;
1032 1033 1034 1035

    return true;
  }

1036
  void closure (hb_closure_context_t *c) const
1037
  {
B
Behdad Esfahbod 已提交
1038
    if (!intersects (c->glyphs)) return;
B
Behdad Esfahbod 已提交
1039

1040 1041
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID>> (lookahead);
B
Behdad Esfahbod 已提交
1042

B
Behdad Esfahbod 已提交
1043 1044 1045
    + hb_zip (this+coverage, substitute)
    | hb_filter (*c->glyphs, hb_first)
    | hb_map (hb_second)
1046
    | hb_sink (c->output)
1047
    ;
1048 1049
  }

1050
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
1051
  {
1052
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
1053 1054 1055 1056 1057

    unsigned int count;

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

1060
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
1061 1062
    count = lookahead.len;
    for (unsigned int i = 0; i < count; i++)
1063
      if (unlikely (!(this+lookahead[i]).add_coverage (c->after))) return;
1064

1065
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID>> (lookahead);
1066
    count = substitute.len;
1067
    c->output->add_array (substitute.arrayZ, substitute.len);
1068 1069
  }

1070
  const Coverage &get_coverage () const { return this+coverage; }
1071

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

1075
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1076
  {
B
Behdad Esfahbod 已提交
1077
    TRACE_APPLY (this);
1078
    if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
B
Behdad Esfahbod 已提交
1079
      return_trace (false); /* No chaining to this type */
1080

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

1084 1085
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID>> (lookahead);
1086

1087
  unsigned int start_index = 0, end_index = 0;
B
Behdad Esfahbod 已提交
1088
    if (match_backtrack (c,
1089
			 backtrack.len, (HBUINT16 *) backtrack.arrayZ,
1090 1091
			 match_coverage, this,
			 &start_index) &&
B
Behdad Esfahbod 已提交
1092
	match_lookahead (c,
1093
			 lookahead.len, (HBUINT16 *) lookahead.arrayZ,
B
Behdad Esfahbod 已提交
1094
			 match_coverage, this,
1095
			 1, &end_index))
1096
    {
1097
      c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index);
B
Behdad Esfahbod 已提交
1098
      c->replace_glyph_inplace (substitute[index]);
1099 1100 1101
      /* 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 已提交
1102
      return_trace (true);
1103 1104
    }

B
Behdad Esfahbod 已提交
1105
    return_trace (false);
1106
  }
B
Behdad Esfahbod 已提交
1107

1108
  bool subset (hb_subset_context_t *c) const
1109 1110 1111 1112 1113 1114
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

1115
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
1116
  {
B
Behdad Esfahbod 已提交
1117
    TRACE_SANITIZE (this);
1118
    if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
B
Behdad Esfahbod 已提交
1119
      return_trace (false);
1120
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
B
Behdad Esfahbod 已提交
1121
    if (!lookahead.sanitize (c, this))
B
Behdad Esfahbod 已提交
1122
      return_trace (false);
1123
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID>> (lookahead);
B
Behdad Esfahbod 已提交
1124
    return_trace (substitute.sanitize (c));
B
Behdad Esfahbod 已提交
1125 1126
  }

1127
  protected:
B
Behdad Esfahbod 已提交
1128
  HBUINT16	format;			/* Format identifier--format = 1 */
1129 1130 1131 1132 1133
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of table */
  OffsetArrayOf<Coverage>
		backtrack;		/* Array of coverage tables
1134
					 * in backtracking sequence, in glyph
B
Behdad Esfahbod 已提交
1135
					 * sequence order */
1136 1137 1138
  OffsetArrayOf<Coverage>
		lookaheadX;		/* Array of coverage tables
					 * in lookahead sequence, in glyph
B
Behdad Esfahbod 已提交
1139
					 * sequence order */
1140 1141 1142
  ArrayOf<GlyphID>
		substituteX;		/* Array of substitute
					 * GlyphIDs--ordered by Coverage Index */
1143
  public:
B
Behdad Esfahbod 已提交
1144
  DEFINE_SIZE_MIN (10);
B
Behdad Esfahbod 已提交
1145 1146
};

B
Behdad Esfahbod 已提交
1147 1148
struct ReverseChainSingleSubst
{
1149
  template <typename context_t, typename ...Ts>
B
Behdad Esfahbod 已提交
1150
  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
1151
  {
1152
    TRACE_DISPATCH (this, u.format);
1153
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1154
    switch (u.format) {
1155
    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
B
Behdad Esfahbod 已提交
1156
    default:return_trace (c->default_return_value ());
1157 1158 1159
    }
  }

1160
  protected:
1161
  union {
B
Behdad Esfahbod 已提交
1162
  HBUINT16				format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1163
  ReverseChainSingleSubstFormat1	format1;
1164 1165 1166 1167 1168
  } u;
};



B
Behdad Esfahbod 已提交
1169 1170 1171 1172
/*
 * SubstLookup
 */

B
Behdad Esfahbod 已提交
1173 1174
struct SubstLookupSubTable
{
B
Behdad Esfahbod 已提交
1175
  friend struct Lookup;
B
Behdad Esfahbod 已提交
1176 1177
  friend struct SubstLookup;

B
Behdad Esfahbod 已提交
1178
  enum Type {
1179 1180 1181 1182 1183 1184 1185
    Single		= 1,
    Multiple		= 2,
    Alternate		= 3,
    Ligature		= 4,
    Context		= 5,
    ChainContext	= 6,
    Extension		= 7,
1186
    ReverseChainSingle	= 8
1187 1188
  };

1189
  template <typename context_t, typename ...Ts>
B
Behdad Esfahbod 已提交
1190
  typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type, Ts&&... ds) const
1191
  {
1192
    TRACE_DISPATCH (this, lookup_type);
1193
    switch (lookup_type) {
1194 1195 1196 1197 1198 1199 1200 1201
    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 已提交
1202
    default:			return_trace (c->default_return_value ());
1203 1204 1205
    }
  }

1206
  protected:
B
Behdad Esfahbod 已提交
1207
  union {
B
Behdad Esfahbod 已提交
1208 1209 1210 1211
  SingleSubst			single;
  MultipleSubst			multiple;
  AlternateSubst		alternate;
  LigatureSubst			ligature;
1212
  ContextSubst			context;
B
Behdad Esfahbod 已提交
1213 1214 1215
  ChainContextSubst		chainContext;
  ExtensionSubst		extension;
  ReverseChainSingleSubst	reverseChainContextSingle;
B
Behdad Esfahbod 已提交
1216
  } u;
B
Behdad Esfahbod 已提交
1217
  public:
B
Behdad Esfahbod 已提交
1218
  DEFINE_SIZE_MIN (0);
B
Behdad Esfahbod 已提交
1219 1220
};

1221

B
Behdad Esfahbod 已提交
1222 1223
struct SubstLookup : Lookup
{
B
Behdad Esfahbod 已提交
1224 1225
  typedef SubstLookupSubTable SubTable;

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

B
Behdad Esfahbod 已提交
1229
  HB_INTERNAL static bool lookup_type_is_reverse (unsigned int lookup_type)
B
Behdad Esfahbod 已提交
1230
  { return lookup_type == SubTable::ReverseChainSingle; }
B
Behdad Esfahbod 已提交
1231

1232
  bool is_reverse () const
B
Behdad Esfahbod 已提交
1233
  {
B
Behdad Esfahbod 已提交
1234
    unsigned int type = get_type ();
B
Behdad Esfahbod 已提交
1235
    if (unlikely (type == SubTable::Extension))
1236
      return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
B
Behdad Esfahbod 已提交
1237
    return lookup_type_is_reverse (type);
B
Behdad Esfahbod 已提交
1238
  }
1239

1240
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1241 1242
  {
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
1243
    return_trace (dispatch (c));
B
Behdad Esfahbod 已提交
1244 1245
  }

1246
  bool intersects (const hb_set_t *glyphs) const
1247 1248 1249 1250 1251
  {
    hb_intersects_context_t c (glyphs);
    return dispatch (&c);
  }

1252
  hb_closure_context_t::return_t closure (hb_closure_context_t *c, unsigned int this_index) const
1253
  {
1254
    if (!c->should_visit_lookup (this_index))
B
Behdad Esfahbod 已提交
1255
      return hb_closure_context_t::default_return_value ();
1256 1257

    c->set_recurse_func (dispatch_closure_recurse_func);
1258 1259 1260 1261 1262

    hb_closure_context_t::return_t ret = dispatch (c);

    c->flush ();

B
Behdad Esfahbod 已提交
1263
    return ret;
B
Behdad Esfahbod 已提交
1264 1265
  }

1266
  hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
B
Behdad Esfahbod 已提交
1267
  {
1268
    c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
B
Behdad Esfahbod 已提交
1269
    return dispatch (c);
1270 1271
  }

B
Behdad Esfahbod 已提交
1272
  template <typename set_t>
1273
  void add_coverage (set_t *glyphs) const
B
Behdad Esfahbod 已提交
1274
  {
1275 1276
    hb_add_coverage_context_t<set_t> c (glyphs);
    dispatch (&c);
B
Behdad Esfahbod 已提交
1277 1278
  }

1279 1280
  bool would_apply (hb_would_apply_context_t *c,
		    const hb_ot_layout_lookup_accelerator_t *accel) const
B
Behdad Esfahbod 已提交
1281
  {
B
Behdad Esfahbod 已提交
1282 1283 1284
    if (unlikely (!c->len)) return false;
    if (!accel->may_have (c->glyphs[0])) return false;
      return dispatch (c);
B
Behdad Esfahbod 已提交
1285 1286
  }

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

1289
  SubTable& serialize_subtable (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
1290
				unsigned int i)
B
Behdad Esfahbod 已提交
1291
  { return get_subtables<SubTable> ()[i].serialize (c, this); }
1292

1293 1294
  bool serialize_single (hb_serialize_context_t *c,
			 uint32_t lookup_props,
B
Behdad Esfahbod 已提交
1295 1296
			 hb_sorted_array_t<const GlyphID> glyphs,
			 hb_array_t<const GlyphID> substitutes)
1297
  {
B
Behdad Esfahbod 已提交
1298
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1299
    if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1300 1301
    return_trace (serialize_subtable (c, 0).u.single.
		  serialize (c, hb_zip (glyphs, substitutes)));
1302 1303
  }

1304 1305
  bool serialize_multiple (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> substitute_len_list,
			   hb_array_t<const GlyphID> substitute_glyphs_list)
1309
  {
B
Behdad Esfahbod 已提交
1310
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1311
    if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1312 1313 1314 1315 1316
    return_trace (serialize_subtable (c, 0).u.multiple.
		  serialize (c,
			     glyphs,
			     substitute_len_list,
			     substitute_glyphs_list));
1317 1318
  }

1319 1320
  bool serialize_alternate (hb_serialize_context_t *c,
			    uint32_t lookup_props,
B
Behdad Esfahbod 已提交
1321
			    hb_sorted_array_t<const GlyphID> glyphs,
B
Behdad Esfahbod 已提交
1322 1323
			    hb_array_t<const unsigned int> alternate_len_list,
			    hb_array_t<const GlyphID> alternate_glyphs_list)
1324
  {
B
Behdad Esfahbod 已提交
1325
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1326
    if (unlikely (!Lookup::serialize (c, SubTable::Alternate, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1327 1328 1329 1330 1331
    return_trace (serialize_subtable (c, 0).u.alternate.
		  serialize (c,
			     glyphs,
			     alternate_len_list,
			     alternate_glyphs_list));
1332 1333
  }

1334 1335
  bool serialize_ligature (hb_serialize_context_t *c,
			   uint32_t lookup_props,
B
Behdad Esfahbod 已提交
1336
			   hb_sorted_array_t<const GlyphID> first_glyphs,
B
Behdad Esfahbod 已提交
1337 1338 1339 1340
			   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 */)
1341
  {
B
Behdad Esfahbod 已提交
1342
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1343
    if (unlikely (!Lookup::serialize (c, SubTable::Ligature, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1344 1345 1346 1347 1348 1349 1350
    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));
1351 1352
  }

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

B
Behdad Esfahbod 已提交
1356
  HB_INTERNAL static hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned int lookup_index)
1357
  {
1358
    if (!c->should_visit_lookup (lookup_index))
B
Behdad Esfahbod 已提交
1359
      return hb_empty_t ();
1360 1361 1362

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

1363 1364 1365 1366
    /* 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 ();
1367 1368

    return ret;
1369 1370
  }

1371
  template <typename context_t, typename ...Ts>
B
Behdad Esfahbod 已提交
1372
  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
1373
  { return Lookup::dispatch<SubTable> (c, hb_forward<Ts> (ds)...); }
B
Behdad Esfahbod 已提交
1374

1375
  bool subset (hb_subset_context_t *c) const
1376
  { return Lookup::subset<SubTable> (c); }
B
Behdad Esfahbod 已提交
1377

1378
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
1379
  { return Lookup::sanitize<SubTable> (c); }
B
Behdad Esfahbod 已提交
1380 1381
};

B
Minor  
Behdad Esfahbod 已提交
1382
/*
1383 1384
 * GSUB -- Glyph Substitution
 * https://docs.microsoft.com/en-us/typography/opentype/spec/gsub
B
Minor  
Behdad Esfahbod 已提交
1385 1386
 */

B
Behdad Esfahbod 已提交
1387 1388
struct GSUB : GSUBGPOS
{
1389
  static constexpr hb_tag_t tableTag = HB_OT_TAG_GSUB;
B
Minor  
Behdad Esfahbod 已提交
1390

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

1394
  bool subset (hb_subset_context_t *c) const
1395
  { return GSUBGPOS::subset<SubstLookup> (c); }
1396

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

1400 1401 1402
  HB_INTERNAL bool is_blacklisted (hb_blob_t *blob,
				   hb_face_t *face) const;

B
WIP  
Behdad Esfahbod 已提交
1403
  typedef GSUBGPOS::accelerator_t<GSUB> accelerator_t;
B
Minor  
Behdad Esfahbod 已提交
1404
};
1405 1406


B
Behdad Esfahbod 已提交
1407 1408 1409
struct GSUB_accelerator_t : GSUB::accelerator_t {};


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

1412
#ifndef HB_NO_OT_LAYOUT
1413
/*static*/ inline bool ExtensionSubst::is_reverse () const
B
Behdad Esfahbod 已提交
1414 1415
{
  unsigned int type = get_type ();
B
Behdad Esfahbod 已提交
1416 1417
  if (unlikely (type == SubTable::Extension))
    return CastR<ExtensionSubst> (get_subtable<SubTable>()).is_reverse ();
B
Behdad Esfahbod 已提交
1418 1419
  return SubstLookup::lookup_type_is_reverse (type);
}
1420
template <typename context_t>
1421
/*static*/ inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
1422
{
B
Behdad Esfahbod 已提交
1423
  const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index);
1424
  return l.dispatch (c);
1425
}
1426
/*static*/ inline bool SubstLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index)
B
Behdad Esfahbod 已提交
1427
{
B
Behdad Esfahbod 已提交
1428
  const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index);
1429
  unsigned int saved_lookup_props = c->lookup_props;
1430 1431 1432
  unsigned int saved_lookup_index = c->lookup_index;
  c->set_lookup_index (lookup_index);
  c->set_lookup_props (l.get_props ());
1433
  bool ret = l.dispatch (c);
1434
  c->set_lookup_index (saved_lookup_index);
1435
  c->set_lookup_props (saved_lookup_props);
1436
  return ret;
1437
}
1438 1439
#endif

1440

B
Behdad Esfahbod 已提交
1441
} /* namespace OT */
1442

B
Behdad Esfahbod 已提交
1443

1444
#endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */