hb-ot-layout-gsub-table.hh 41.6 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-private.hh"
B
Behdad Esfahbod 已提交
33

B
Behdad Esfahbod 已提交
34

35 36
namespace OT {

37

B
Behdad Esfahbod 已提交
38 39
struct SingleSubstFormat1
{
B
Behdad Esfahbod 已提交
40
  inline void closure (hb_closure_context_t *c) const
41
  {
B
Behdad Esfahbod 已提交
42
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
43
    Coverage::Iter iter;
44 45 46 47
    for (iter.init (this+coverage); iter.more (); iter.next ())
    {
      /* TODO Switch to range-based API to work around malicious fonts.
       * https://github.com/behdad/harfbuzz/issues/363 */
B
Behdad Esfahbod 已提交
48 49
      hb_codepoint_t glyph_id = iter.get_glyph ();
      if (c->glyphs->has (glyph_id))
50
	c->glyphs->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
B
Behdad Esfahbod 已提交
51
    }
52 53
  }

54 55
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
56
    TRACE_COLLECT_GLYPHS (this);
57
    Coverage::Iter iter;
58 59 60 61
    for (iter.init (this+coverage); iter.more (); iter.next ())
    {
      /* TODO Switch to range-based API to work around malicious fonts.
       * https://github.com/behdad/harfbuzz/issues/363 */
62
      hb_codepoint_t glyph_id = iter.get_glyph ();
B
Minor  
Behdad Esfahbod 已提交
63
      c->input->add (glyph_id);
64
      c->output->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
65 66 67
    }
  }

68 69 70 71 72
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

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

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

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

B
Behdad Esfahbod 已提交
91
    return_trace (true);
92
  }
B
Behdad Esfahbod 已提交
93

94
  inline bool serialize (hb_serialize_context_t *c,
95
			 Supplier<GlyphID> &glyphs,
96
			 unsigned int num_glyphs,
B
Minor  
Behdad Esfahbod 已提交
97
			 int delta)
98
  {
B
Behdad Esfahbod 已提交
99
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
100 101
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
B
Minor  
Behdad Esfahbod 已提交
102
    deltaGlyphID.set (delta); /* TODO(serilaize) overflow? */
B
Behdad Esfahbod 已提交
103
    return_trace (true);
104 105
  }

B
Behdad Esfahbod 已提交
106 107
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
108
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
109
    return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
B
Behdad Esfahbod 已提交
110 111
  }

112
  protected:
B
Behdad Esfahbod 已提交
113
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
114 115
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
116 117 118
					 * beginning of Substitution table */
  SHORT		deltaGlyphID;		/* Add to original GlyphID to get
					 * substitute GlyphID */
119 120
  public:
  DEFINE_SIZE_STATIC (6);
B
Behdad Esfahbod 已提交
121 122
};

B
Behdad Esfahbod 已提交
123 124
struct SingleSubstFormat2
{
B
Behdad Esfahbod 已提交
125
  inline void closure (hb_closure_context_t *c) const
126
  {
B
Behdad Esfahbod 已提交
127
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
128
    Coverage::Iter iter;
129 130 131 132 133
    unsigned int count = substitute.len;
    for (iter.init (this+coverage); iter.more (); iter.next ())
    {
      if (unlikely (iter.get_coverage () >= count))
        break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
B
Behdad Esfahbod 已提交
134
      if (c->glyphs->has (iter.get_glyph ()))
B
Behdad Esfahbod 已提交
135
	c->glyphs->add (substitute[iter.get_coverage ()]);
B
Behdad Esfahbod 已提交
136
    }
137 138
  }

139 140
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
141
    TRACE_COLLECT_GLYPHS (this);
142
    Coverage::Iter iter;
143 144 145 146 147
    unsigned int count = substitute.len;
    for (iter.init (this+coverage); iter.more (); iter.next ())
    {
      if (unlikely (iter.get_coverage () >= count))
        break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
B
Minor  
Behdad Esfahbod 已提交
148 149
      c->input->add (iter.get_glyph ());
      c->output->add (substitute[iter.get_coverage ()]);
150 151 152
    }
  }

153 154 155 156 157
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

158 159
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
160
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
161
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
162 163
  }

B
Behdad Esfahbod 已提交
164
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
165
  {
B
Behdad Esfahbod 已提交
166
    TRACE_APPLY (this);
167
    hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
168
    unsigned int index = (this+coverage).get_coverage (glyph_id);
B
Behdad Esfahbod 已提交
169
    if (likely (index == NOT_COVERED)) return_trace (false);
170

B
Behdad Esfahbod 已提交
171
    if (unlikely (index >= substitute.len)) return_trace (false);
172 173

    glyph_id = substitute[index];
174
    c->replace_glyph (glyph_id);
B
Behdad Esfahbod 已提交
175

B
Behdad Esfahbod 已提交
176
    return_trace (true);
177
  }
B
Behdad Esfahbod 已提交
178

B
Behdad Esfahbod 已提交
179
  inline bool serialize (hb_serialize_context_t *c,
180 181
			 Supplier<GlyphID> &glyphs,
			 Supplier<GlyphID> &substitutes,
B
Behdad Esfahbod 已提交
182 183
			 unsigned int num_glyphs)
  {
B
Behdad Esfahbod 已提交
184
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
185 186 187 188
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    if (unlikely (!substitute.serialize (c, substitutes, num_glyphs))) return_trace (false);
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
    return_trace (true);
B
Behdad Esfahbod 已提交
189 190
  }

B
Behdad Esfahbod 已提交
191 192
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
193
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
194
    return_trace (coverage.sanitize (c, this) && substitute.sanitize (c));
B
Behdad Esfahbod 已提交
195 196
  }

197
  protected:
B
Behdad Esfahbod 已提交
198
  USHORT	format;			/* Format identifier--format = 2 */
B
Behdad Esfahbod 已提交
199 200
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
201
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
202 203 204
  ArrayOf<GlyphID>
		substitute;		/* Array of substitute
					 * GlyphIDs--ordered by Coverage Index */
205
  public:
206
  DEFINE_SIZE_ARRAY (6, substitute);
B
Behdad Esfahbod 已提交
207 208
};

B
Behdad Esfahbod 已提交
209 210
struct SingleSubst
{
B
Behdad Esfahbod 已提交
211
  inline bool serialize (hb_serialize_context_t *c,
212 213
			 Supplier<GlyphID> &glyphs,
			 Supplier<GlyphID> &substitutes,
B
Behdad Esfahbod 已提交
214 215
			 unsigned int num_glyphs)
  {
B
Behdad Esfahbod 已提交
216
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
217
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
B
Behdad Esfahbod 已提交
218
    unsigned int format = 2;
B
Behdad Esfahbod 已提交
219
    int delta = 0;
B
Behdad Esfahbod 已提交
220 221
    if (num_glyphs) {
      format = 1;
B
Minor  
Behdad Esfahbod 已提交
222
      /* TODO(serialize) check for wrap-around */
B
Behdad Esfahbod 已提交
223 224 225 226 227 228 229 230 231
      delta = substitutes[0] - glyphs[0];
      for (unsigned int i = 1; i < num_glyphs; i++)
	if (delta != substitutes[i] - glyphs[i]) {
	  format = 2;
	  break;
	}
    }
    u.format.set (format);
    switch (u.format) {
B
Behdad Esfahbod 已提交
232 233 234
    case 1: return_trace (u.format1.serialize (c, glyphs, num_glyphs, delta));
    case 2: return_trace (u.format2.serialize (c, glyphs, substitutes, num_glyphs));
    default:return_trace (false);
B
Behdad Esfahbod 已提交
235 236 237
    }
  }

B
Behdad Esfahbod 已提交
238 239 240
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
  {
241
    TRACE_DISPATCH (this, u.format);
242
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
243
    switch (u.format) {
B
Behdad Esfahbod 已提交
244 245 246
    case 1: return_trace (c->dispatch (u.format1));
    case 2: return_trace (c->dispatch (u.format2));
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
247 248 249
    }
  }

250
  protected:
251
  union {
B
Behdad Esfahbod 已提交
252
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
253 254
  SingleSubstFormat1	format1;
  SingleSubstFormat2	format2;
255
  } u;
B
Behdad Esfahbod 已提交
256
};
257

B
Behdad Esfahbod 已提交
258

B
Behdad Esfahbod 已提交
259 260
struct Sequence
{
B
Behdad Esfahbod 已提交
261
  inline void closure (hb_closure_context_t *c) const
262
  {
B
Behdad Esfahbod 已提交
263
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
264 265
    unsigned int count = substitute.len;
    for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
266
      c->glyphs->add (substitute[i]);
267 268
  }

269 270
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
271
    TRACE_COLLECT_GLYPHS (this);
272 273
    unsigned int count = substitute.len;
    for (unsigned int i = 0; i < count; i++)
B
Minor  
Behdad Esfahbod 已提交
274
      c->output->add (substitute[i]);
275 276
  }

B
Behdad Esfahbod 已提交
277
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
278
  {
B
Behdad Esfahbod 已提交
279
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
280
    unsigned int count = substitute.len;
281

B
Behdad Esfahbod 已提交
282 283 284
    /* Special-case to make it in-place and not consider this
     * as a "multiplied" substitution. */
    if (unlikely (count == 1))
285 286
    {
      c->replace_glyph (substitute.array[0]);
B
Behdad Esfahbod 已提交
287
      return_trace (true);
288
    }
289 290 291 292 293 294 295
    /* Spec disallows this, but Uniscribe allows it.
     * https://github.com/behdad/harfbuzz/issues/253 */
    else if (unlikely (count == 0))
    {
      c->buffer->delete_glyph ();
      return_trace (true);
    }
B
Behdad Esfahbod 已提交
296 297 298 299 300 301

    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);
302
      c->output_glyph_for_component (substitute.array[i], klass);
303
    }
B
Behdad Esfahbod 已提交
304
    c->buffer->skip_glyph ();
B
Behdad Esfahbod 已提交
305

B
Behdad Esfahbod 已提交
306
    return_trace (true);
B
Behdad Esfahbod 已提交
307 308
  }

309
  inline bool serialize (hb_serialize_context_t *c,
310
			 Supplier<GlyphID> &glyphs,
311 312
			 unsigned int num_glyphs)
  {
B
Behdad Esfahbod 已提交
313
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
314 315 316
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    if (unlikely (!substitute.serialize (c, glyphs, num_glyphs))) return_trace (false);
    return_trace (true);
317 318
  }

B
Behdad Esfahbod 已提交
319 320
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
321
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
322
    return_trace (substitute.sanitize (c));
B
Behdad Esfahbod 已提交
323 324
  }

325
  protected:
B
Behdad Esfahbod 已提交
326 327
  ArrayOf<GlyphID>
		substitute;		/* String of GlyphIDs to substitute */
328
  public:
329
  DEFINE_SIZE_ARRAY (2, substitute);
B
Behdad Esfahbod 已提交
330 331
};

B
Behdad Esfahbod 已提交
332 333
struct MultipleSubstFormat1
{
B
Behdad Esfahbod 已提交
334
  inline void closure (hb_closure_context_t *c) const
335
  {
B
Behdad Esfahbod 已提交
336
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
337
    Coverage::Iter iter;
338 339 340 341 342
    unsigned int count = sequence.len;
    for (iter.init (this+coverage); iter.more (); iter.next ())
    {
      if (unlikely (iter.get_coverage () >= count))
        break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
B
Behdad Esfahbod 已提交
343
      if (c->glyphs->has (iter.get_glyph ()))
B
Behdad Esfahbod 已提交
344
	(this+sequence[iter.get_coverage ()]).closure (c);
B
Behdad Esfahbod 已提交
345
    }
346 347
  }

348 349
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
350
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
351
    (this+coverage).add_coverage (c->input);
352 353 354 355 356
    unsigned int count = sequence.len;
    for (unsigned int i = 0; i < count; i++)
	(this+sequence[i]).collect_glyphs (c);
  }

357 358 359 360 361
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

362 363
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
364
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
365
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
366 367
  }

B
Behdad Esfahbod 已提交
368
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
369
  {
B
Behdad Esfahbod 已提交
370
    TRACE_APPLY (this);
371

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

B
Behdad Esfahbod 已提交
375
    return_trace ((this+sequence[index]).apply (c));
376
  }
B
Behdad Esfahbod 已提交
377

378
  inline bool serialize (hb_serialize_context_t *c,
379 380
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &substitute_len_list,
381
			 unsigned int num_glyphs,
382
			 Supplier<GlyphID> &substitute_glyphs_list)
383
  {
B
Behdad Esfahbod 已提交
384
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
385 386
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    if (unlikely (!sequence.serialize (c, num_glyphs))) return_trace (false);
387 388 389
    for (unsigned int i = 0; i < num_glyphs; i++)
      if (unlikely (!sequence[i].serialize (c, this).serialize (c,
								substitute_glyphs_list,
B
Behdad Esfahbod 已提交
390
								substitute_len_list[i]))) return_trace (false);
391
    substitute_len_list.advance (num_glyphs);
B
Behdad Esfahbod 已提交
392 393
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
    return_trace (true);
394 395
  }

B
Behdad Esfahbod 已提交
396 397
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
398
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
399
    return_trace (coverage.sanitize (c, this) && sequence.sanitize (c, this));
B
Behdad Esfahbod 已提交
400 401
  }

402
  protected:
B
Behdad Esfahbod 已提交
403
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
404 405
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
406
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
407 408 409
  OffsetArrayOf<Sequence>
		sequence;		/* Array of Sequence tables
					 * ordered by Coverage Index */
410
  public:
411
  DEFINE_SIZE_ARRAY (6, sequence);
B
Behdad Esfahbod 已提交
412
};
413

B
Behdad Esfahbod 已提交
414 415
struct MultipleSubst
{
416
  inline bool serialize (hb_serialize_context_t *c,
417 418
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &substitute_len_list,
419
			 unsigned int num_glyphs,
420
			 Supplier<GlyphID> &substitute_glyphs_list)
421
  {
B
Behdad Esfahbod 已提交
422
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
423
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
424 425 426
    unsigned int format = 1;
    u.format.set (format);
    switch (u.format) {
B
Behdad Esfahbod 已提交
427 428
    case 1: return_trace (u.format1.serialize (c, glyphs, substitute_len_list, num_glyphs, substitute_glyphs_list));
    default:return_trace (false);
429 430 431
    }
  }

B
Behdad Esfahbod 已提交
432 433 434
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
  {
435
    TRACE_DISPATCH (this, u.format);
436
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
437
    switch (u.format) {
B
Behdad Esfahbod 已提交
438 439
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
440 441 442
    }
  }

443
  protected:
444
  union {
B
Behdad Esfahbod 已提交
445
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
446
  MultipleSubstFormat1	format1;
447 448 449
  } u;
};

B
Behdad Esfahbod 已提交
450

B
Behdad Esfahbod 已提交
451
typedef ArrayOf<GlyphID> AlternateSet;	/* Array of alternate GlyphIDs--in
B
Behdad Esfahbod 已提交
452 453
					 * arbitrary order */

B
Behdad Esfahbod 已提交
454 455
struct AlternateSubstFormat1
{
B
Behdad Esfahbod 已提交
456
  inline void closure (hb_closure_context_t *c) const
457
  {
B
Behdad Esfahbod 已提交
458
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
459
    Coverage::Iter iter;
460 461 462 463 464
    unsigned int count = alternateSet.len;
    for (iter.init (this+coverage); iter.more (); iter.next ())
    {
      if (unlikely (iter.get_coverage () >= count))
        break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
B
Behdad Esfahbod 已提交
465 466 467 468
      if (c->glyphs->has (iter.get_glyph ())) {
	const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
	unsigned int count = alt_set.len;
	for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
469
	  c->glyphs->add (alt_set[i]);
B
Behdad Esfahbod 已提交
470 471
      }
    }
472 473
  }

474 475
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
476
    TRACE_COLLECT_GLYPHS (this);
477
    Coverage::Iter iter;
478 479 480 481 482
    unsigned int count = alternateSet.len;
    for (iter.init (this+coverage); iter.more (); iter.next ())
    {
      if (unlikely (iter.get_coverage () >= count))
        break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
B
Minor  
Behdad Esfahbod 已提交
483
      c->input->add (iter.get_glyph ());
484 485 486
      const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
      unsigned int count = alt_set.len;
      for (unsigned int i = 0; i < count; i++)
B
Minor  
Behdad Esfahbod 已提交
487
	c->output->add (alt_set[i]);
488 489 490
    }
  }

491 492 493 494 495
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

496 497
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
498
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
499
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
500 501
  }

B
Behdad Esfahbod 已提交
502
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
503
  {
B
Behdad Esfahbod 已提交
504
    TRACE_APPLY (this);
505
    hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
506

507
    unsigned int index = (this+coverage).get_coverage (glyph_id);
B
Behdad Esfahbod 已提交
508
    if (likely (index == NOT_COVERED)) return_trace (false);
509

B
Behdad Esfahbod 已提交
510
    const AlternateSet &alt_set = this+alternateSet[index];
511

B
Behdad Esfahbod 已提交
512
    if (unlikely (!alt_set.len)) return_trace (false);
513

514
    hb_mask_t glyph_mask = c->buffer->cur().mask;
B
Behdad Esfahbod 已提交
515 516
    hb_mask_t lookup_mask = c->lookup_mask;

B
Behdad Esfahbod 已提交
517
    /* Note: This breaks badly if two features enabled this lookup together. */
B
Behdad Esfahbod 已提交
518
    unsigned int shift = _hb_ctz (lookup_mask);
B
Behdad Esfahbod 已提交
519
    unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
520

B
Behdad Esfahbod 已提交
521
    if (unlikely (alt_index > alt_set.len || alt_index == 0)) return_trace (false);
522

B
Behdad Esfahbod 已提交
523
    glyph_id = alt_set[alt_index - 1];
524

525
    c->replace_glyph (glyph_id);
526

B
Behdad Esfahbod 已提交
527
    return_trace (true);
528
  }
B
Behdad Esfahbod 已提交
529

530
  inline bool serialize (hb_serialize_context_t *c,
531 532
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &alternate_len_list,
533
			 unsigned int num_glyphs,
534
			 Supplier<GlyphID> &alternate_glyphs_list)
535
  {
B
Behdad Esfahbod 已提交
536
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
537 538
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    if (unlikely (!alternateSet.serialize (c, num_glyphs))) return_trace (false);
539 540 541
    for (unsigned int i = 0; i < num_glyphs; i++)
      if (unlikely (!alternateSet[i].serialize (c, this).serialize (c,
								    alternate_glyphs_list,
B
Behdad Esfahbod 已提交
542
								    alternate_len_list[i]))) return_trace (false);
543
    alternate_len_list.advance (num_glyphs);
B
Behdad Esfahbod 已提交
544 545
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
    return_trace (true);
546 547
  }

B
Behdad Esfahbod 已提交
548 549
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
550
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
551
    return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
552 553
  }

554
  protected:
B
Behdad Esfahbod 已提交
555
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
556 557
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
558
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
559 560 561
  OffsetArrayOf<AlternateSet>
		alternateSet;		/* Array of AlternateSet tables
					 * ordered by Coverage Index */
562
  public:
563
  DEFINE_SIZE_ARRAY (6, alternateSet);
B
Behdad Esfahbod 已提交
564
};
565

B
Behdad Esfahbod 已提交
566 567
struct AlternateSubst
{
568
  inline bool serialize (hb_serialize_context_t *c,
569 570
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &alternate_len_list,
571
			 unsigned int num_glyphs,
572
			 Supplier<GlyphID> &alternate_glyphs_list)
573
  {
B
Behdad Esfahbod 已提交
574
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
575
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
576 577 578
    unsigned int format = 1;
    u.format.set (format);
    switch (u.format) {
B
Behdad Esfahbod 已提交
579 580
    case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, num_glyphs, alternate_glyphs_list));
    default:return_trace (false);
581 582 583
    }
  }

B
Behdad Esfahbod 已提交
584 585 586
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
  {
587
    TRACE_DISPATCH (this, u.format);
588
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
589
    switch (u.format) {
B
Behdad Esfahbod 已提交
590 591
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
592 593 594
    }
  }

595
  protected:
596
  union {
B
Behdad Esfahbod 已提交
597
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
598
  AlternateSubstFormat1	format1;
599 600 601
  } u;
};

602

B
Behdad Esfahbod 已提交
603 604
struct Ligature
{
B
Behdad Esfahbod 已提交
605
  inline void closure (hb_closure_context_t *c) const
606
  {
B
Behdad Esfahbod 已提交
607
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
608 609 610
    unsigned int count = component.len;
    for (unsigned int i = 1; i < count; i++)
      if (!c->glyphs->has (component[i]))
B
Behdad Esfahbod 已提交
611 612
        return;
    c->glyphs->add (ligGlyph);
613 614
  }

615 616
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
617
    TRACE_COLLECT_GLYPHS (this);
618 619
    unsigned int count = component.len;
    for (unsigned int i = 1; i < count; i++)
B
Minor  
Behdad Esfahbod 已提交
620 621
      c->input->add (component[i]);
    c->output->add (ligGlyph);
622 623
  }

624
  inline bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
625
  {
B
Behdad Esfahbod 已提交
626
    TRACE_WOULD_APPLY (this);
627
    if (c->len != component.len)
B
Behdad Esfahbod 已提交
628
      return_trace (false);
629 630 631

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

B
Behdad Esfahbod 已提交
634
    return_trace (true);
B
Behdad Esfahbod 已提交
635 636
  }

637
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
638
  {
B
Behdad Esfahbod 已提交
639
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
640
    unsigned int count = component.len;
B
Behdad Esfahbod 已提交
641

B
Behdad Esfahbod 已提交
642
    if (unlikely (!count)) return_trace (false);
B
Behdad Esfahbod 已提交
643

644 645 646 647 648
    /* 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 已提交
649
      return_trace (true);
650 651
    }

B
Behdad Esfahbod 已提交
652 653
    bool is_mark_ligature = false;
    unsigned int total_component_count = 0;
654

655
    unsigned int match_length = 0;
656
    unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
657

658 659 660 661
    if (likely (!match_input (c, count,
			      &component[1],
			      match_glyph,
			      NULL,
662 663
			      &match_length,
			      match_positions,
664 665
			      &is_mark_ligature,
			      &total_component_count)))
B
Behdad Esfahbod 已提交
666
      return_trace (false);
667

668 669
    ligate_input (c,
		  count,
670 671
		  match_positions,
		  match_length,
672
		  ligGlyph,
673 674
		  is_mark_ligature,
		  total_component_count);
675

B
Behdad Esfahbod 已提交
676
    return_trace (true);
677
  }
678

679 680 681 682 683
  inline bool serialize (hb_serialize_context_t *c,
			 GlyphID ligature,
			 Supplier<GlyphID> &components, /* Starting from second */
			 unsigned int num_components /* Including first component */)
  {
B
Behdad Esfahbod 已提交
684
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
685
    if (unlikely (!c->extend_min (*this))) return_trace (false);
686
    ligGlyph = ligature;
B
Behdad Esfahbod 已提交
687 688
    if (unlikely (!component.serialize (c, components, num_components))) return_trace (false);
    return_trace (true);
689 690
  }

B
Behdad Esfahbod 已提交
691
  public:
B
Behdad Esfahbod 已提交
692 693
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
694
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
695
    return_trace (ligGlyph.sanitize (c) && component.sanitize (c));
B
Behdad Esfahbod 已提交
696 697
  }

698
  protected:
699
  GlyphID	ligGlyph;		/* GlyphID of ligature to substitute */
B
Behdad Esfahbod 已提交
700 701
  HeadlessArrayOf<GlyphID>
		component;		/* Array of component GlyphIDs--start
702 703
					 * with the second  component--ordered
					 * in writing direction */
704
  public:
705
  DEFINE_SIZE_ARRAY (4, component);
706
};
B
Behdad Esfahbod 已提交
707

B
Behdad Esfahbod 已提交
708 709
struct LigatureSet
{
B
Behdad Esfahbod 已提交
710
  inline void closure (hb_closure_context_t *c) const
711
  {
B
Behdad Esfahbod 已提交
712
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
713 714
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
B
Behdad Esfahbod 已提交
715
      (this+ligature[i]).closure (c);
716 717
  }

718 719
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
720
    TRACE_COLLECT_GLYPHS (this);
721 722 723 724 725
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
      (this+ligature[i]).collect_glyphs (c);
  }

726
  inline bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
727
  {
B
Behdad Esfahbod 已提交
728
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
729 730 731 732
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
    {
      const Ligature &lig = this+ligature[i];
733
      if (lig.would_apply (c))
B
Behdad Esfahbod 已提交
734
        return_trace (true);
B
Behdad Esfahbod 已提交
735
    }
B
Behdad Esfahbod 已提交
736
    return_trace (false);
B
Behdad Esfahbod 已提交
737 738
  }

739
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
740
  {
B
Behdad Esfahbod 已提交
741
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
742
    unsigned int num_ligs = ligature.len;
B
Behdad Esfahbod 已提交
743 744
    for (unsigned int i = 0; i < num_ligs; i++)
    {
B
Behdad Esfahbod 已提交
745
      const Ligature &lig = this+ligature[i];
B
Behdad Esfahbod 已提交
746
      if (lig.apply (c)) return_trace (true);
747 748
    }

B
Behdad Esfahbod 已提交
749
    return_trace (false);
750
  }
B
Behdad Esfahbod 已提交
751

752 753 754 755 756 757
  inline bool serialize (hb_serialize_context_t *c,
			 Supplier<GlyphID> &ligatures,
			 Supplier<unsigned int> &component_count_list,
			 unsigned int num_ligatures,
			 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
  {
B
Behdad Esfahbod 已提交
758
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
759 760
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    if (unlikely (!ligature.serialize (c, num_ligatures))) return_trace (false);
761 762 763 764
    for (unsigned int i = 0; i < num_ligatures; i++)
      if (unlikely (!ligature[i].serialize (c, this).serialize (c,
								ligatures[i],
								component_list,
B
Behdad Esfahbod 已提交
765
								component_count_list[i]))) return_trace (false);
766
    ligatures.advance (num_ligatures);
767
    component_count_list.advance (num_ligatures);
B
Behdad Esfahbod 已提交
768
    return_trace (true);
769 770
  }

B
Behdad Esfahbod 已提交
771 772
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
773
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
774
    return_trace (ligature.sanitize (c, this));
B
Behdad Esfahbod 已提交
775 776
  }

777
  protected:
B
Behdad Esfahbod 已提交
778 779 780
  OffsetArrayOf<Ligature>
		ligature;		/* Array LigatureSet tables
					 * ordered by preference */
781
  public:
782
  DEFINE_SIZE_ARRAY (2, ligature);
B
Behdad Esfahbod 已提交
783 784
};

B
Behdad Esfahbod 已提交
785 786
struct LigatureSubstFormat1
{
B
Behdad Esfahbod 已提交
787
  inline void closure (hb_closure_context_t *c) const
788
  {
B
Behdad Esfahbod 已提交
789
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
790
    Coverage::Iter iter;
791 792 793 794 795
    unsigned int count = ligatureSet.len;
    for (iter.init (this+coverage); iter.more (); iter.next ())
    {
      if (unlikely (iter.get_coverage () >= count))
        break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
B
Behdad Esfahbod 已提交
796
      if (c->glyphs->has (iter.get_glyph ()))
B
Behdad Esfahbod 已提交
797
	(this+ligatureSet[iter.get_coverage ()]).closure (c);
B
Behdad Esfahbod 已提交
798
    }
799 800
  }

801 802
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
803
    TRACE_COLLECT_GLYPHS (this);
804
    Coverage::Iter iter;
805 806 807 808 809
    unsigned int count = ligatureSet.len;
    for (iter.init (this+coverage); iter.more (); iter.next ())
    {
      if (unlikely (iter.get_coverage () >= count))
        break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
B
Minor  
Behdad Esfahbod 已提交
810
      c->input->add (iter.get_glyph ());
811 812 813 814
      (this+ligatureSet[iter.get_coverage ()]).collect_glyphs (c);
    }
  }

815 816 817 818 819
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

820
  inline bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
821
  {
B
Behdad Esfahbod 已提交
822
    TRACE_WOULD_APPLY (this);
823
    unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
B
Behdad Esfahbod 已提交
824
    if (likely (index == NOT_COVERED)) return_trace (false);
825 826

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

B
Behdad Esfahbod 已提交
830
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
831
  {
B
Behdad Esfahbod 已提交
832
    TRACE_APPLY (this);
833
    hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
834

835
    unsigned int index = (this+coverage).get_coverage (glyph_id);
B
Behdad Esfahbod 已提交
836
    if (likely (index == NOT_COVERED)) return_trace (false);
837

B
Behdad Esfahbod 已提交
838
    const LigatureSet &lig_set = this+ligatureSet[index];
B
Behdad Esfahbod 已提交
839
    return_trace (lig_set.apply (c));
840
  }
B
Behdad Esfahbod 已提交
841

842 843 844 845 846 847 848 849
  inline bool serialize (hb_serialize_context_t *c,
			 Supplier<GlyphID> &first_glyphs,
			 Supplier<unsigned int> &ligature_per_first_glyph_count_list,
			 unsigned int num_first_glyphs,
			 Supplier<GlyphID> &ligatures_list,
			 Supplier<unsigned int> &component_count_list,
			 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
  {
B
Behdad Esfahbod 已提交
850
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
851 852
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    if (unlikely (!ligatureSet.serialize (c, num_first_glyphs))) return_trace (false);
853 854 855 856 857
    for (unsigned int i = 0; i < num_first_glyphs; i++)
      if (unlikely (!ligatureSet[i].serialize (c, this).serialize (c,
								   ligatures_list,
								   component_count_list,
								   ligature_per_first_glyph_count_list[i],
B
Behdad Esfahbod 已提交
858
								   component_list))) return_trace (false);
859
    ligature_per_first_glyph_count_list.advance (num_first_glyphs);
B
Behdad Esfahbod 已提交
860 861
    if (unlikely (!coverage.serialize (c, this).serialize (c, first_glyphs, num_first_glyphs))) return_trace (false);
    return_trace (true);
862 863
  }

B
Behdad Esfahbod 已提交
864 865
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
866
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
867
    return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
868 869
  }

870
  protected:
B
Behdad Esfahbod 已提交
871
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
872 873
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
874
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
875
  OffsetArrayOf<LigatureSet>
B
Behdad Esfahbod 已提交
876 877
		ligatureSet;		/* Array LigatureSet tables
					 * ordered by Coverage Index */
878
  public:
879
  DEFINE_SIZE_ARRAY (6, ligatureSet);
B
Behdad Esfahbod 已提交
880
};
881

B
Behdad Esfahbod 已提交
882 883
struct LigatureSubst
{
884 885 886 887 888 889 890 891
  inline bool serialize (hb_serialize_context_t *c,
			 Supplier<GlyphID> &first_glyphs,
			 Supplier<unsigned int> &ligature_per_first_glyph_count_list,
			 unsigned int num_first_glyphs,
			 Supplier<GlyphID> &ligatures_list,
			 Supplier<unsigned int> &component_count_list,
			 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
  {
B
Behdad Esfahbod 已提交
892
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
893
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
894 895 896
    unsigned int format = 1;
    u.format.set (format);
    switch (u.format) {
B
Behdad Esfahbod 已提交
897 898 899 900 901 902 903 904
    case 1: return_trace (u.format1.serialize (c,
					       first_glyphs,
					       ligature_per_first_glyph_count_list,
					       num_first_glyphs,
					       ligatures_list,
					       component_count_list,
					       component_list));
    default:return_trace (false);
905 906 907
    }
  }

B
Behdad Esfahbod 已提交
908 909 910
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
  {
911
    TRACE_DISPATCH (this, u.format);
912
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
913
    switch (u.format) {
B
Behdad Esfahbod 已提交
914 915
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
916 917 918
    }
  }

919
  protected:
920
  union {
B
Behdad Esfahbod 已提交
921
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
922
  LigatureSubstFormat1	format1;
923 924 925
  } u;
};

B
Behdad Esfahbod 已提交
926

B
Minor  
Behdad Esfahbod 已提交
927
struct ContextSubst : Context {};
B
Behdad Esfahbod 已提交
928

B
Minor  
Behdad Esfahbod 已提交
929
struct ChainContextSubst : ChainContext {};
930

B
Behdad Esfahbod 已提交
931
struct ExtensionSubst : Extension<ExtensionSubst>
B
Behdad Esfahbod 已提交
932
{
933
  typedef struct SubstLookupSubTable LookupSubTable;
B
Behdad Esfahbod 已提交
934

B
Behdad Esfahbod 已提交
935
  inline bool is_reverse (void) const;
936 937 938
};


B
Behdad Esfahbod 已提交
939 940
struct ReverseChainSingleSubstFormat1
{
B
Behdad Esfahbod 已提交
941
  inline void closure (hb_closure_context_t *c) const
942
  {
B
Behdad Esfahbod 已提交
943
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
944 945 946 947 948 949 950
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);

    unsigned int count;

    count = backtrack.len;
    for (unsigned int i = 0; i < count; i++)
      if (!(this+backtrack[i]).intersects (c->glyphs))
B
Behdad Esfahbod 已提交
951
        return;
B
Behdad Esfahbod 已提交
952 953 954 955

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

    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
    Coverage::Iter iter;
960 961 962 963 964
    count = substitute.len;
    for (iter.init (this+coverage); iter.more (); iter.next ())
    {
      if (unlikely (iter.get_coverage () >= count))
        break; /* Work around malicious fonts. https://github.com/behdad/harfbuzz/issues/363 */
B
Behdad Esfahbod 已提交
965
      if (c->glyphs->has (iter.get_glyph ()))
B
Behdad Esfahbod 已提交
966
	c->glyphs->add (substitute[iter.get_coverage ()]);
B
Behdad Esfahbod 已提交
967
    }
968 969
  }

970 971
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
972 973
    TRACE_COLLECT_GLYPHS (this);

974 975 976 977
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);

    unsigned int count;

B
Minor  
Behdad Esfahbod 已提交
978
    (this+coverage).add_coverage (c->input);
979 980 981

    count = backtrack.len;
    for (unsigned int i = 0; i < count; i++)
B
Minor  
Behdad Esfahbod 已提交
982
      (this+backtrack[i]).add_coverage (c->before);
983 984 985

    count = lookahead.len;
    for (unsigned int i = 0; i < count; i++)
B
Minor  
Behdad Esfahbod 已提交
986
      (this+lookahead[i]).add_coverage (c->after);
987 988 989 990

    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
    count = substitute.len;
    for (unsigned int i = 0; i < count; i++)
B
Minor  
Behdad Esfahbod 已提交
991
      c->output->add (substitute[i]);
992 993
  }

994 995 996 997 998
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

999 1000
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1001
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
1002
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
1003 1004
  }

B
Behdad Esfahbod 已提交
1005
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1006
  {
B
Behdad Esfahbod 已提交
1007
    TRACE_APPLY (this);
1008
    if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
B
Behdad Esfahbod 已提交
1009
      return_trace (false); /* No chaining to this type */
1010

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

1014 1015
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
1016

1017
  unsigned int start_index = 0, end_index = 0;
B
Behdad Esfahbod 已提交
1018
    if (match_backtrack (c,
B
Behdad Esfahbod 已提交
1019
			 backtrack.len, (USHORT *) backtrack.array,
1020 1021
			 match_coverage, this,
			 &start_index) &&
B
Behdad Esfahbod 已提交
1022
        match_lookahead (c,
B
Behdad Esfahbod 已提交
1023
			 lookahead.len, (USHORT *) lookahead.array,
B
Behdad Esfahbod 已提交
1024
			 match_coverage, this,
1025
			 1, &end_index))
1026
    {
1027
      c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index);
B
Behdad Esfahbod 已提交
1028
      c->replace_glyph_inplace (substitute[index]);
1029 1030 1031
      /* 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 已提交
1032
      return_trace (true);
1033 1034
    }

B
Behdad Esfahbod 已提交
1035
    return_trace (false);
1036
  }
B
Behdad Esfahbod 已提交
1037

B
Behdad Esfahbod 已提交
1038 1039
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1040
    TRACE_SANITIZE (this);
1041
    if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
B
Behdad Esfahbod 已提交
1042
      return_trace (false);
B
Behdad Esfahbod 已提交
1043
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
B
Behdad Esfahbod 已提交
1044
    if (!lookahead.sanitize (c, this))
B
Behdad Esfahbod 已提交
1045
      return_trace (false);
B
Behdad Esfahbod 已提交
1046
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
B
Behdad Esfahbod 已提交
1047
    return_trace (substitute.sanitize (c));
B
Behdad Esfahbod 已提交
1048 1049
  }

1050
  protected:
B
Behdad Esfahbod 已提交
1051
  USHORT	format;			/* Format identifier--format = 1 */
1052 1053 1054 1055 1056
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of table */
  OffsetArrayOf<Coverage>
		backtrack;		/* Array of coverage tables
B
Behdad Esfahbod 已提交
1057 1058
					 * in backtracking sequence, in  glyph
					 * sequence order */
1059 1060 1061
  OffsetArrayOf<Coverage>
		lookaheadX;		/* Array of coverage tables
					 * in lookahead sequence, in glyph
B
Behdad Esfahbod 已提交
1062
					 * sequence order */
1063 1064 1065
  ArrayOf<GlyphID>
		substituteX;		/* Array of substitute
					 * GlyphIDs--ordered by Coverage Index */
1066
  public:
B
Behdad Esfahbod 已提交
1067
  DEFINE_SIZE_MIN (10);
B
Behdad Esfahbod 已提交
1068 1069
};

B
Behdad Esfahbod 已提交
1070 1071
struct ReverseChainSingleSubst
{
1072
  template <typename context_t>
1073
  inline typename context_t::return_t dispatch (context_t *c) const
1074
  {
1075
    TRACE_DISPATCH (this, u.format);
1076
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1077
    switch (u.format) {
B
Behdad Esfahbod 已提交
1078 1079
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
1080 1081 1082
    }
  }

1083
  protected:
1084 1085
  union {
  USHORT				format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1086
  ReverseChainSingleSubstFormat1	format1;
1087 1088 1089 1090 1091
  } u;
};



B
Behdad Esfahbod 已提交
1092 1093 1094 1095
/*
 * SubstLookup
 */

B
Behdad Esfahbod 已提交
1096 1097
struct SubstLookupSubTable
{
B
Behdad Esfahbod 已提交
1098 1099
  friend struct SubstLookup;

B
Behdad Esfahbod 已提交
1100
  enum Type {
1101 1102 1103 1104 1105 1106 1107
    Single		= 1,
    Multiple		= 2,
    Alternate		= 3,
    Ligature		= 4,
    Context		= 5,
    ChainContext	= 6,
    Extension		= 7,
1108
    ReverseChainSingle	= 8
1109 1110
  };

1111
  template <typename context_t>
1112
  inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
1113
  {
1114
    TRACE_DISPATCH (this, lookup_type);
1115
    if (unlikely (!c->may_dispatch (this, &u.sub_format))) return_trace (c->no_dispatch_return_value ());
1116
    switch (lookup_type) {
B
Behdad Esfahbod 已提交
1117 1118 1119 1120 1121 1122 1123 1124 1125
    case Single:		return_trace (u.single.dispatch (c));
    case Multiple:		return_trace (u.multiple.dispatch (c));
    case Alternate:		return_trace (u.alternate.dispatch (c));
    case Ligature:		return_trace (u.ligature.dispatch (c));
    case Context:		return_trace (u.context.dispatch (c));
    case ChainContext:		return_trace (u.chainContext.dispatch (c));
    case Extension:		return_trace (u.extension.dispatch (c));
    case ReverseChainSingle:	return_trace (u.reverseChainContextSingle.dispatch (c));
    default:			return_trace (c->default_return_value ());
1126 1127 1128
    }
  }

1129
  protected:
B
Behdad Esfahbod 已提交
1130
  union {
B
Minor  
Behdad Esfahbod 已提交
1131
  USHORT			sub_format;
B
Behdad Esfahbod 已提交
1132 1133 1134 1135
  SingleSubst			single;
  MultipleSubst			multiple;
  AlternateSubst		alternate;
  LigatureSubst			ligature;
1136
  ContextSubst			context;
B
Behdad Esfahbod 已提交
1137 1138 1139
  ChainContextSubst		chainContext;
  ExtensionSubst		extension;
  ReverseChainSingleSubst	reverseChainContextSingle;
B
Behdad Esfahbod 已提交
1140
  } u;
B
Behdad Esfahbod 已提交
1141
  public:
B
Minor  
Behdad Esfahbod 已提交
1142
  DEFINE_SIZE_UNION (2, sub_format);
B
Behdad Esfahbod 已提交
1143 1144
};

1145

B
Behdad Esfahbod 已提交
1146 1147
struct SubstLookup : Lookup
{
1148
  inline const SubstLookupSubTable& get_subtable (unsigned int i) const
1149
  { return Lookup::get_subtable<SubstLookupSubTable> (i); }
B
Behdad Esfahbod 已提交
1150

B
Behdad Esfahbod 已提交
1151
  inline static bool lookup_type_is_reverse (unsigned int lookup_type)
1152
  { return lookup_type == SubstLookupSubTable::ReverseChainSingle; }
B
Behdad Esfahbod 已提交
1153 1154

  inline bool is_reverse (void) const
B
Behdad Esfahbod 已提交
1155
  {
B
Behdad Esfahbod 已提交
1156
    unsigned int type = get_type ();
1157
    if (unlikely (type == SubstLookupSubTable::Extension))
1158
      return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
B
Behdad Esfahbod 已提交
1159
    return lookup_type_is_reverse (type);
B
Behdad Esfahbod 已提交
1160
  }
1161

B
Behdad Esfahbod 已提交
1162 1163 1164
  inline bool apply (hb_apply_context_t *c) const
  {
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
1165
    return_trace (dispatch (c));
B
Behdad Esfahbod 已提交
1166 1167
  }

1168 1169
  inline hb_closure_context_t::return_t closure (hb_closure_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1170
    TRACE_CLOSURE (this);
1171
    c->set_recurse_func (dispatch_recurse_func<hb_closure_context_t>);
B
Behdad Esfahbod 已提交
1172
    return_trace (dispatch (c));
B
Behdad Esfahbod 已提交
1173 1174
  }

B
Behdad Esfahbod 已提交
1175
  inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
B
Behdad Esfahbod 已提交
1176 1177
  {
    TRACE_COLLECT_GLYPHS (this);
1178
    c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
B
Behdad Esfahbod 已提交
1179
    return_trace (dispatch (c));
1180 1181
  }

B
Behdad Esfahbod 已提交
1182 1183 1184
  template <typename set_t>
  inline void add_coverage (set_t *glyphs) const
  {
1185 1186
    hb_add_coverage_context_t<set_t> c (glyphs);
    dispatch (&c);
B
Behdad Esfahbod 已提交
1187 1188
  }

1189 1190
  inline bool would_apply (hb_would_apply_context_t *c,
			   const hb_ot_layout_lookup_accelerator_t *accel) const
B
Behdad Esfahbod 已提交
1191
  {
B
Behdad Esfahbod 已提交
1192
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
1193 1194 1195
    if (unlikely (!c->len))  return_trace (false);
    if (!accel->may_have (c->glyphs[0]))  return_trace (false);
      return_trace (dispatch (c));
B
Behdad Esfahbod 已提交
1196 1197
  }

1198
  static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);
B
Behdad Esfahbod 已提交
1199

1200 1201
  inline SubstLookupSubTable& serialize_subtable (hb_serialize_context_t *c,
						  unsigned int i)
1202
  { return get_subtables<SubstLookupSubTable> ()[i].serialize (c, this); }
1203 1204 1205 1206 1207 1208 1209

  inline bool serialize_single (hb_serialize_context_t *c,
				uint32_t lookup_props,
			        Supplier<GlyphID> &glyphs,
			        Supplier<GlyphID> &substitutes,
			        unsigned int num_glyphs)
  {
B
Behdad Esfahbod 已提交
1210
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1211 1212
    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Single, lookup_props, 1))) return_trace (false);
    return_trace (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes, num_glyphs));
1213 1214 1215 1216 1217 1218 1219 1220 1221
  }

  inline bool serialize_multiple (hb_serialize_context_t *c,
				  uint32_t lookup_props,
				  Supplier<GlyphID> &glyphs,
				  Supplier<unsigned int> &substitute_len_list,
				  unsigned int num_glyphs,
				  Supplier<GlyphID> &substitute_glyphs_list)
  {
B
Behdad Esfahbod 已提交
1222
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1223 1224 1225 1226 1227 1228
    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Multiple, lookup_props, 1))) return_trace (false);
    return_trace (serialize_subtable (c, 0).u.multiple.serialize (c,
								  glyphs,
								  substitute_len_list,
								  num_glyphs,
								  substitute_glyphs_list));
1229 1230 1231 1232 1233 1234 1235 1236 1237
  }

  inline bool serialize_alternate (hb_serialize_context_t *c,
				   uint32_t lookup_props,
				   Supplier<GlyphID> &glyphs,
				   Supplier<unsigned int> &alternate_len_list,
				   unsigned int num_glyphs,
				   Supplier<GlyphID> &alternate_glyphs_list)
  {
B
Behdad Esfahbod 已提交
1238
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1239 1240 1241 1242 1243 1244
    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Alternate, lookup_props, 1))) return_trace (false);
    return_trace (serialize_subtable (c, 0).u.alternate.serialize (c,
								   glyphs,
								   alternate_len_list,
								   num_glyphs,
								   alternate_glyphs_list));
1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255
  }

  inline bool serialize_ligature (hb_serialize_context_t *c,
				  uint32_t lookup_props,
				  Supplier<GlyphID> &first_glyphs,
				  Supplier<unsigned int> &ligature_per_first_glyph_count_list,
				  unsigned int num_first_glyphs,
				  Supplier<GlyphID> &ligatures_list,
				  Supplier<unsigned int> &component_count_list,
				  Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
  {
B
Behdad Esfahbod 已提交
1256
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1257 1258 1259 1260 1261 1262 1263 1264
    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Ligature, lookup_props, 1))) return_trace (false);
    return_trace (serialize_subtable (c, 0).u.ligature.serialize (c,
								  first_glyphs,
								  ligature_per_first_glyph_count_list,
								  num_first_glyphs,
								  ligatures_list,
								  component_count_list,
								  component_list));
1265 1266
  }

B
Behdad Esfahbod 已提交
1267 1268 1269 1270 1271
  template <typename context_t>
  static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);

  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
1272
  { return Lookup::dispatch<SubstLookupSubTable> (c); }
B
Behdad Esfahbod 已提交
1273

B
Behdad Esfahbod 已提交
1274
  inline bool sanitize (hb_sanitize_context_t *c) const
1275
  {
B
Behdad Esfahbod 已提交
1276
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1277 1278
    if (unlikely (!Lookup::sanitize (c))) return_trace (false);
    if (unlikely (!dispatch (c))) return_trace (false);
B
Behdad Esfahbod 已提交
1279 1280 1281 1282 1283

    if (unlikely (get_type () == SubstLookupSubTable::Extension))
    {
      /* The spec says all subtables of an Extension lookup should
       * have the same type.  This is specially important if one has
B
Minor  
Behdad Esfahbod 已提交
1284
       * a reverse type! */
B
Behdad Esfahbod 已提交
1285 1286 1287 1288
      unsigned int type = get_subtable (0).u.extension.get_type ();
      unsigned int count = get_subtable_count ();
      for (unsigned int i = 1; i < count; i++)
        if (get_subtable (i).u.extension.get_type () != type)
B
Behdad Esfahbod 已提交
1289
	  return_trace (false);
B
Behdad Esfahbod 已提交
1290
    }
B
Behdad Esfahbod 已提交
1291
    return_trace (true);
B
Behdad Esfahbod 已提交
1292
  }
B
Behdad Esfahbod 已提交
1293 1294
};

B
Behdad Esfahbod 已提交
1295
typedef OffsetListOf<SubstLookup> SubstLookupList;
1296

B
Minor  
Behdad Esfahbod 已提交
1297
/*
B
Behdad Esfahbod 已提交
1298
 * GSUB -- The Glyph Substitution Table
B
Minor  
Behdad Esfahbod 已提交
1299 1300
 */

B
Behdad Esfahbod 已提交
1301 1302
struct GSUB : GSUBGPOS
{
1303
  static const hb_tag_t tableTag	= HB_OT_TAG_GSUB;
B
Minor  
Behdad Esfahbod 已提交
1304

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

1308
  static inline void substitute_start (hb_font_t *font, hb_buffer_t *buffer);
B
Behdad Esfahbod 已提交
1309

B
Behdad Esfahbod 已提交
1310 1311
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1312
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1313
    if (unlikely (!GSUBGPOS::sanitize (c))) return_trace (false);
B
Behdad Esfahbod 已提交
1314
    const OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
B
Behdad Esfahbod 已提交
1315
    return_trace (list.sanitize (c, this));
B
Behdad Esfahbod 已提交
1316
  }
B
Minor  
Behdad Esfahbod 已提交
1317
};
1318 1319


B
Behdad Esfahbod 已提交
1320
void
1321
GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer)
B
Behdad Esfahbod 已提交
1322
{
1323
  _hb_buffer_assert_gsubgpos_vars (buffer);
1324

1325
  const GDEF &gdef = *hb_ot_layout_from_face (font->face)->gdef;
B
Behdad Esfahbod 已提交
1326
  unsigned int count = buffer->len;
B
Behdad Esfahbod 已提交
1327 1328
  for (unsigned int i = 0; i < count; i++)
  {
1329 1330
    _hb_glyph_info_set_glyph_props (&buffer->info[i], gdef.get_glyph_props (buffer->info[i].codepoint));
    _hb_glyph_info_clear_lig_props (&buffer->info[i]);
B
Behdad Esfahbod 已提交
1331
    buffer->info[i].syllable() = 0;
1332
  }
B
Behdad Esfahbod 已提交
1333 1334 1335
}


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

1338
/*static*/ inline bool ExtensionSubst::is_reverse (void) const
B
Behdad Esfahbod 已提交
1339 1340
{
  unsigned int type = get_type ();
1341
  if (unlikely (type == SubstLookupSubTable::Extension))
1342
    return CastR<ExtensionSubst> (get_subtable<LookupSubTable>()).is_reverse ();
B
Behdad Esfahbod 已提交
1343 1344 1345
  return SubstLookup::lookup_type_is_reverse (type);
}

1346
template <typename context_t>
1347
/*static*/ inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
1348 1349 1350
{
  const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
  const SubstLookup &l = gsub.get_lookup (lookup_index);
1351
  return l.dispatch (c);
1352 1353
}

1354
/*static*/ inline bool SubstLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
B
Behdad Esfahbod 已提交
1355
{
1356
  const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
1357
  const SubstLookup &l = gsub.get_lookup (lookup_index);
1358
  unsigned int saved_lookup_props = c->lookup_props;
1359 1360 1361
  unsigned int saved_lookup_index = c->lookup_index;
  c->set_lookup_index (lookup_index);
  c->set_lookup_props (l.get_props ());
1362
  bool ret = l.dispatch (c);
1363
  c->set_lookup_index (saved_lookup_index);
1364
  c->set_lookup_props (saved_lookup_props);
1365
  return ret;
1366 1367 1368
}


B
Behdad Esfahbod 已提交
1369
} /* namespace OT */
1370

B
Behdad Esfahbod 已提交
1371

1372
#endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */