hb-ot-layout-gsub-table.hh 43.1 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 44 45 46
    Coverage::Iter iter;
    for (iter.init (this+coverage); iter.more (); iter.next ()) {
      hb_codepoint_t glyph_id = iter.get_glyph ();
      if (c->glyphs->has (glyph_id))
B
Behdad Esfahbod 已提交
47
	c->glyphs->add ((glyph_id + deltaGlyphID) & 0xFFFF);
B
Behdad Esfahbod 已提交
48
    }
49 50
  }

51 52
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
53
    TRACE_COLLECT_GLYPHS (this);
54 55 56
    Coverage::Iter iter;
    for (iter.init (this+coverage); iter.more (); iter.next ()) {
      hb_codepoint_t glyph_id = iter.get_glyph ();
B
Minor  
Behdad Esfahbod 已提交
57 58
      c->input->add (glyph_id);
      c->output->add ((glyph_id + deltaGlyphID) & 0xFFFF);
59 60 61
    }
  }

62 63 64 65 66
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

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

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

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

85
    return TRACE_RETURN (true);
86
  }
B
Behdad Esfahbod 已提交
87

88
  inline bool serialize (hb_serialize_context_t *c,
89
			 Supplier<GlyphID> &glyphs,
90
			 unsigned int num_glyphs,
B
Minor  
Behdad Esfahbod 已提交
91
			 int delta)
92
  {
B
Behdad Esfahbod 已提交
93
    TRACE_SERIALIZE (this);
94
    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
95
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
B
Minor  
Behdad Esfahbod 已提交
96
    deltaGlyphID.set (delta); /* TODO(serilaize) overflow? */
97 98 99
    return TRACE_RETURN (true);
  }

B
Behdad Esfahbod 已提交
100
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
101
    TRACE_SANITIZE (this);
102
    return TRACE_RETURN (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
B
Behdad Esfahbod 已提交
103 104
  }

105
  protected:
B
Behdad Esfahbod 已提交
106
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
107 108
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
109 110 111
					 * beginning of Substitution table */
  SHORT		deltaGlyphID;		/* Add to original GlyphID to get
					 * substitute GlyphID */
112 113
  public:
  DEFINE_SIZE_STATIC (6);
B
Behdad Esfahbod 已提交
114 115
};

B
Behdad Esfahbod 已提交
116 117
struct SingleSubstFormat2
{
B
Behdad Esfahbod 已提交
118
  inline void closure (hb_closure_context_t *c) const
119
  {
B
Behdad Esfahbod 已提交
120
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
121 122 123
    Coverage::Iter iter;
    for (iter.init (this+coverage); iter.more (); iter.next ()) {
      if (c->glyphs->has (iter.get_glyph ()))
B
Behdad Esfahbod 已提交
124
	c->glyphs->add (substitute[iter.get_coverage ()]);
B
Behdad Esfahbod 已提交
125
    }
126 127
  }

128 129
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
130
    TRACE_COLLECT_GLYPHS (this);
131 132
    Coverage::Iter iter;
    for (iter.init (this+coverage); iter.more (); iter.next ()) {
B
Minor  
Behdad Esfahbod 已提交
133 134
      c->input->add (iter.get_glyph ());
      c->output->add (substitute[iter.get_coverage ()]);
135 136 137
    }
  }

138 139 140 141 142
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

143 144
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
145
    TRACE_WOULD_APPLY (this);
146
    return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
147 148
  }

B
Behdad Esfahbod 已提交
149
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
150
  {
B
Behdad Esfahbod 已提交
151
    TRACE_APPLY (this);
152
    hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
153
    unsigned int index = (this+coverage).get_coverage (glyph_id);
154
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
155

156
    if (unlikely (index >= substitute.len)) return TRACE_RETURN (false);
157 158

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

161
    return TRACE_RETURN (true);
162
  }
B
Behdad Esfahbod 已提交
163

B
Behdad Esfahbod 已提交
164
  inline bool serialize (hb_serialize_context_t *c,
165 166
			 Supplier<GlyphID> &glyphs,
			 Supplier<GlyphID> &substitutes,
B
Behdad Esfahbod 已提交
167 168
			 unsigned int num_glyphs)
  {
B
Behdad Esfahbod 已提交
169
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
170 171
    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
    if (unlikely (!substitute.serialize (c, substitutes, num_glyphs))) return TRACE_RETURN (false);
172
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
173 174 175
    return TRACE_RETURN (true);
  }

B
Behdad Esfahbod 已提交
176
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
177
    TRACE_SANITIZE (this);
178
    return TRACE_RETURN (coverage.sanitize (c, this) && substitute.sanitize (c));
B
Behdad Esfahbod 已提交
179 180
  }

181
  protected:
B
Behdad Esfahbod 已提交
182
  USHORT	format;			/* Format identifier--format = 2 */
B
Behdad Esfahbod 已提交
183 184
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
185
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
186 187 188
  ArrayOf<GlyphID>
		substitute;		/* Array of substitute
					 * GlyphIDs--ordered by Coverage Index */
189
  public:
190
  DEFINE_SIZE_ARRAY (6, substitute);
B
Behdad Esfahbod 已提交
191 192
};

B
Behdad Esfahbod 已提交
193 194
struct SingleSubst
{
B
Behdad Esfahbod 已提交
195
  inline bool serialize (hb_serialize_context_t *c,
196 197
			 Supplier<GlyphID> &glyphs,
			 Supplier<GlyphID> &substitutes,
B
Behdad Esfahbod 已提交
198 199
			 unsigned int num_glyphs)
  {
B
Behdad Esfahbod 已提交
200
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
201 202
    if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
    unsigned int format = 2;
B
Minor  
Behdad Esfahbod 已提交
203
    int delta;
B
Behdad Esfahbod 已提交
204 205
    if (num_glyphs) {
      format = 1;
B
Minor  
Behdad Esfahbod 已提交
206
      /* TODO(serialize) check for wrap-around */
B
Behdad Esfahbod 已提交
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
      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) {
    case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, num_glyphs, delta));
    case 2: return TRACE_RETURN (u.format2.serialize (c, glyphs, substitutes, num_glyphs));
    default:return TRACE_RETURN (false);
    }
  }

B
Behdad Esfahbod 已提交
222 223 224 225 226 227 228 229 230 231 232
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
  {
    TRACE_DISPATCH (this);
    switch (u.format) {
    case 1: return TRACE_RETURN (c->dispatch (u.format1));
    case 2: return TRACE_RETURN (c->dispatch (u.format2));
    default:return TRACE_RETURN (c->default_return_value ());
    }
  }

B
Behdad Esfahbod 已提交
233
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
234
    TRACE_SANITIZE (this);
235
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
236
    switch (u.format) {
237 238 239
    case 1: return TRACE_RETURN (u.format1.sanitize (c));
    case 2: return TRACE_RETURN (u.format2.sanitize (c));
    default:return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
240 241 242
    }
  }

243
  protected:
244
  union {
B
Behdad Esfahbod 已提交
245
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
246 247
  SingleSubstFormat1	format1;
  SingleSubstFormat2	format2;
248
  } u;
B
Behdad Esfahbod 已提交
249
};
250

B
Behdad Esfahbod 已提交
251

B
Behdad Esfahbod 已提交
252 253
struct Sequence
{
B
Behdad Esfahbod 已提交
254
  inline void closure (hb_closure_context_t *c) const
255
  {
B
Behdad Esfahbod 已提交
256
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
257 258
    unsigned int count = substitute.len;
    for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
259
      c->glyphs->add (substitute[i]);
260 261
  }

262 263
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
264
    TRACE_COLLECT_GLYPHS (this);
265 266
    unsigned int count = substitute.len;
    for (unsigned int i = 0; i < count; i++)
B
Minor  
Behdad Esfahbod 已提交
267
      c->output->add (substitute[i]);
268 269
  }

B
Behdad Esfahbod 已提交
270
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
271
  {
B
Behdad Esfahbod 已提交
272
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
273
    unsigned int count = substitute.len;
274 275 276 277 278 279 280 281 282

    /* TODO:
     * Testing shows that Uniscribe actually allows zero-len susbstitute,
     * which essentially deletes a glyph.  We don't allow for now.  It
     * can be confusing to the client since the cluster from the deleted
     * glyph won't be merged with any output cluster...  Also, currently
     * buffer->move_to() makes assumptions about this too.  Perhaps fix
     * in the future after figuring out what to do with the clusters.
     */
B
Behdad Esfahbod 已提交
283
    if (unlikely (!count)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
284

B
Behdad Esfahbod 已提交
285 286 287
    /* Special-case to make it in-place and not consider this
     * as a "multiplied" substitution. */
    if (unlikely (count == 1))
288 289
    {
      c->replace_glyph (substitute.array[0]);
B
Behdad Esfahbod 已提交
290
      return TRACE_RETURN (true);
291
    }
B
Behdad Esfahbod 已提交
292 293 294 295 296 297

    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);
298
      c->output_glyph_for_component (substitute.array[i], klass);
299
    }
B
Behdad Esfahbod 已提交
300
    c->buffer->skip_glyph ();
B
Behdad Esfahbod 已提交
301

302
    return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
303 304
  }

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

B
Behdad Esfahbod 已提交
315
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
316
    TRACE_SANITIZE (this);
317
    return TRACE_RETURN (substitute.sanitize (c));
B
Behdad Esfahbod 已提交
318 319
  }

320
  protected:
B
Behdad Esfahbod 已提交
321 322
  ArrayOf<GlyphID>
		substitute;		/* String of GlyphIDs to substitute */
323
  public:
324
  DEFINE_SIZE_ARRAY (2, substitute);
B
Behdad Esfahbod 已提交
325 326
};

B
Behdad Esfahbod 已提交
327 328
struct MultipleSubstFormat1
{
B
Behdad Esfahbod 已提交
329
  inline void closure (hb_closure_context_t *c) const
330
  {
B
Behdad Esfahbod 已提交
331
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
332 333 334
    Coverage::Iter iter;
    for (iter.init (this+coverage); iter.more (); iter.next ()) {
      if (c->glyphs->has (iter.get_glyph ()))
B
Behdad Esfahbod 已提交
335
	(this+sequence[iter.get_coverage ()]).closure (c);
B
Behdad Esfahbod 已提交
336
    }
337 338
  }

339 340
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
341
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
342
    (this+coverage).add_coverage (c->input);
343 344 345 346 347
    unsigned int count = sequence.len;
    for (unsigned int i = 0; i < count; i++)
	(this+sequence[i]).collect_glyphs (c);
  }

348 349 350 351 352
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

353 354
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
355
    TRACE_WOULD_APPLY (this);
356
    return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
357 358
  }

B
Behdad Esfahbod 已提交
359
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
360
  {
B
Behdad Esfahbod 已提交
361
    TRACE_APPLY (this);
362

363
    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
364
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
365

366
    return TRACE_RETURN ((this+sequence[index]).apply (c));
367
  }
B
Behdad Esfahbod 已提交
368

369
  inline bool serialize (hb_serialize_context_t *c,
370 371
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &substitute_len_list,
372
			 unsigned int num_glyphs,
373
			 Supplier<GlyphID> &substitute_glyphs_list)
374
  {
B
Behdad Esfahbod 已提交
375
    TRACE_SERIALIZE (this);
376 377
    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
    if (unlikely (!sequence.serialize (c, num_glyphs))) return TRACE_RETURN (false);
378 379 380 381 382
    for (unsigned int i = 0; i < num_glyphs; i++)
      if (unlikely (!sequence[i].serialize (c, this).serialize (c,
								substitute_glyphs_list,
								substitute_len_list[i]))) return TRACE_RETURN (false);
    substitute_len_list.advance (num_glyphs);
383
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
384 385 386
    return TRACE_RETURN (true);
  }

B
Behdad Esfahbod 已提交
387
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
388
    TRACE_SANITIZE (this);
389
    return TRACE_RETURN (coverage.sanitize (c, this) && sequence.sanitize (c, this));
B
Behdad Esfahbod 已提交
390 391
  }

392
  protected:
B
Behdad Esfahbod 已提交
393
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
394 395
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
396
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
397 398 399
  OffsetArrayOf<Sequence>
		sequence;		/* Array of Sequence tables
					 * ordered by Coverage Index */
400
  public:
401
  DEFINE_SIZE_ARRAY (6, sequence);
B
Behdad Esfahbod 已提交
402
};
403

B
Behdad Esfahbod 已提交
404 405
struct MultipleSubst
{
406
  inline bool serialize (hb_serialize_context_t *c,
407 408
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &substitute_len_list,
409
			 unsigned int num_glyphs,
410
			 Supplier<GlyphID> &substitute_glyphs_list)
411
  {
B
Behdad Esfahbod 已提交
412
    TRACE_SERIALIZE (this);
413 414 415 416 417 418 419 420 421
    if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
    unsigned int format = 1;
    u.format.set (format);
    switch (u.format) {
    case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, substitute_len_list, num_glyphs, substitute_glyphs_list));
    default:return TRACE_RETURN (false);
    }
  }

B
Behdad Esfahbod 已提交
422 423 424 425 426 427 428 429 430 431
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
  {
    TRACE_DISPATCH (this);
    switch (u.format) {
    case 1: return TRACE_RETURN (c->dispatch (u.format1));
    default:return TRACE_RETURN (c->default_return_value ());
    }
  }

B
Behdad Esfahbod 已提交
432
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
433
    TRACE_SANITIZE (this);
434
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
435
    switch (u.format) {
436 437
    case 1: return TRACE_RETURN (u.format1.sanitize (c));
    default:return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
438 439 440
    }
  }

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

B
Behdad Esfahbod 已提交
448

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

B
Behdad Esfahbod 已提交
452 453
struct AlternateSubstFormat1
{
B
Behdad Esfahbod 已提交
454
  inline void closure (hb_closure_context_t *c) const
455
  {
B
Behdad Esfahbod 已提交
456
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
457 458 459 460 461 462
    Coverage::Iter iter;
    for (iter.init (this+coverage); iter.more (); iter.next ()) {
      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 已提交
463
	  c->glyphs->add (alt_set[i]);
B
Behdad Esfahbod 已提交
464 465
      }
    }
466 467
  }

468 469
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
470
    TRACE_COLLECT_GLYPHS (this);
471 472
    Coverage::Iter iter;
    for (iter.init (this+coverage); iter.more (); iter.next ()) {
B
Minor  
Behdad Esfahbod 已提交
473
      c->input->add (iter.get_glyph ());
474 475 476
      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 已提交
477
	c->output->add (alt_set[i]);
478 479 480
    }
  }

481 482 483 484 485
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

486 487
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
488
    TRACE_WOULD_APPLY (this);
489
    return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
490 491
  }

B
Behdad Esfahbod 已提交
492
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
493
  {
B
Behdad Esfahbod 已提交
494
    TRACE_APPLY (this);
495
    hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
496

497
    unsigned int index = (this+coverage).get_coverage (glyph_id);
498
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
499

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

502
    if (unlikely (!alt_set.len)) return TRACE_RETURN (false);
503

504
    hb_mask_t glyph_mask = c->buffer->cur().mask;
B
Behdad Esfahbod 已提交
505 506
    hb_mask_t lookup_mask = c->lookup_mask;

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

511
    if (unlikely (alt_index > alt_set.len || alt_index == 0)) return TRACE_RETURN (false);
512

B
Behdad Esfahbod 已提交
513
    glyph_id = alt_set[alt_index - 1];
514

515
    c->replace_glyph (glyph_id);
516

517
    return TRACE_RETURN (true);
518
  }
B
Behdad Esfahbod 已提交
519

520
  inline bool serialize (hb_serialize_context_t *c,
521 522
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &alternate_len_list,
523
			 unsigned int num_glyphs,
524
			 Supplier<GlyphID> &alternate_glyphs_list)
525
  {
B
Behdad Esfahbod 已提交
526
    TRACE_SERIALIZE (this);
527 528
    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
    if (unlikely (!alternateSet.serialize (c, num_glyphs))) return TRACE_RETURN (false);
529 530 531 532 533
    for (unsigned int i = 0; i < num_glyphs; i++)
      if (unlikely (!alternateSet[i].serialize (c, this).serialize (c,
								    alternate_glyphs_list,
								    alternate_len_list[i]))) return TRACE_RETURN (false);
    alternate_len_list.advance (num_glyphs);
534
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
535 536 537
    return TRACE_RETURN (true);
  }

B
Behdad Esfahbod 已提交
538
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
539
    TRACE_SANITIZE (this);
540
    return TRACE_RETURN (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
541 542
  }

543
  protected:
B
Behdad Esfahbod 已提交
544
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
545 546
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
547
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
548 549 550
  OffsetArrayOf<AlternateSet>
		alternateSet;		/* Array of AlternateSet tables
					 * ordered by Coverage Index */
551
  public:
552
  DEFINE_SIZE_ARRAY (6, alternateSet);
B
Behdad Esfahbod 已提交
553
};
554

B
Behdad Esfahbod 已提交
555 556
struct AlternateSubst
{
557
  inline bool serialize (hb_serialize_context_t *c,
558 559
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &alternate_len_list,
560
			 unsigned int num_glyphs,
561
			 Supplier<GlyphID> &alternate_glyphs_list)
562
  {
B
Behdad Esfahbod 已提交
563
    TRACE_SERIALIZE (this);
564 565 566 567 568 569 570 571 572
    if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
    unsigned int format = 1;
    u.format.set (format);
    switch (u.format) {
    case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, alternate_len_list, num_glyphs, alternate_glyphs_list));
    default:return TRACE_RETURN (false);
    }
  }

B
Behdad Esfahbod 已提交
573 574 575 576 577 578 579 580 581 582
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
  {
    TRACE_DISPATCH (this);
    switch (u.format) {
    case 1: return TRACE_RETURN (c->dispatch (u.format1));
    default:return TRACE_RETURN (c->default_return_value ());
    }
  }

B
Behdad Esfahbod 已提交
583
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
584
    TRACE_SANITIZE (this);
585
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
586
    switch (u.format) {
587 588
    case 1: return TRACE_RETURN (u.format1.sanitize (c));
    default:return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
589 590 591
    }
  }

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

599

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

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

621
  inline bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
622
  {
B
Behdad Esfahbod 已提交
623
    TRACE_WOULD_APPLY (this);
624
    if (c->len != component.len)
625
      return TRACE_RETURN (false);
626 627 628

    for (unsigned int i = 1; i < c->len; i++)
      if (likely (c->glyphs[i] != component[i]))
629
	return TRACE_RETURN (false);
630

631
    return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
632 633
  }

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

    if (unlikely (!count)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
640

641 642 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);
      return TRACE_RETURN (true);
    }

B
Behdad Esfahbod 已提交
649 650
    bool is_mark_ligature = false;
    unsigned int total_component_count = 0;
651

652 653 654
    unsigned int match_length = 0;
    unsigned int match_positions[MAX_CONTEXT_LENGTH];

655 656 657 658
    if (likely (!match_input (c, count,
			      &component[1],
			      match_glyph,
			      NULL,
659 660
			      &match_length,
			      match_positions,
661 662 663
			      &is_mark_ligature,
			      &total_component_count)))
      return TRACE_RETURN (false);
664

665 666
    ligate_input (c,
		  count,
667 668
		  match_positions,
		  match_length,
669
		  ligGlyph,
670 671
		  is_mark_ligature,
		  total_component_count);
672

673
    return TRACE_RETURN (true);
674
  }
675

676 677 678 679 680
  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 已提交
681
    TRACE_SERIALIZE (this);
682
    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
683
    ligGlyph = ligature;
684 685 686 687
    if (unlikely (!component.serialize (c, components, num_components))) return TRACE_RETURN (false);
    return TRACE_RETURN (true);
  }

B
Behdad Esfahbod 已提交
688
  public:
B
Behdad Esfahbod 已提交
689
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
690
    TRACE_SANITIZE (this);
691
    return TRACE_RETURN (ligGlyph.sanitize (c) && component.sanitize (c));
B
Behdad Esfahbod 已提交
692 693
  }

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

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

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

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

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

745
    return TRACE_RETURN (false);
746
  }
B
Behdad Esfahbod 已提交
747

748 749 750 751 752 753
  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 已提交
754
    TRACE_SERIALIZE (this);
755 756 757 758 759 760 761
    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
    if (unlikely (!ligature.serialize (c, num_ligatures))) return TRACE_RETURN (false);
    for (unsigned int i = 0; i < num_ligatures; i++)
      if (unlikely (!ligature[i].serialize (c, this).serialize (c,
								ligatures[i],
								component_list,
								component_count_list[i]))) return TRACE_RETURN (false);
762
    ligatures.advance (num_ligatures);
763 764 765 766
    component_count_list.advance (num_ligatures);
    return TRACE_RETURN (true);
  }

B
Behdad Esfahbod 已提交
767
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
768
    TRACE_SANITIZE (this);
769
    return TRACE_RETURN (ligature.sanitize (c, this));
B
Behdad Esfahbod 已提交
770 771
  }

772
  protected:
B
Behdad Esfahbod 已提交
773 774 775
  OffsetArrayOf<Ligature>
		ligature;		/* Array LigatureSet tables
					 * ordered by preference */
776
  public:
777
  DEFINE_SIZE_ARRAY (2, ligature);
B
Behdad Esfahbod 已提交
778 779
};

B
Behdad Esfahbod 已提交
780 781
struct LigatureSubstFormat1
{
B
Behdad Esfahbod 已提交
782
  inline void closure (hb_closure_context_t *c) const
783
  {
B
Behdad Esfahbod 已提交
784
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
785 786 787
    Coverage::Iter iter;
    for (iter.init (this+coverage); iter.more (); iter.next ()) {
      if (c->glyphs->has (iter.get_glyph ()))
B
Behdad Esfahbod 已提交
788
	(this+ligatureSet[iter.get_coverage ()]).closure (c);
B
Behdad Esfahbod 已提交
789
    }
790 791
  }

792 793
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
794
    TRACE_COLLECT_GLYPHS (this);
795 796
    Coverage::Iter iter;
    for (iter.init (this+coverage); iter.more (); iter.next ()) {
B
Minor  
Behdad Esfahbod 已提交
797
      c->input->add (iter.get_glyph ());
798 799 800 801
      (this+ligatureSet[iter.get_coverage ()]).collect_glyphs (c);
    }
  }

802 803 804 805 806
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

807
  inline bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
808
  {
B
Behdad Esfahbod 已提交
809
    TRACE_WOULD_APPLY (this);
810
    unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
811 812 813 814
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);

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

B
Behdad Esfahbod 已提交
817
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
818
  {
B
Behdad Esfahbod 已提交
819
    TRACE_APPLY (this);
820
    hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
821

822
    unsigned int index = (this+coverage).get_coverage (glyph_id);
823
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
824

B
Behdad Esfahbod 已提交
825
    const LigatureSet &lig_set = this+ligatureSet[index];
826
    return TRACE_RETURN (lig_set.apply (c));
827
  }
B
Behdad Esfahbod 已提交
828

829 830 831 832 833 834 835 836
  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 已提交
837
    TRACE_SERIALIZE (this);
838 839 840 841 842 843 844 845 846
    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
    if (unlikely (!ligatureSet.serialize (c, num_first_glyphs))) return TRACE_RETURN (false);
    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],
								   component_list))) return TRACE_RETURN (false);
    ligature_per_first_glyph_count_list.advance (num_first_glyphs);
847
    if (unlikely (!coverage.serialize (c, this).serialize (c, first_glyphs, num_first_glyphs))) return TRACE_RETURN (false);
848 849 850
    return TRACE_RETURN (true);
  }

B
Behdad Esfahbod 已提交
851
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
852
    TRACE_SANITIZE (this);
853
    return TRACE_RETURN (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
854 855
  }

856
  protected:
B
Behdad Esfahbod 已提交
857
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
858 859
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
860
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
861
  OffsetArrayOf<LigatureSet>
B
Behdad Esfahbod 已提交
862 863
		ligatureSet;		/* Array LigatureSet tables
					 * ordered by Coverage Index */
864
  public:
865
  DEFINE_SIZE_ARRAY (6, ligatureSet);
B
Behdad Esfahbod 已提交
866
};
867

B
Behdad Esfahbod 已提交
868 869
struct LigatureSubst
{
870 871 872 873 874 875 876 877
  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 已提交
878
    TRACE_SERIALIZE (this);
879 880 881 882 883 884 885 886 887 888
    if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
    unsigned int format = 1;
    u.format.set (format);
    switch (u.format) {
    case 1: return TRACE_RETURN (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_RETURN (false);
    }
  }

B
Behdad Esfahbod 已提交
889 890 891 892 893 894 895 896 897 898
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
  {
    TRACE_DISPATCH (this);
    switch (u.format) {
    case 1: return TRACE_RETURN (c->dispatch (u.format1));
    default:return TRACE_RETURN (c->default_return_value ());
    }
  }

B
Behdad Esfahbod 已提交
899
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
900
    TRACE_SANITIZE (this);
901
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
902
    switch (u.format) {
903 904
    case 1: return TRACE_RETURN (u.format1.sanitize (c));
    default:return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
905 906 907
    }
  }

908
  protected:
909
  union {
B
Behdad Esfahbod 已提交
910
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
911
  LigatureSubstFormat1	format1;
912 913 914
  } u;
};

B
Behdad Esfahbod 已提交
915

B
Minor  
Behdad Esfahbod 已提交
916
struct ContextSubst : Context {};
B
Behdad Esfahbod 已提交
917

B
Minor  
Behdad Esfahbod 已提交
918
struct ChainContextSubst : ChainContext {};
919

B
Behdad Esfahbod 已提交
920
struct ExtensionSubst : Extension<ExtensionSubst>
B
Behdad Esfahbod 已提交
921
{
922
  typedef struct SubstLookupSubTable LookupSubTable;
B
Behdad Esfahbod 已提交
923

B
Behdad Esfahbod 已提交
924
  inline bool is_reverse (void) const;
925 926 927
};


B
Behdad Esfahbod 已提交
928 929
struct ReverseChainSingleSubstFormat1
{
B
Behdad Esfahbod 已提交
930
  inline void closure (hb_closure_context_t *c) const
931
  {
B
Behdad Esfahbod 已提交
932
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
933 934 935 936 937 938 939
    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 已提交
940
        return;
B
Behdad Esfahbod 已提交
941 942 943 944

    count = lookahead.len;
    for (unsigned int i = 0; i < count; i++)
      if (!(this+lookahead[i]).intersects (c->glyphs))
B
Behdad Esfahbod 已提交
945
        return;
B
Behdad Esfahbod 已提交
946 947 948 949 950

    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
    Coverage::Iter iter;
    for (iter.init (this+coverage); iter.more (); iter.next ()) {
      if (c->glyphs->has (iter.get_glyph ()))
B
Behdad Esfahbod 已提交
951
	c->glyphs->add (substitute[iter.get_coverage ()]);
B
Behdad Esfahbod 已提交
952
    }
953 954
  }

955 956
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
957 958
    TRACE_COLLECT_GLYPHS (this);

959 960 961 962
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);

    unsigned int count;

B
Minor  
Behdad Esfahbod 已提交
963
    (this+coverage).add_coverage (c->input);
964 965 966

    count = backtrack.len;
    for (unsigned int i = 0; i < count; i++)
B
Minor  
Behdad Esfahbod 已提交
967
      (this+backtrack[i]).add_coverage (c->before);
968 969 970

    count = lookahead.len;
    for (unsigned int i = 0; i < count; i++)
B
Minor  
Behdad Esfahbod 已提交
971
      (this+lookahead[i]).add_coverage (c->after);
972 973 974 975

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

979 980 981 982 983
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

984 985
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
986
    TRACE_WOULD_APPLY (this);
987
    return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
988 989
  }

B
Behdad Esfahbod 已提交
990
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
991
  {
B
Behdad Esfahbod 已提交
992
    TRACE_APPLY (this);
993 994
    if (unlikely (c->nesting_level_left != MAX_NESTING_LEVEL))
      return TRACE_RETURN (false); /* No chaining to this type */
995

996
    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
997
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
998

999 1000
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
1001

B
Behdad Esfahbod 已提交
1002
    if (match_backtrack (c,
B
Behdad Esfahbod 已提交
1003
			 backtrack.len, (USHORT *) backtrack.array,
B
Behdad Esfahbod 已提交
1004
			 match_coverage, this) &&
B
Behdad Esfahbod 已提交
1005
        match_lookahead (c,
B
Behdad Esfahbod 已提交
1006
			 lookahead.len, (USHORT *) lookahead.array,
B
Behdad Esfahbod 已提交
1007
			 match_coverage, this,
1008 1009
			 1))
    {
B
Behdad Esfahbod 已提交
1010
      c->replace_glyph_inplace (substitute[index]);
1011 1012 1013
      /* 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. */
1014
      return TRACE_RETURN (true);
1015 1016
    }

1017
    return TRACE_RETURN (false);
1018
  }
B
Behdad Esfahbod 已提交
1019

B
Behdad Esfahbod 已提交
1020
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
1021
    TRACE_SANITIZE (this);
1022 1023
    if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
      return TRACE_RETURN (false);
1024
    OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
B
Behdad Esfahbod 已提交
1025
    if (!lookahead.sanitize (c, this))
1026
      return TRACE_RETURN (false);
1027
    ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
1028
    return TRACE_RETURN (substitute.sanitize (c));
B
Behdad Esfahbod 已提交
1029 1030
  }

1031
  protected:
B
Behdad Esfahbod 已提交
1032
  USHORT	format;			/* Format identifier--format = 1 */
1033 1034 1035 1036 1037
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of table */
  OffsetArrayOf<Coverage>
		backtrack;		/* Array of coverage tables
B
Behdad Esfahbod 已提交
1038 1039
					 * in backtracking sequence, in  glyph
					 * sequence order */
1040 1041 1042
  OffsetArrayOf<Coverage>
		lookaheadX;		/* Array of coverage tables
					 * in lookahead sequence, in glyph
B
Behdad Esfahbod 已提交
1043
					 * sequence order */
1044 1045 1046
  ArrayOf<GlyphID>
		substituteX;		/* Array of substitute
					 * GlyphIDs--ordered by Coverage Index */
1047
  public:
B
Behdad Esfahbod 已提交
1048
  DEFINE_SIZE_MIN (10);
B
Behdad Esfahbod 已提交
1049 1050
};

B
Behdad Esfahbod 已提交
1051 1052
struct ReverseChainSingleSubst
{
1053
  template <typename context_t>
1054
  inline typename context_t::return_t dispatch (context_t *c) const
1055
  {
1056
    TRACE_DISPATCH (this);
1057
    switch (u.format) {
1058
    case 1: return TRACE_RETURN (c->dispatch (u.format1));
B
Behdad Esfahbod 已提交
1059
    default:return TRACE_RETURN (c->default_return_value ());
1060 1061 1062
    }
  }

B
Behdad Esfahbod 已提交
1063
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
1064
    TRACE_SANITIZE (this);
1065
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1066
    switch (u.format) {
1067 1068
    case 1: return TRACE_RETURN (u.format1.sanitize (c));
    default:return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
1069 1070 1071
    }
  }

1072
  protected:
1073 1074
  union {
  USHORT				format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1075
  ReverseChainSingleSubstFormat1	format1;
1076 1077 1078 1079 1080
  } u;
};



B
Behdad Esfahbod 已提交
1081 1082 1083 1084
/*
 * SubstLookup
 */

B
Behdad Esfahbod 已提交
1085 1086
struct SubstLookupSubTable
{
B
Behdad Esfahbod 已提交
1087 1088
  friend struct SubstLookup;

B
Behdad Esfahbod 已提交
1089
  enum Type {
1090 1091 1092 1093 1094 1095 1096
    Single		= 1,
    Multiple		= 2,
    Alternate		= 3,
    Ligature		= 4,
    Context		= 5,
    ChainContext	= 6,
    Extension		= 7,
1097
    ReverseChainSingle	= 8
1098 1099
  };

1100
  template <typename context_t>
1101
  inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
1102
  {
1103
    TRACE_DISPATCH (this);
1104
    switch (lookup_type) {
1105 1106 1107 1108 1109 1110 1111 1112
    case Single:		return TRACE_RETURN (u.single.dispatch (c));
    case Multiple:		return TRACE_RETURN (u.multiple.dispatch (c));
    case Alternate:		return TRACE_RETURN (u.alternate.dispatch (c));
    case Ligature:		return TRACE_RETURN (u.ligature.dispatch (c));
    case Context:		return TRACE_RETURN (u.context.dispatch (c));
    case ChainContext:		return TRACE_RETURN (u.chainContext.dispatch (c));
    case Extension:		return TRACE_RETURN (u.extension.dispatch (c));
    case ReverseChainSingle:	return TRACE_RETURN (u.reverseChainContextSingle.dispatch (c));
B
Behdad Esfahbod 已提交
1113
    default:			return TRACE_RETURN (c->default_return_value ());
1114 1115 1116
    }
  }

B
Behdad Esfahbod 已提交
1117
  inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
B
Behdad Esfahbod 已提交
1118
    TRACE_SANITIZE (this);
1119
    if (!u.header.sub_format.sanitize (c))
1120
      return TRACE_RETURN (false);
1121
    switch (lookup_type) {
1122 1123 1124 1125
    case Single:		return TRACE_RETURN (u.single.sanitize (c));
    case Multiple:		return TRACE_RETURN (u.multiple.sanitize (c));
    case Alternate:		return TRACE_RETURN (u.alternate.sanitize (c));
    case Ligature:		return TRACE_RETURN (u.ligature.sanitize (c));
1126
    case Context:		return TRACE_RETURN (u.context.sanitize (c));
1127 1128 1129 1130
    case ChainContext:		return TRACE_RETURN (u.chainContext.sanitize (c));
    case Extension:		return TRACE_RETURN (u.extension.sanitize (c));
    case ReverseChainSingle:	return TRACE_RETURN (u.reverseChainContextSingle.sanitize (c));
    default:			return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
1131 1132 1133
    }
  }

1134
  protected:
B
Behdad Esfahbod 已提交
1135
  union {
1136 1137 1138
  struct {
    USHORT			sub_format;
  } header;
B
Behdad Esfahbod 已提交
1139 1140 1141 1142
  SingleSubst			single;
  MultipleSubst			multiple;
  AlternateSubst		alternate;
  LigatureSubst			ligature;
1143
  ContextSubst			context;
B
Behdad Esfahbod 已提交
1144 1145 1146
  ChainContextSubst		chainContext;
  ExtensionSubst		extension;
  ReverseChainSingleSubst	reverseChainContextSingle;
B
Behdad Esfahbod 已提交
1147
  } u;
B
Behdad Esfahbod 已提交
1148
  public:
1149
  DEFINE_SIZE_UNION (2, header.sub_format);
B
Behdad Esfahbod 已提交
1150 1151
};

1152

B
Behdad Esfahbod 已提交
1153 1154
struct SubstLookup : Lookup
{
1155 1156
  inline const SubstLookupSubTable& get_subtable (unsigned int i) const
  { return this+CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable)[i]; }
B
Behdad Esfahbod 已提交
1157

B
Behdad Esfahbod 已提交
1158
  inline static bool lookup_type_is_reverse (unsigned int lookup_type)
1159
  { return lookup_type == SubstLookupSubTable::ReverseChainSingle; }
B
Behdad Esfahbod 已提交
1160 1161

  inline bool is_reverse (void) const
B
Behdad Esfahbod 已提交
1162
  {
B
Behdad Esfahbod 已提交
1163
    unsigned int type = get_type ();
1164
    if (unlikely (type == SubstLookupSubTable::Extension))
1165
      return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
B
Behdad Esfahbod 已提交
1166
    return lookup_type_is_reverse (type);
B
Behdad Esfahbod 已提交
1167
  }
1168

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

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

B
Behdad Esfahbod 已提交
1183 1184 1185
  template <typename set_t>
  inline void add_coverage (set_t *glyphs) const
  {
1186
    hb_get_coverage_context_t c;
B
Behdad Esfahbod 已提交
1187 1188 1189
    const Coverage *last = NULL;
    unsigned int count = get_subtable_count ();
    for (unsigned int i = 0; i < count; i++) {
1190
      const Coverage *coverage = &get_subtable (i).dispatch (&c, get_type ());
1191 1192 1193
      if (coverage != last) {
        coverage->add_coverage (glyphs);
        last = coverage;
B
Behdad Esfahbod 已提交
1194 1195 1196 1197
      }
    }
  }

B
Behdad Esfahbod 已提交
1198
  inline bool would_apply (hb_would_apply_context_t *c, const hb_set_digest_t *digest) const
B
Behdad Esfahbod 已提交
1199
  {
B
Behdad Esfahbod 已提交
1200
    TRACE_WOULD_APPLY (this);
1201 1202
    if (unlikely (!c->len))  return TRACE_RETURN (false);
    if (!digest->may_have (c->glyphs[0]))  return TRACE_RETURN (false);
1203
      return TRACE_RETURN (dispatch (c));
B
Behdad Esfahbod 已提交
1204 1205
  }

1206
  inline bool apply_once (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1207
  {
B
Behdad Esfahbod 已提交
1208
    TRACE_APPLY (this);
1209
    if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props))
B
Behdad Esfahbod 已提交
1210
      return TRACE_RETURN (false);
1211
    return TRACE_RETURN (dispatch (c));
B
Behdad Esfahbod 已提交
1212
  }
1213

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

1216 1217 1218 1219 1220 1221 1222 1223 1224 1225
  inline SubstLookupSubTable& serialize_subtable (hb_serialize_context_t *c,
						  unsigned int i)
  { return CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable)[i].serialize (c, this); }

  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 已提交
1226
    TRACE_SERIALIZE (this);
1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237
    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Single, lookup_props, 1))) return TRACE_RETURN (false);
    return TRACE_RETURN (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes, num_glyphs));
  }

  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 已提交
1238
    TRACE_SERIALIZE (this);
1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250
    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Multiple, lookup_props, 1))) return TRACE_RETURN (false);
    return TRACE_RETURN (serialize_subtable (c, 0).u.multiple.serialize (c, glyphs, substitute_len_list, num_glyphs,
									 substitute_glyphs_list));
  }

  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 已提交
1251
    TRACE_SERIALIZE (this);
1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265
    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Alternate, lookup_props, 1))) return TRACE_RETURN (false);
    return TRACE_RETURN (serialize_subtable (c, 0).u.alternate.serialize (c, glyphs, alternate_len_list, num_glyphs,
									  alternate_glyphs_list));
  }

  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 已提交
1266
    TRACE_SERIALIZE (this);
1267 1268 1269 1270 1271
    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Ligature, lookup_props, 1))) return TRACE_RETURN (false);
    return TRACE_RETURN (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));
  }

B
Behdad Esfahbod 已提交
1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288
  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
  {
    TRACE_DISPATCH (this);
    unsigned int lookup_type = get_type ();
    unsigned int count = get_subtable_count ();
    for (unsigned int i = 0; i < count; i++) {
      typename context_t::return_t r = get_subtable (i).dispatch (c, lookup_type);
      if (c->stop_sublookup_iteration (r))
        return TRACE_RETURN (r);
    }
    return TRACE_RETURN (c->default_return_value ());
  }

1289 1290
  inline bool sanitize (hb_sanitize_context_t *c)
  {
B
Behdad Esfahbod 已提交
1291
    TRACE_SANITIZE (this);
1292
    if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false);
1293
    OffsetArrayOf<SubstLookupSubTable> &list = CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable);
B
Behdad Esfahbod 已提交
1294 1295 1296 1297 1298 1299
    if (unlikely (!list.sanitize (c, this, get_type ()))) return TRACE_RETURN (false);

    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 已提交
1300
       * a reverse type! */
B
Behdad Esfahbod 已提交
1301 1302 1303 1304 1305 1306 1307
      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)
	  return TRACE_RETURN (false);
    }
    return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
1308
  }
B
Behdad Esfahbod 已提交
1309 1310
};

B
Behdad Esfahbod 已提交
1311
typedef OffsetListOf<SubstLookup> SubstLookupList;
1312

B
Minor  
Behdad Esfahbod 已提交
1313
/*
B
Behdad Esfahbod 已提交
1314
 * GSUB -- The Glyph Substitution Table
B
Minor  
Behdad Esfahbod 已提交
1315 1316
 */

B
Behdad Esfahbod 已提交
1317 1318
struct GSUB : GSUBGPOS
{
1319
  static const hb_tag_t tableTag	= HB_OT_TAG_GSUB;
B
Minor  
Behdad Esfahbod 已提交
1320

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

1324 1325
  static inline void substitute_start (hb_font_t *font, hb_buffer_t *buffer);
  static inline void substitute_finish (hb_font_t *font, hb_buffer_t *buffer);
B
Behdad Esfahbod 已提交
1326

B
Behdad Esfahbod 已提交
1327
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
1328
    TRACE_SANITIZE (this);
1329
    if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false);
1330
    OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
1331
    return TRACE_RETURN (list.sanitize (c, this));
B
Behdad Esfahbod 已提交
1332
  }
1333 1334
  public:
  DEFINE_SIZE_STATIC (10);
B
Minor  
Behdad Esfahbod 已提交
1335
};
1336 1337


B
Behdad Esfahbod 已提交
1338
void
1339
GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer)
B
Behdad Esfahbod 已提交
1340
{
B
Behdad Esfahbod 已提交
1341
  _hb_buffer_allocate_gsubgpos_vars (buffer);
1342

1343
  const GDEF &gdef = *hb_ot_layout_from_face (font->face)->gdef;
B
Behdad Esfahbod 已提交
1344
  unsigned int count = buffer->len;
B
Behdad Esfahbod 已提交
1345 1346
  for (unsigned int i = 0; i < count; i++)
  {
1347
    _hb_glyph_info_set_glyph_props (&buffer->info[i], gdef.get_glyph_props (buffer->info[i].codepoint));
B
Behdad Esfahbod 已提交
1348 1349
    _hb_glyph_info_clear_lig_props (&buffer->info[i]);
    buffer->info[i].syllable() = 0;
1350
  }
B
Behdad Esfahbod 已提交
1351 1352 1353
}

void
1354
GSUB::substitute_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSED)
B
Behdad Esfahbod 已提交
1355 1356 1357 1358
{
}


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

1361
/*static*/ inline bool ExtensionSubst::is_reverse (void) const
B
Behdad Esfahbod 已提交
1362 1363
{
  unsigned int type = get_type ();
1364
  if (unlikely (type == SubstLookupSubTable::Extension))
1365
    return CastR<ExtensionSubst> (get_subtable<SubstLookupSubTable>()).is_reverse ();
B
Behdad Esfahbod 已提交
1366 1367 1368
  return SubstLookup::lookup_type_is_reverse (type);
}

1369
template <typename context_t>
1370
/*static*/ inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
1371 1372 1373
{
  const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
  const SubstLookup &l = gsub.get_lookup (lookup_index);
1374
  return l.dispatch (c);
1375 1376
}

1377
/*static*/ inline bool SubstLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
B
Behdad Esfahbod 已提交
1378
{
1379
  const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
1380
  const SubstLookup &l = gsub.get_lookup (lookup_index);
1381
  unsigned int saved_lookup_props = c->lookup_props;
1382
  c->set_lookup (l);
1383 1384 1385
  bool ret = l.apply_once (c);
  c->lookup_props = saved_lookup_props;
  return ret;
1386 1387 1388
}


B
Behdad Esfahbod 已提交
1389
} /* namespace OT */
1390

B
Behdad Esfahbod 已提交
1391

1392
#endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */