hb-ot-layout-gsub-table.hh 42.5 KB
Newer Older
B
Behdad Esfahbod 已提交
1
/*
B
Behdad Esfahbod 已提交
2
 * Copyright © 2007,2008,2009,2010  Red Hat, Inc.
B
Behdad Esfahbod 已提交
3
 * Copyright © 2010,2012  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 53 54 55 56 57 58 59 60
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    Coverage::Iter iter;
    for (iter.init (this+coverage); iter.more (); iter.next ()) {
      hb_codepoint_t glyph_id = iter.get_glyph ();
      c->input.add (glyph_id);
      c->output.add ((glyph_id + deltaGlyphID) & 0xFFFF);
    }
  }

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

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

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

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

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

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

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

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

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

127 128 129 130 131 132 133 134 135
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    Coverage::Iter iter;
    for (iter.init (this+coverage); iter.more (); iter.next ()) {
      c->input.add (iter.get_glyph ());
      c->output.add (substitute[iter.get_coverage ()]);
    }
  }

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

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

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

154
    if (unlikely (index >= substitute.len)) return TRACE_RETURN (false);
155 156

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

159
    return TRACE_RETURN (true);
160
  }
B
Behdad Esfahbod 已提交
161

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

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

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

B
Behdad Esfahbod 已提交
191 192
struct SingleSubst
{
193 194
  template <typename context_t>
  inline typename context_t::return_t process (context_t *c) const
195
  {
B
Behdad Esfahbod 已提交
196
    TRACE_PROCESS (this);
197
    switch (u.format) {
B
Behdad Esfahbod 已提交
198 199 200
    case 1: return TRACE_RETURN (c->process (u.format1));
    case 2: return TRACE_RETURN (c->process (u.format2));
    default:return TRACE_RETURN (c->default_return_value ());
201 202 203
    }
  }

B
Behdad Esfahbod 已提交
204
  inline bool serialize (hb_serialize_context_t *c,
205 206
			 Supplier<GlyphID> &glyphs,
			 Supplier<GlyphID> &substitutes,
B
Behdad Esfahbod 已提交
207 208
			 unsigned int num_glyphs)
  {
B
Behdad Esfahbod 已提交
209
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
210 211
    if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
    unsigned int format = 2;
B
Minor  
Behdad Esfahbod 已提交
212
    int delta;
B
Behdad Esfahbod 已提交
213 214
    if (num_glyphs) {
      format = 1;
B
Minor  
Behdad Esfahbod 已提交
215
      /* TODO(serialize) check for wrap-around */
B
Behdad Esfahbod 已提交
216 217 218 219 220 221 222 223 224 225 226 227 228 229 230
      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 已提交
231
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
232
    TRACE_SANITIZE (this);
233
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
234
    switch (u.format) {
235 236 237
    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 已提交
238 239 240
    }
  }

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

B
Behdad Esfahbod 已提交
249

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

260 261 262 263 264 265 266
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    unsigned int count = substitute.len;
    for (unsigned int i = 0; i < count; i++)
      c->output.add (substitute[i]);
  }

B
Behdad Esfahbod 已提交
267
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
268
  {
B
Behdad Esfahbod 已提交
269
    TRACE_APPLY (this);
270
    if (unlikely (!substitute.len)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
271

272
    unsigned int klass = c->property & HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE ? HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
273
    unsigned int count = substitute.len;
274
    for (unsigned int i = 0; i < count; i++) {
B
Behdad Esfahbod 已提交
275
      set_lig_props_for_component (c->buffer->cur(), i);
276
      c->output_glyph (substitute.array[i], klass);
277
    }
278
    c->buffer->skip_glyph ();
B
Behdad Esfahbod 已提交
279

280
    return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
281 282
  }

283
  inline bool serialize (hb_serialize_context_t *c,
284
			 Supplier<GlyphID> &glyphs,
285 286
			 unsigned int num_glyphs)
  {
B
Behdad Esfahbod 已提交
287
    TRACE_SERIALIZE (this);
288 289 290 291 292
    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 已提交
293
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
294
    TRACE_SANITIZE (this);
295
    return TRACE_RETURN (substitute.sanitize (c));
B
Behdad Esfahbod 已提交
296 297
  }

298
  protected:
B
Behdad Esfahbod 已提交
299 300
  ArrayOf<GlyphID>
		substitute;		/* String of GlyphIDs to substitute */
301
  public:
302
  DEFINE_SIZE_ARRAY (2, substitute);
B
Behdad Esfahbod 已提交
303 304
};

B
Behdad Esfahbod 已提交
305 306
struct MultipleSubstFormat1
{
B
Behdad Esfahbod 已提交
307
  inline void closure (hb_closure_context_t *c) const
308
  {
B
Behdad Esfahbod 已提交
309
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
310 311 312
    Coverage::Iter iter;
    for (iter.init (this+coverage); iter.more (); iter.next ()) {
      if (c->glyphs->has (iter.get_glyph ()))
B
Behdad Esfahbod 已提交
313
	(this+sequence[iter.get_coverage ()]).closure (c);
B
Behdad Esfahbod 已提交
314
    }
315 316
  }

317 318 319 320 321 322 323 324
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    (this+coverage).add_coverage (&c->input);
    unsigned int count = sequence.len;
    for (unsigned int i = 0; i < count; i++)
	(this+sequence[i]).collect_glyphs (c);
  }

325 326 327 328 329
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

330 331
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
332
    TRACE_WOULD_APPLY (this);
333 334 335
    return TRACE_RETURN (c->len == 1 && (this+coverage) (c->glyphs[0]) != NOT_COVERED);
  }

B
Behdad Esfahbod 已提交
336
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
337
  {
B
Behdad Esfahbod 已提交
338
    TRACE_APPLY (this);
339

340
    unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
341
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
342

343
    return TRACE_RETURN ((this+sequence[index]).apply (c));
344
  }
B
Behdad Esfahbod 已提交
345

346
  inline bool serialize (hb_serialize_context_t *c,
347 348
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &substitute_len_list,
349
			 unsigned int num_glyphs,
350
			 Supplier<GlyphID> &substitute_glyphs_list)
351
  {
B
Behdad Esfahbod 已提交
352
    TRACE_SERIALIZE (this);
353 354
    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
    if (unlikely (!sequence.serialize (c, num_glyphs))) return TRACE_RETURN (false);
355 356 357 358 359
    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);
360
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
361 362 363
    return TRACE_RETURN (true);
  }

B
Behdad Esfahbod 已提交
364
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
365
    TRACE_SANITIZE (this);
366
    return TRACE_RETURN (coverage.sanitize (c, this) && sequence.sanitize (c, this));
B
Behdad Esfahbod 已提交
367 368
  }

369
  protected:
B
Behdad Esfahbod 已提交
370
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
371 372
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
373
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
374 375 376
  OffsetArrayOf<Sequence>
		sequence;		/* Array of Sequence tables
					 * ordered by Coverage Index */
377
  public:
378
  DEFINE_SIZE_ARRAY (6, sequence);
B
Behdad Esfahbod 已提交
379
};
380

B
Behdad Esfahbod 已提交
381 382
struct MultipleSubst
{
383 384
  template <typename context_t>
  inline typename context_t::return_t process (context_t *c) const
385
  {
B
Behdad Esfahbod 已提交
386
    TRACE_PROCESS (this);
387
    switch (u.format) {
B
Behdad Esfahbod 已提交
388 389
    case 1: return TRACE_RETURN (c->process (u.format1));
    default:return TRACE_RETURN (c->default_return_value ());
390 391 392
    }
  }

393
  inline bool serialize (hb_serialize_context_t *c,
394 395
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &substitute_len_list,
396
			 unsigned int num_glyphs,
397
			 Supplier<GlyphID> &substitute_glyphs_list)
398
  {
B
Behdad Esfahbod 已提交
399
    TRACE_SERIALIZE (this);
400 401 402 403 404 405 406 407 408
    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 已提交
409
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
410
    TRACE_SANITIZE (this);
411
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
412
    switch (u.format) {
413 414
    case 1: return TRACE_RETURN (u.format1.sanitize (c));
    default:return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
415 416 417
    }
  }

418
  protected:
419
  union {
B
Behdad Esfahbod 已提交
420
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
421
  MultipleSubstFormat1	format1;
422 423 424
  } u;
};

B
Behdad Esfahbod 已提交
425

B
Behdad Esfahbod 已提交
426
typedef ArrayOf<GlyphID> AlternateSet;	/* Array of alternate GlyphIDs--in
B
Behdad Esfahbod 已提交
427 428
					 * arbitrary order */

B
Behdad Esfahbod 已提交
429 430
struct AlternateSubstFormat1
{
B
Behdad Esfahbod 已提交
431
  inline void closure (hb_closure_context_t *c) const
432
  {
B
Behdad Esfahbod 已提交
433
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
434 435 436 437 438 439
    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 已提交
440
	  c->glyphs->add (alt_set[i]);
B
Behdad Esfahbod 已提交
441 442
      }
    }
443 444
  }

445 446 447 448 449 450 451 452 453 454 455 456
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    Coverage::Iter iter;
    for (iter.init (this+coverage); iter.more (); iter.next ()) {
      c->input.add (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++)
	c->output.add (alt_set[i]);
    }
  }

457 458 459 460 461
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

462 463
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
464
    TRACE_WOULD_APPLY (this);
465 466 467
    return TRACE_RETURN (c->len == 1 && (this+coverage) (c->glyphs[0]) != NOT_COVERED);
  }

B
Behdad Esfahbod 已提交
468
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
469
  {
B
Behdad Esfahbod 已提交
470
    TRACE_APPLY (this);
471
    hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
472

B
Behdad Esfahbod 已提交
473
    unsigned int index = (this+coverage) (glyph_id);
474
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
475

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

478
    if (unlikely (!alt_set.len)) return TRACE_RETURN (false);
479

480
    hb_mask_t glyph_mask = c->buffer->cur().mask;
B
Behdad Esfahbod 已提交
481 482
    hb_mask_t lookup_mask = c->lookup_mask;

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

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

B
Behdad Esfahbod 已提交
489
    glyph_id = alt_set[alt_index - 1];
490

491
    c->replace_glyph (glyph_id);
492

493
    return TRACE_RETURN (true);
494
  }
B
Behdad Esfahbod 已提交
495

496
  inline bool serialize (hb_serialize_context_t *c,
497 498
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &alternate_len_list,
499
			 unsigned int num_glyphs,
500
			 Supplier<GlyphID> &alternate_glyphs_list)
501
  {
B
Behdad Esfahbod 已提交
502
    TRACE_SERIALIZE (this);
503 504
    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
    if (unlikely (!alternateSet.serialize (c, num_glyphs))) return TRACE_RETURN (false);
505 506 507 508 509
    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);
510
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
511 512 513
    return TRACE_RETURN (true);
  }

B
Behdad Esfahbod 已提交
514
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
515
    TRACE_SANITIZE (this);
516
    return TRACE_RETURN (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
517 518
  }

519
  protected:
B
Behdad Esfahbod 已提交
520
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
521 522
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
523
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
524 525 526
  OffsetArrayOf<AlternateSet>
		alternateSet;		/* Array of AlternateSet tables
					 * ordered by Coverage Index */
527
  public:
528
  DEFINE_SIZE_ARRAY (6, alternateSet);
B
Behdad Esfahbod 已提交
529
};
530

B
Behdad Esfahbod 已提交
531 532
struct AlternateSubst
{
533 534
  template <typename context_t>
  inline typename context_t::return_t process (context_t *c) const
535
  {
B
Behdad Esfahbod 已提交
536
    TRACE_PROCESS (this);
537
    switch (u.format) {
B
Behdad Esfahbod 已提交
538 539
    case 1: return TRACE_RETURN (c->process (u.format1));
    default:return TRACE_RETURN (c->default_return_value ());
540 541 542
    }
  }

543
  inline bool serialize (hb_serialize_context_t *c,
544 545
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &alternate_len_list,
546
			 unsigned int num_glyphs,
547
			 Supplier<GlyphID> &alternate_glyphs_list)
548
  {
B
Behdad Esfahbod 已提交
549
    TRACE_SERIALIZE (this);
550 551 552 553 554 555 556 557 558
    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 已提交
559
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
560
    TRACE_SANITIZE (this);
561
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
562
    switch (u.format) {
563 564
    case 1: return TRACE_RETURN (u.format1.sanitize (c));
    default:return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
565 566 567
    }
  }

568
  protected:
569
  union {
B
Behdad Esfahbod 已提交
570
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
571
  AlternateSubstFormat1	format1;
572 573 574
  } u;
};

575

B
Behdad Esfahbod 已提交
576 577
struct Ligature
{
B
Behdad Esfahbod 已提交
578
  inline void closure (hb_closure_context_t *c) const
579
  {
B
Behdad Esfahbod 已提交
580
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
581 582 583
    unsigned int count = component.len;
    for (unsigned int i = 1; i < count; i++)
      if (!c->glyphs->has (component[i]))
B
Behdad Esfahbod 已提交
584 585
        return;
    c->glyphs->add (ligGlyph);
586 587
  }

588 589 590 591 592 593 594 595
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    unsigned int count = component.len;
    for (unsigned int i = 1; i < count; i++)
      c->input.add (component[i]);
    c->output.add (ligGlyph);
  }

596
  inline bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
597
  {
B
Behdad Esfahbod 已提交
598
    TRACE_WOULD_APPLY (this);
599
    if (c->len != component.len)
600
      return TRACE_RETURN (false);
601 602 603

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

606
    return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
607 608
  }

609
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
610
  {
B
Behdad Esfahbod 已提交
611
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
612
    unsigned int count = component.len;
613
    if (unlikely (count < 1)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
614

B
Behdad Esfahbod 已提交
615 616 617
    unsigned int end_offset = 0;
    bool is_mark_ligature = false;
    unsigned int total_component_count = 0;
618 619 620 621 622 623 624 625 626

    if (likely (!match_input (c, count,
			      &component[1],
			      match_glyph,
			      NULL,
			      &end_offset,
			      &is_mark_ligature,
			      &total_component_count)))
      return TRACE_RETURN (false);
627

628
    /* Deal, we are forming the ligature. */
629
    c->buffer->merge_clusters (c->buffer->idx, c->buffer->idx + end_offset);
630

631 632 633 634 635 636 637 638
    ligate_input (c,
		  count,
		  &component[1],
		  ligGlyph,
		  match_glyph,
		  NULL,
		  is_mark_ligature,
		  total_component_count);
639

640
    return TRACE_RETURN (true);
641
  }
642

643 644 645 646 647
  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 已提交
648
    TRACE_SERIALIZE (this);
649
    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
650
    ligGlyph = ligature;
651 652 653 654
    if (unlikely (!component.serialize (c, components, num_components))) return TRACE_RETURN (false);
    return TRACE_RETURN (true);
  }

B
Behdad Esfahbod 已提交
655
  public:
B
Behdad Esfahbod 已提交
656
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
657
    TRACE_SANITIZE (this);
658
    return TRACE_RETURN (ligGlyph.sanitize (c) && component.sanitize (c));
B
Behdad Esfahbod 已提交
659 660
  }

661
  protected:
662
  GlyphID	ligGlyph;		/* GlyphID of ligature to substitute */
B
Behdad Esfahbod 已提交
663 664
  HeadlessArrayOf<GlyphID>
		component;		/* Array of component GlyphIDs--start
665 666
					 * with the second  component--ordered
					 * in writing direction */
667
  public:
668
  DEFINE_SIZE_ARRAY (4, component);
669
};
B
Behdad Esfahbod 已提交
670

B
Behdad Esfahbod 已提交
671 672
struct LigatureSet
{
B
Behdad Esfahbod 已提交
673
  inline void closure (hb_closure_context_t *c) const
674
  {
B
Behdad Esfahbod 已提交
675
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
676 677
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
B
Behdad Esfahbod 已提交
678
      (this+ligature[i]).closure (c);
679 680
  }

681 682 683 684 685 686 687
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
      (this+ligature[i]).collect_glyphs (c);
  }

688
  inline bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
689
  {
B
Behdad Esfahbod 已提交
690
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
691 692 693 694
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
    {
      const Ligature &lig = this+ligature[i];
695
      if (lig.would_apply (c))
696
        return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
697
    }
698
    return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
699 700
  }

701
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
702
  {
B
Behdad Esfahbod 已提交
703
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
704
    unsigned int num_ligs = ligature.len;
B
Behdad Esfahbod 已提交
705 706
    for (unsigned int i = 0; i < num_ligs; i++)
    {
B
Behdad Esfahbod 已提交
707
      const Ligature &lig = this+ligature[i];
708
      if (lig.apply (c)) return TRACE_RETURN (true);
709 710
    }

711
    return TRACE_RETURN (false);
712
  }
B
Behdad Esfahbod 已提交
713

714 715 716 717 718 719
  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 已提交
720
    TRACE_SERIALIZE (this);
721 722 723 724 725 726 727
    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);
728
    ligatures.advance (num_ligatures);
729 730 731 732
    component_count_list.advance (num_ligatures);
    return TRACE_RETURN (true);
  }

B
Behdad Esfahbod 已提交
733
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
734
    TRACE_SANITIZE (this);
735
    return TRACE_RETURN (ligature.sanitize (c, this));
B
Behdad Esfahbod 已提交
736 737
  }

738
  protected:
B
Behdad Esfahbod 已提交
739 740 741
  OffsetArrayOf<Ligature>
		ligature;		/* Array LigatureSet tables
					 * ordered by preference */
742
  public:
743
  DEFINE_SIZE_ARRAY (2, ligature);
B
Behdad Esfahbod 已提交
744 745
};

B
Behdad Esfahbod 已提交
746 747
struct LigatureSubstFormat1
{
B
Behdad Esfahbod 已提交
748
  inline void closure (hb_closure_context_t *c) const
749
  {
B
Behdad Esfahbod 已提交
750
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
751 752 753
    Coverage::Iter iter;
    for (iter.init (this+coverage); iter.more (); iter.next ()) {
      if (c->glyphs->has (iter.get_glyph ()))
B
Behdad Esfahbod 已提交
754
	(this+ligatureSet[iter.get_coverage ()]).closure (c);
B
Behdad Esfahbod 已提交
755
    }
756 757
  }

758 759 760 761 762 763 764 765 766
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    Coverage::Iter iter;
    for (iter.init (this+coverage); iter.more (); iter.next ()) {
      c->input.add (iter.get_glyph ());
      (this+ligatureSet[iter.get_coverage ()]).collect_glyphs (c);
    }
  }

767 768 769 770 771
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

772
  inline bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
773
  {
B
Behdad Esfahbod 已提交
774
    TRACE_WOULD_APPLY (this);
775 776 777 778 779
    unsigned int index = (this+coverage) (c->glyphs[0]);
    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 已提交
780 781
  }

B
Behdad Esfahbod 已提交
782
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
783
  {
B
Behdad Esfahbod 已提交
784
    TRACE_APPLY (this);
785
    hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
786

B
Behdad Esfahbod 已提交
787
    unsigned int index = (this+coverage) (glyph_id);
788
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
789

B
Behdad Esfahbod 已提交
790
    const LigatureSet &lig_set = this+ligatureSet[index];
791
    return TRACE_RETURN (lig_set.apply (c));
792
  }
B
Behdad Esfahbod 已提交
793

794 795 796 797 798 799 800 801
  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 已提交
802
    TRACE_SERIALIZE (this);
803 804 805 806 807 808 809 810 811
    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);
812
    if (unlikely (!coverage.serialize (c, this).serialize (c, first_glyphs, num_first_glyphs))) return TRACE_RETURN (false);
813 814 815
    return TRACE_RETURN (true);
  }

B
Behdad Esfahbod 已提交
816
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
817
    TRACE_SANITIZE (this);
818
    return TRACE_RETURN (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
819 820
  }

821
  protected:
B
Behdad Esfahbod 已提交
822
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
823 824
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
825
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
826
  OffsetArrayOf<LigatureSet>
B
Behdad Esfahbod 已提交
827 828
		ligatureSet;		/* Array LigatureSet tables
					 * ordered by Coverage Index */
829
  public:
830
  DEFINE_SIZE_ARRAY (6, ligatureSet);
B
Behdad Esfahbod 已提交
831
};
832

B
Behdad Esfahbod 已提交
833 834
struct LigatureSubst
{
835 836
  template <typename context_t>
  inline typename context_t::return_t process (context_t *c) const
837
  {
B
Behdad Esfahbod 已提交
838
    TRACE_PROCESS (this);
839
    switch (u.format) {
B
Behdad Esfahbod 已提交
840 841
    case 1: return TRACE_RETURN (c->process (u.format1));
    default:return TRACE_RETURN (c->default_return_value ());
B
Behdad Esfahbod 已提交
842 843 844
    }
  }

845 846 847 848 849 850 851 852
  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 已提交
853
    TRACE_SERIALIZE (this);
854 855 856 857 858 859 860 861 862 863
    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 已提交
864
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
865
    TRACE_SANITIZE (this);
866
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
867
    switch (u.format) {
868 869
    case 1: return TRACE_RETURN (u.format1.sanitize (c));
    default:return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
870 871 872
    }
  }

873
  protected:
874
  union {
B
Behdad Esfahbod 已提交
875
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
876
  LigatureSubstFormat1	format1;
877 878 879
  } u;
};

B
Behdad Esfahbod 已提交
880

B
Minor  
Behdad Esfahbod 已提交
881
struct ContextSubst : Context {};
B
Behdad Esfahbod 已提交
882

B
Minor  
Behdad Esfahbod 已提交
883
struct ChainContextSubst : ChainContext {};
884

B
Behdad Esfahbod 已提交
885
struct ExtensionSubst : Extension<ExtensionSubst>
B
Behdad Esfahbod 已提交
886
{
887
  typedef struct SubstLookupSubTable LookupSubTable;
B
Behdad Esfahbod 已提交
888

B
Behdad Esfahbod 已提交
889
  inline bool is_reverse (void) const;
890 891 892
};


B
Behdad Esfahbod 已提交
893 894
struct ReverseChainSingleSubstFormat1
{
B
Behdad Esfahbod 已提交
895
  inline void closure (hb_closure_context_t *c) const
896
  {
B
Behdad Esfahbod 已提交
897
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
898 899 900 901 902 903 904
    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 已提交
905
        return;
B
Behdad Esfahbod 已提交
906 907 908 909

    count = lookahead.len;
    for (unsigned int i = 0; i < count; i++)
      if (!(this+lookahead[i]).intersects (c->glyphs))
B
Behdad Esfahbod 已提交
910
        return;
B
Behdad Esfahbod 已提交
911 912 913 914 915

    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 已提交
916
	c->glyphs->add (substitute[iter.get_coverage ()]);
B
Behdad Esfahbod 已提交
917
    }
918 919
  }

920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);

    unsigned int count;

    (this+coverage).add_coverage (&c->input);

    count = backtrack.len;
    for (unsigned int i = 0; i < count; i++)
      (this+backtrack[i]).add_coverage (&c->before);

    count = lookahead.len;
    for (unsigned int i = 0; i < count; i++)
      (this+lookahead[i]).add_coverage (&c->after);

    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
    count = substitute.len;
    for (unsigned int i = 0; i < count; i++)
      c->output.add (substitute[i]);
  }

942 943 944 945 946
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

947 948
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
949
    TRACE_WOULD_APPLY (this);
950 951 952
    return TRACE_RETURN (c->len == 1 && (this+coverage) (c->glyphs[0]) != NOT_COVERED);
  }

B
Behdad Esfahbod 已提交
953
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
954
  {
B
Behdad Esfahbod 已提交
955
    TRACE_APPLY (this);
956 957
    if (unlikely (c->nesting_level_left != MAX_NESTING_LEVEL))
      return TRACE_RETURN (false); /* No chaining to this type */
958

959
    unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
960
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
961

962 963
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
964

B
Behdad Esfahbod 已提交
965
    if (match_backtrack (c,
B
Behdad Esfahbod 已提交
966
			 backtrack.len, (USHORT *) backtrack.array,
B
Behdad Esfahbod 已提交
967
			 match_coverage, this) &&
B
Behdad Esfahbod 已提交
968
        match_lookahead (c,
B
Behdad Esfahbod 已提交
969
			 lookahead.len, (USHORT *) lookahead.array,
B
Behdad Esfahbod 已提交
970
			 match_coverage, this,
971 972
			 1))
    {
B
Behdad Esfahbod 已提交
973
      c->replace_glyph_inplace (substitute[index]);
974
      c->buffer->idx--; /* Reverse! */
975
      return TRACE_RETURN (true);
976 977
    }

978
    return TRACE_RETURN (false);
979
  }
B
Behdad Esfahbod 已提交
980

B
Behdad Esfahbod 已提交
981
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
982
    TRACE_SANITIZE (this);
983 984
    if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
      return TRACE_RETURN (false);
985
    OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
B
Behdad Esfahbod 已提交
986
    if (!lookahead.sanitize (c, this))
987
      return TRACE_RETURN (false);
988
    ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
989
    return TRACE_RETURN (substitute.sanitize (c));
B
Behdad Esfahbod 已提交
990 991
  }

992
  protected:
B
Behdad Esfahbod 已提交
993
  USHORT	format;			/* Format identifier--format = 1 */
994 995 996 997 998
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of table */
  OffsetArrayOf<Coverage>
		backtrack;		/* Array of coverage tables
B
Behdad Esfahbod 已提交
999 1000
					 * in backtracking sequence, in  glyph
					 * sequence order */
1001 1002 1003
  OffsetArrayOf<Coverage>
		lookaheadX;		/* Array of coverage tables
					 * in lookahead sequence, in glyph
B
Behdad Esfahbod 已提交
1004
					 * sequence order */
1005 1006 1007
  ArrayOf<GlyphID>
		substituteX;		/* Array of substitute
					 * GlyphIDs--ordered by Coverage Index */
1008
  public:
B
Behdad Esfahbod 已提交
1009
  DEFINE_SIZE_MIN (10);
B
Behdad Esfahbod 已提交
1010 1011
};

B
Behdad Esfahbod 已提交
1012 1013
struct ReverseChainSingleSubst
{
1014 1015
  template <typename context_t>
  inline typename context_t::return_t process (context_t *c) const
1016
  {
B
Behdad Esfahbod 已提交
1017
    TRACE_PROCESS (this);
1018
    switch (u.format) {
B
Behdad Esfahbod 已提交
1019 1020
    case 1: return TRACE_RETURN (c->process (u.format1));
    default:return TRACE_RETURN (c->default_return_value ());
1021 1022 1023
    }
  }

B
Behdad Esfahbod 已提交
1024
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
1025
    TRACE_SANITIZE (this);
1026
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1027
    switch (u.format) {
1028 1029
    case 1: return TRACE_RETURN (u.format1.sanitize (c));
    default:return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
1030 1031 1032
    }
  }

1033
  protected:
1034 1035
  union {
  USHORT				format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1036
  ReverseChainSingleSubstFormat1	format1;
1037 1038 1039 1040 1041
  } u;
};



B
Behdad Esfahbod 已提交
1042 1043 1044 1045
/*
 * SubstLookup
 */

B
Behdad Esfahbod 已提交
1046 1047
struct SubstLookupSubTable
{
B
Behdad Esfahbod 已提交
1048 1049
  friend struct SubstLookup;

B
Behdad Esfahbod 已提交
1050
  enum Type {
1051 1052 1053 1054 1055 1056 1057
    Single		= 1,
    Multiple		= 2,
    Alternate		= 3,
    Ligature		= 4,
    Context		= 5,
    ChainContext	= 6,
    Extension		= 7,
1058
    ReverseChainSingle	= 8
1059 1060
  };

1061 1062
  template <typename context_t>
  inline typename context_t::return_t process (context_t *c, unsigned int lookup_type) const
1063
  {
B
Behdad Esfahbod 已提交
1064
    TRACE_PROCESS (this);
1065
    switch (lookup_type) {
B
Behdad Esfahbod 已提交
1066 1067 1068 1069 1070 1071 1072 1073 1074
    case Single:		return TRACE_RETURN (u.single.process (c));
    case Multiple:		return TRACE_RETURN (u.multiple.process (c));
    case Alternate:		return TRACE_RETURN (u.alternate.process (c));
    case Ligature:		return TRACE_RETURN (u.ligature.process (c));
    case Context:		return TRACE_RETURN (u.context.process (c));
    case ChainContext:		return TRACE_RETURN (u.chainContext.process (c));
    case Extension:		return TRACE_RETURN (u.extension.process (c));
    case ReverseChainSingle:	return TRACE_RETURN (u.reverseChainContextSingle.process (c));
    default:			return TRACE_RETURN (c->default_return_value ());
1075 1076 1077
    }
  }

B
Behdad Esfahbod 已提交
1078
  inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
B
Behdad Esfahbod 已提交
1079
    TRACE_SANITIZE (this);
1080
    if (!u.header.sub_format.sanitize (c))
1081
      return TRACE_RETURN (false);
1082
    switch (lookup_type) {
1083 1084 1085 1086
    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));
1087
    case Context:		return TRACE_RETURN (u.context.sanitize (c));
1088 1089 1090 1091
    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 已提交
1092 1093 1094
    }
  }

1095
  protected:
B
Behdad Esfahbod 已提交
1096
  union {
1097 1098 1099
  struct {
    USHORT			sub_format;
  } header;
B
Behdad Esfahbod 已提交
1100 1101 1102 1103
  SingleSubst			single;
  MultipleSubst			multiple;
  AlternateSubst		alternate;
  LigatureSubst			ligature;
1104
  ContextSubst			context;
B
Behdad Esfahbod 已提交
1105 1106 1107
  ChainContextSubst		chainContext;
  ExtensionSubst		extension;
  ReverseChainSingleSubst	reverseChainContextSingle;
B
Behdad Esfahbod 已提交
1108
  } u;
B
Behdad Esfahbod 已提交
1109
  public:
1110
  DEFINE_SIZE_UNION (2, header.sub_format);
B
Behdad Esfahbod 已提交
1111 1112
};

1113

B
Behdad Esfahbod 已提交
1114 1115
struct SubstLookup : Lookup
{
1116 1117
  inline const SubstLookupSubTable& get_subtable (unsigned int i) const
  { return this+CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable)[i]; }
B
Behdad Esfahbod 已提交
1118

B
Behdad Esfahbod 已提交
1119
  inline static bool lookup_type_is_reverse (unsigned int lookup_type)
1120
  { return lookup_type == SubstLookupSubTable::ReverseChainSingle; }
B
Behdad Esfahbod 已提交
1121 1122

  inline bool is_reverse (void) const
B
Behdad Esfahbod 已提交
1123
  {
B
Behdad Esfahbod 已提交
1124
    unsigned int type = get_type ();
1125
    if (unlikely (type == SubstLookupSubTable::Extension))
1126
      return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
B
Behdad Esfahbod 已提交
1127
    return lookup_type_is_reverse (type);
B
Behdad Esfahbod 已提交
1128 1129
  }

1130 1131
  template <typename context_t>
  inline typename context_t::return_t process (context_t *c) const
1132
  {
B
Behdad Esfahbod 已提交
1133
    TRACE_PROCESS (this);
1134
    unsigned int lookup_type = get_type ();
B
Behdad Esfahbod 已提交
1135
    unsigned int count = get_subtable_count ();
1136 1137 1138
    for (unsigned int i = 0; i < count; i++) {
      typename context_t::return_t r = get_subtable (i).process (c, lookup_type);
      if (c->stop_sublookup_iteration (r))
B
Behdad Esfahbod 已提交
1139
        return TRACE_RETURN (r);
1140
    }
B
Behdad Esfahbod 已提交
1141
    return TRACE_RETURN (c->default_return_value ());
1142
  }
B
Behdad Esfahbod 已提交
1143

1144 1145 1146 1147 1148 1149 1150
  static inline void_t closure_recurse_func (hb_closure_context_t *c, unsigned int lookup_index);
  inline hb_closure_context_t::return_t closure (hb_closure_context_t *c) const
  {
    c->set_recurse_func (closure_recurse_func);
    return process (c);
  }

B
Behdad Esfahbod 已提交
1151 1152 1153
  template <typename set_t>
  inline void add_coverage (set_t *glyphs) const
  {
1154
    hb_get_coverage_context_t c;
B
Behdad Esfahbod 已提交
1155 1156 1157
    const Coverage *last = NULL;
    unsigned int count = get_subtable_count ();
    for (unsigned int i = 0; i < count; i++) {
1158 1159 1160 1161
      const Coverage *coverage = &get_subtable (i).process (&c, get_type ());
      if (coverage != last) {
        coverage->add_coverage (glyphs);
        last = coverage;
B
Behdad Esfahbod 已提交
1162 1163 1164 1165
      }
    }
  }

B
Behdad Esfahbod 已提交
1166
  inline bool would_apply (hb_would_apply_context_t *c, const hb_set_digest_t *digest) const
B
Behdad Esfahbod 已提交
1167
  {
B
Behdad Esfahbod 已提交
1168
    TRACE_WOULD_APPLY (this);
1169 1170 1171
    if (unlikely (!c->len))  return TRACE_RETURN (false);
    if (!digest->may_have (c->glyphs[0]))  return TRACE_RETURN (false);
      return TRACE_RETURN (process (c));
B
Behdad Esfahbod 已提交
1172 1173
  }

1174
  inline bool apply_once (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1175
  {
1176
    if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props, &c->property))
1177
      return false;
B
Behdad Esfahbod 已提交
1178

1179
    return process (c);
B
Behdad Esfahbod 已提交
1180
  }
1181

1182
  static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);
B
Behdad Esfahbod 已提交
1183
  inline bool apply_string (hb_apply_context_t *c, const hb_set_digest_t *digest) const
B
Behdad Esfahbod 已提交
1184
  {
1185 1186
    bool ret = false;

B
Minor  
Behdad Esfahbod 已提交
1187
    if (unlikely (!c->buffer->len || !c->lookup_mask))
B
Behdad Esfahbod 已提交
1188 1189
      return false;

1190
    c->set_recurse_func (apply_recurse_func);
B
Behdad Esfahbod 已提交
1191
    c->set_lookup (*this);
1192

1193
    if (likely (!is_reverse ()))
B
Behdad Esfahbod 已提交
1194
    {
1195
	/* in/out forward substitution */
B
Behdad Esfahbod 已提交
1196 1197
	c->buffer->clear_output ();
	c->buffer->idx = 0;
1198

1199 1200 1201
	while (c->buffer->idx < c->buffer->len)
	{
	  if ((c->buffer->cur().mask & c->lookup_mask) &&
B
Behdad Esfahbod 已提交
1202
	      digest->may_have (c->buffer->cur().codepoint) &&
1203 1204 1205 1206 1207
	      apply_once (c))
	    ret = true;
	  else
	    c->buffer->next_glyph ();
	}
1208
	if (ret)
B
Behdad Esfahbod 已提交
1209
	  c->buffer->swap_buffers ();
B
Behdad Esfahbod 已提交
1210 1211 1212
    }
    else
    {
1213
	/* in-place backward substitution */
B
Behdad Esfahbod 已提交
1214
	c->buffer->remove_output ();
B
Behdad Esfahbod 已提交
1215
	c->buffer->idx = c->buffer->len - 1;
B
Behdad Esfahbod 已提交
1216 1217
	do
	{
1218
	  if ((c->buffer->cur().mask & c->lookup_mask) &&
B
Behdad Esfahbod 已提交
1219
	      digest->may_have (c->buffer->cur().codepoint) &&
1220
	      apply_once (c))
1221 1222
	    ret = true;
	  else
B
Behdad Esfahbod 已提交
1223
	    c->buffer->idx--;
1224

B
Behdad Esfahbod 已提交
1225
	}
B
Behdad Esfahbod 已提交
1226
	while ((int) c->buffer->idx >= 0);
1227 1228 1229 1230
    }

    return ret;
  }
B
Behdad Esfahbod 已提交
1231

1232 1233 1234 1235 1236 1237 1238 1239 1240 1241
  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 已提交
1242
    TRACE_SERIALIZE (this);
1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253
    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 已提交
1254
    TRACE_SERIALIZE (this);
1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266
    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 已提交
1267
    TRACE_SERIALIZE (this);
1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281
    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 已提交
1282
    TRACE_SERIALIZE (this);
1283 1284 1285 1286 1287 1288 1289
    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));
  }

  inline bool sanitize (hb_sanitize_context_t *c)
  {
B
Behdad Esfahbod 已提交
1290
    TRACE_SANITIZE (this);
1291
    if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false);
1292
    OffsetArrayOf<SubstLookupSubTable> &list = CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable);
B
Behdad Esfahbod 已提交
1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308
    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
       * a reverse type!
       *
       * We just check that they are all either forward, or reverse. */
      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 已提交
1309
  }
B
Behdad Esfahbod 已提交
1310 1311
};

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

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

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

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

B
Behdad Esfahbod 已提交
1325 1326 1327 1328
  template <typename set_t>
  inline void add_coverage (set_t *glyphs, unsigned int lookup_index) const
  { get_lookup (lookup_index).add_coverage (glyphs); }

1329 1330
  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 已提交
1331

1332 1333 1334 1335 1336
#if 0
  inline hb_collect_glyphs_context_t::return_t collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
								      unsigned int lookup_index) const
  { return get_lookup (lookup_index).process (c); }
#endif
1337

B
Behdad Esfahbod 已提交
1338
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
1339
    TRACE_SANITIZE (this);
1340
    if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false);
1341
    OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
1342
    return TRACE_RETURN (list.sanitize (c, this));
B
Behdad Esfahbod 已提交
1343
  }
1344 1345
  public:
  DEFINE_SIZE_STATIC (10);
B
Minor  
Behdad Esfahbod 已提交
1346
};
1347 1348


B
Behdad Esfahbod 已提交
1349
void
1350
GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer)
B
Behdad Esfahbod 已提交
1351
{
B
Minor  
Behdad Esfahbod 已提交
1352
  HB_BUFFER_ALLOCATE_VAR (buffer, glyph_props);
1353
  HB_BUFFER_ALLOCATE_VAR (buffer, lig_props);
1354
  HB_BUFFER_ALLOCATE_VAR (buffer, syllable);
1355

1356
  const GDEF &gdef = *hb_ot_layout_from_face (font->face)->gdef;
B
Behdad Esfahbod 已提交
1357
  unsigned int count = buffer->len;
1358 1359
  for (unsigned int i = 0; i < count; i++) {
    buffer->info[i].lig_props() = buffer->info[i].syllable() = 0;
B
Minor  
Behdad Esfahbod 已提交
1360
    buffer->info[i].glyph_props() = gdef.get_glyph_props (buffer->info[i].codepoint);
1361
  }
B
Behdad Esfahbod 已提交
1362 1363 1364
}

void
1365
GSUB::substitute_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSED)
B
Behdad Esfahbod 已提交
1366 1367 1368 1369
{
}


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

B
Behdad Esfahbod 已提交
1372 1373 1374
inline bool ExtensionSubst::is_reverse (void) const
{
  unsigned int type = get_type ();
1375
  if (unlikely (type == SubstLookupSubTable::Extension))
1376
    return CastR<ExtensionSubst> (get_subtable<SubstLookupSubTable>()).is_reverse ();
B
Behdad Esfahbod 已提交
1377 1378 1379
  return SubstLookup::lookup_type_is_reverse (type);
}

1380 1381 1382 1383 1384 1385 1386
inline void_t SubstLookup::closure_recurse_func (hb_closure_context_t *c, unsigned int lookup_index)
{
  const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
  const SubstLookup &l = gsub.get_lookup (lookup_index);
  return l.process (c);
}

1387
inline bool SubstLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
B
Behdad Esfahbod 已提交
1388
{
1389
  const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
1390
  const SubstLookup &l = gsub.get_lookup (lookup_index);
1391 1392
  c->set_lookup (l);
  return l.apply_once (c);
1393 1394 1395
}


B
Behdad Esfahbod 已提交
1396
} /* namespace OT */
1397

B
Behdad Esfahbod 已提交
1398

1399
#endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */