hb-ot-layout-gsub-table.hh 40.5 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))
47
	c->glyphs->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
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
      c->input->add (glyph_id);
58
      c->output->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
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);
B
Behdad Esfahbod 已提交
70
    return_trace (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);
B
Behdad Esfahbod 已提交
78
    if (likely (index == NOT_COVERED)) return_trace (false);
B
Behdad Esfahbod 已提交
79

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

B
Behdad Esfahbod 已提交
85
    return_trace (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);
B
Behdad Esfahbod 已提交
94 95
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
B
Minor  
Behdad Esfahbod 已提交
96
    deltaGlyphID.set (delta); /* TODO(serilaize) overflow? */
B
Behdad Esfahbod 已提交
97
    return_trace (true);
98 99
  }

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

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

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

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

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

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

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

B
Behdad Esfahbod 已提交
157
    if (unlikely (index >= substitute.len)) return_trace (false);
158 159

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

B
Behdad Esfahbod 已提交
162
    return_trace (true);
163
  }
B
Behdad Esfahbod 已提交
164

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

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

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

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

B
Behdad Esfahbod 已提交
224 225 226
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
  {
227
    TRACE_DISPATCH (this, u.format);
228
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
229
    switch (u.format) {
B
Behdad Esfahbod 已提交
230 231 232
    case 1: return_trace (c->dispatch (u.format1));
    case 2: return_trace (c->dispatch (u.format2));
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
233 234 235
    }
  }

236
  protected:
237
  union {
B
Behdad Esfahbod 已提交
238
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
239 240
  SingleSubstFormat1	format1;
  SingleSubstFormat2	format2;
241
  } u;
B
Behdad Esfahbod 已提交
242
};
243

B
Behdad Esfahbod 已提交
244

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

255 256
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
257
    TRACE_COLLECT_GLYPHS (this);
258 259
    unsigned int count = substitute.len;
    for (unsigned int i = 0; i < count; i++)
B
Minor  
Behdad Esfahbod 已提交
260
      c->output->add (substitute[i]);
261 262
  }

B
Behdad Esfahbod 已提交
263
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
264
  {
B
Behdad Esfahbod 已提交
265
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
266
    unsigned int count = substitute.len;
267

B
Behdad Esfahbod 已提交
268 269 270
    /* Special-case to make it in-place and not consider this
     * as a "multiplied" substitution. */
    if (unlikely (count == 1))
271 272
    {
      c->replace_glyph (substitute.array[0]);
B
Behdad Esfahbod 已提交
273
      return_trace (true);
274
    }
275 276 277 278 279 280 281
    /* Spec disallows this, but Uniscribe allows it.
     * https://github.com/behdad/harfbuzz/issues/253 */
    else if (unlikely (count == 0))
    {
      c->buffer->delete_glyph ();
      return_trace (true);
    }
B
Behdad Esfahbod 已提交
282 283 284 285 286 287

    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);
288
      c->output_glyph_for_component (substitute.array[i], klass);
289
    }
B
Behdad Esfahbod 已提交
290
    c->buffer->skip_glyph ();
B
Behdad Esfahbod 已提交
291

B
Behdad Esfahbod 已提交
292
    return_trace (true);
B
Behdad Esfahbod 已提交
293 294
  }

295
  inline bool serialize (hb_serialize_context_t *c,
296
			 Supplier<GlyphID> &glyphs,
297 298
			 unsigned int num_glyphs)
  {
B
Behdad Esfahbod 已提交
299
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
300 301 302
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    if (unlikely (!substitute.serialize (c, glyphs, num_glyphs))) return_trace (false);
    return_trace (true);
303 304
  }

B
Behdad Esfahbod 已提交
305 306
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
307
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
308
    return_trace (substitute.sanitize (c));
B
Behdad Esfahbod 已提交
309 310
  }

311
  protected:
B
Behdad Esfahbod 已提交
312 313
  ArrayOf<GlyphID>
		substitute;		/* String of GlyphIDs to substitute */
314
  public:
315
  DEFINE_SIZE_ARRAY (2, substitute);
B
Behdad Esfahbod 已提交
316 317
};

B
Behdad Esfahbod 已提交
318 319
struct MultipleSubstFormat1
{
B
Behdad Esfahbod 已提交
320
  inline void closure (hb_closure_context_t *c) const
321
  {
B
Behdad Esfahbod 已提交
322
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
323 324 325
    Coverage::Iter iter;
    for (iter.init (this+coverage); iter.more (); iter.next ()) {
      if (c->glyphs->has (iter.get_glyph ()))
B
Behdad Esfahbod 已提交
326
	(this+sequence[iter.get_coverage ()]).closure (c);
B
Behdad Esfahbod 已提交
327
    }
328 329
  }

330 331
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
332
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
333
    (this+coverage).add_coverage (c->input);
334 335 336 337 338
    unsigned int count = sequence.len;
    for (unsigned int i = 0; i < count; i++)
	(this+sequence[i]).collect_glyphs (c);
  }

339 340 341 342 343
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

344 345
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
346
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
347
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
348 349
  }

B
Behdad Esfahbod 已提交
350
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
351
  {
B
Behdad Esfahbod 已提交
352
    TRACE_APPLY (this);
353

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

B
Behdad Esfahbod 已提交
357
    return_trace ((this+sequence[index]).apply (c));
358
  }
B
Behdad Esfahbod 已提交
359

360
  inline bool serialize (hb_serialize_context_t *c,
361 362
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &substitute_len_list,
363
			 unsigned int num_glyphs,
364
			 Supplier<GlyphID> &substitute_glyphs_list)
365
  {
B
Behdad Esfahbod 已提交
366
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
367 368
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    if (unlikely (!sequence.serialize (c, num_glyphs))) return_trace (false);
369 370 371
    for (unsigned int i = 0; i < num_glyphs; i++)
      if (unlikely (!sequence[i].serialize (c, this).serialize (c,
								substitute_glyphs_list,
B
Behdad Esfahbod 已提交
372
								substitute_len_list[i]))) return_trace (false);
373
    substitute_len_list.advance (num_glyphs);
B
Behdad Esfahbod 已提交
374 375
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
    return_trace (true);
376 377
  }

B
Behdad Esfahbod 已提交
378 379
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
380
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
381
    return_trace (coverage.sanitize (c, this) && sequence.sanitize (c, this));
B
Behdad Esfahbod 已提交
382 383
  }

384
  protected:
B
Behdad Esfahbod 已提交
385
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
386 387
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
388
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
389 390 391
  OffsetArrayOf<Sequence>
		sequence;		/* Array of Sequence tables
					 * ordered by Coverage Index */
392
  public:
393
  DEFINE_SIZE_ARRAY (6, sequence);
B
Behdad Esfahbod 已提交
394
};
395

B
Behdad Esfahbod 已提交
396 397
struct MultipleSubst
{
398
  inline bool serialize (hb_serialize_context_t *c,
399 400
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &substitute_len_list,
401
			 unsigned int num_glyphs,
402
			 Supplier<GlyphID> &substitute_glyphs_list)
403
  {
B
Behdad Esfahbod 已提交
404
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
405
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
406 407 408
    unsigned int format = 1;
    u.format.set (format);
    switch (u.format) {
B
Behdad Esfahbod 已提交
409 410
    case 1: return_trace (u.format1.serialize (c, glyphs, substitute_len_list, num_glyphs, substitute_glyphs_list));
    default:return_trace (false);
411 412 413
    }
  }

B
Behdad Esfahbod 已提交
414 415 416
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
  {
417
    TRACE_DISPATCH (this, u.format);
418
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
419
    switch (u.format) {
B
Behdad Esfahbod 已提交
420 421
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
422 423 424
    }
  }

425
  protected:
426
  union {
B
Behdad Esfahbod 已提交
427
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
428
  MultipleSubstFormat1	format1;
429 430 431
  } u;
};

B
Behdad Esfahbod 已提交
432

B
Behdad Esfahbod 已提交
433
typedef ArrayOf<GlyphID> AlternateSet;	/* Array of alternate GlyphIDs--in
B
Behdad Esfahbod 已提交
434 435
					 * arbitrary order */

B
Behdad Esfahbod 已提交
436 437
struct AlternateSubstFormat1
{
B
Behdad Esfahbod 已提交
438
  inline void closure (hb_closure_context_t *c) const
439
  {
B
Behdad Esfahbod 已提交
440
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
441 442 443 444 445 446
    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 已提交
447
	  c->glyphs->add (alt_set[i]);
B
Behdad Esfahbod 已提交
448 449
      }
    }
450 451
  }

452 453
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
454
    TRACE_COLLECT_GLYPHS (this);
455 456
    Coverage::Iter iter;
    for (iter.init (this+coverage); iter.more (); iter.next ()) {
B
Minor  
Behdad Esfahbod 已提交
457
      c->input->add (iter.get_glyph ());
458 459 460
      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 已提交
461
	c->output->add (alt_set[i]);
462 463 464
    }
  }

465 466 467 468 469
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

470 471
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
472
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
473
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
474 475
  }

B
Behdad Esfahbod 已提交
476
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
477
  {
B
Behdad Esfahbod 已提交
478
    TRACE_APPLY (this);
479
    hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
480

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

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

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

488
    hb_mask_t glyph_mask = c->buffer->cur().mask;
B
Behdad Esfahbod 已提交
489 490
    hb_mask_t lookup_mask = c->lookup_mask;

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

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

B
Behdad Esfahbod 已提交
497
    glyph_id = alt_set[alt_index - 1];
498

499
    c->replace_glyph (glyph_id);
500

B
Behdad Esfahbod 已提交
501
    return_trace (true);
502
  }
B
Behdad Esfahbod 已提交
503

504
  inline bool serialize (hb_serialize_context_t *c,
505 506
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &alternate_len_list,
507
			 unsigned int num_glyphs,
508
			 Supplier<GlyphID> &alternate_glyphs_list)
509
  {
B
Behdad Esfahbod 已提交
510
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
511 512
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    if (unlikely (!alternateSet.serialize (c, num_glyphs))) return_trace (false);
513 514 515
    for (unsigned int i = 0; i < num_glyphs; i++)
      if (unlikely (!alternateSet[i].serialize (c, this).serialize (c,
								    alternate_glyphs_list,
B
Behdad Esfahbod 已提交
516
								    alternate_len_list[i]))) return_trace (false);
517
    alternate_len_list.advance (num_glyphs);
B
Behdad Esfahbod 已提交
518 519
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
    return_trace (true);
520 521
  }

B
Behdad Esfahbod 已提交
522 523
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
524
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
525
    return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
526 527
  }

528
  protected:
B
Behdad Esfahbod 已提交
529
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
530 531
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
532
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
533 534 535
  OffsetArrayOf<AlternateSet>
		alternateSet;		/* Array of AlternateSet tables
					 * ordered by Coverage Index */
536
  public:
537
  DEFINE_SIZE_ARRAY (6, alternateSet);
B
Behdad Esfahbod 已提交
538
};
539

B
Behdad Esfahbod 已提交
540 541
struct AlternateSubst
{
542
  inline bool serialize (hb_serialize_context_t *c,
543 544
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &alternate_len_list,
545
			 unsigned int num_glyphs,
546
			 Supplier<GlyphID> &alternate_glyphs_list)
547
  {
B
Behdad Esfahbod 已提交
548
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
549
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
550 551 552
    unsigned int format = 1;
    u.format.set (format);
    switch (u.format) {
B
Behdad Esfahbod 已提交
553 554
    case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, num_glyphs, alternate_glyphs_list));
    default:return_trace (false);
555 556 557
    }
  }

B
Behdad Esfahbod 已提交
558 559 560
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
  {
561
    TRACE_DISPATCH (this, u.format);
562
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
563
    switch (u.format) {
B
Behdad Esfahbod 已提交
564 565
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
566 567 568
    }
  }

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

576

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

589 590
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
591
    TRACE_COLLECT_GLYPHS (this);
592 593
    unsigned int count = component.len;
    for (unsigned int i = 1; i < count; i++)
B
Minor  
Behdad Esfahbod 已提交
594 595
      c->input->add (component[i]);
    c->output->add (ligGlyph);
596 597
  }

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

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

B
Behdad Esfahbod 已提交
608
    return_trace (true);
B
Behdad Esfahbod 已提交
609 610
  }

611
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
612
  {
B
Behdad Esfahbod 已提交
613
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
614
    unsigned int count = component.len;
B
Behdad Esfahbod 已提交
615

B
Behdad Esfahbod 已提交
616
    if (unlikely (!count)) return_trace (false);
B
Behdad Esfahbod 已提交
617

618 619 620 621 622
    /* Special-case to make it in-place and not consider this
     * as a "ligated" substitution. */
    if (unlikely (count == 1))
    {
      c->replace_glyph (ligGlyph);
B
Behdad Esfahbod 已提交
623
      return_trace (true);
624 625
    }

B
Behdad Esfahbod 已提交
626 627
    bool is_mark_ligature = false;
    unsigned int total_component_count = 0;
628

629
    unsigned int match_length = 0;
630
    unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
631

632 633 634 635
    if (likely (!match_input (c, count,
			      &component[1],
			      match_glyph,
			      NULL,
636 637
			      &match_length,
			      match_positions,
638 639
			      &is_mark_ligature,
			      &total_component_count)))
B
Behdad Esfahbod 已提交
640
      return_trace (false);
641

642 643
    ligate_input (c,
		  count,
644 645
		  match_positions,
		  match_length,
646
		  ligGlyph,
647 648
		  is_mark_ligature,
		  total_component_count);
649

B
Behdad Esfahbod 已提交
650
    return_trace (true);
651
  }
652

653 654 655 656 657
  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 已提交
658
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
659
    if (unlikely (!c->extend_min (*this))) return_trace (false);
660
    ligGlyph = ligature;
B
Behdad Esfahbod 已提交
661 662
    if (unlikely (!component.serialize (c, components, num_components))) return_trace (false);
    return_trace (true);
663 664
  }

B
Behdad Esfahbod 已提交
665
  public:
B
Behdad Esfahbod 已提交
666 667
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
668
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
669
    return_trace (ligGlyph.sanitize (c) && component.sanitize (c));
B
Behdad Esfahbod 已提交
670 671
  }

672
  protected:
673
  GlyphID	ligGlyph;		/* GlyphID of ligature to substitute */
B
Behdad Esfahbod 已提交
674 675
  HeadlessArrayOf<GlyphID>
		component;		/* Array of component GlyphIDs--start
676 677
					 * with the second  component--ordered
					 * in writing direction */
678
  public:
679
  DEFINE_SIZE_ARRAY (4, component);
680
};
B
Behdad Esfahbod 已提交
681

B
Behdad Esfahbod 已提交
682 683
struct LigatureSet
{
B
Behdad Esfahbod 已提交
684
  inline void closure (hb_closure_context_t *c) const
685
  {
B
Behdad Esfahbod 已提交
686
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
687 688
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
B
Behdad Esfahbod 已提交
689
      (this+ligature[i]).closure (c);
690 691
  }

692 693
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
694
    TRACE_COLLECT_GLYPHS (this);
695 696 697 698 699
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
      (this+ligature[i]).collect_glyphs (c);
  }

700
  inline bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
701
  {
B
Behdad Esfahbod 已提交
702
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
703 704 705 706
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
    {
      const Ligature &lig = this+ligature[i];
707
      if (lig.would_apply (c))
B
Behdad Esfahbod 已提交
708
        return_trace (true);
B
Behdad Esfahbod 已提交
709
    }
B
Behdad Esfahbod 已提交
710
    return_trace (false);
B
Behdad Esfahbod 已提交
711 712
  }

713
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
714
  {
B
Behdad Esfahbod 已提交
715
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
716
    unsigned int num_ligs = ligature.len;
B
Behdad Esfahbod 已提交
717 718
    for (unsigned int i = 0; i < num_ligs; i++)
    {
B
Behdad Esfahbod 已提交
719
      const Ligature &lig = this+ligature[i];
B
Behdad Esfahbod 已提交
720
      if (lig.apply (c)) return_trace (true);
721 722
    }

B
Behdad Esfahbod 已提交
723
    return_trace (false);
724
  }
B
Behdad Esfahbod 已提交
725

726 727 728 729 730 731
  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 已提交
732
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
733 734
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    if (unlikely (!ligature.serialize (c, num_ligatures))) return_trace (false);
735 736 737 738
    for (unsigned int i = 0; i < num_ligatures; i++)
      if (unlikely (!ligature[i].serialize (c, this).serialize (c,
								ligatures[i],
								component_list,
B
Behdad Esfahbod 已提交
739
								component_count_list[i]))) return_trace (false);
740
    ligatures.advance (num_ligatures);
741
    component_count_list.advance (num_ligatures);
B
Behdad Esfahbod 已提交
742
    return_trace (true);
743 744
  }

B
Behdad Esfahbod 已提交
745 746
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
747
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
748
    return_trace (ligature.sanitize (c, this));
B
Behdad Esfahbod 已提交
749 750
  }

751
  protected:
B
Behdad Esfahbod 已提交
752 753 754
  OffsetArrayOf<Ligature>
		ligature;		/* Array LigatureSet tables
					 * ordered by preference */
755
  public:
756
  DEFINE_SIZE_ARRAY (2, ligature);
B
Behdad Esfahbod 已提交
757 758
};

B
Behdad Esfahbod 已提交
759 760
struct LigatureSubstFormat1
{
B
Behdad Esfahbod 已提交
761
  inline void closure (hb_closure_context_t *c) const
762
  {
B
Behdad Esfahbod 已提交
763
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
764 765 766
    Coverage::Iter iter;
    for (iter.init (this+coverage); iter.more (); iter.next ()) {
      if (c->glyphs->has (iter.get_glyph ()))
B
Behdad Esfahbod 已提交
767
	(this+ligatureSet[iter.get_coverage ()]).closure (c);
B
Behdad Esfahbod 已提交
768
    }
769 770
  }

771 772
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
773
    TRACE_COLLECT_GLYPHS (this);
774 775
    Coverage::Iter iter;
    for (iter.init (this+coverage); iter.more (); iter.next ()) {
B
Minor  
Behdad Esfahbod 已提交
776
      c->input->add (iter.get_glyph ());
777 778 779 780
      (this+ligatureSet[iter.get_coverage ()]).collect_glyphs (c);
    }
  }

781 782 783 784 785
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

786
  inline bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
787
  {
B
Behdad Esfahbod 已提交
788
    TRACE_WOULD_APPLY (this);
789
    unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
B
Behdad Esfahbod 已提交
790
    if (likely (index == NOT_COVERED)) return_trace (false);
791 792

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

B
Behdad Esfahbod 已提交
796
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
797
  {
B
Behdad Esfahbod 已提交
798
    TRACE_APPLY (this);
799
    hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
800

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

B
Behdad Esfahbod 已提交
804
    const LigatureSet &lig_set = this+ligatureSet[index];
B
Behdad Esfahbod 已提交
805
    return_trace (lig_set.apply (c));
806
  }
B
Behdad Esfahbod 已提交
807

808 809 810 811 812 813 814 815
  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 已提交
816
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
817 818
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    if (unlikely (!ligatureSet.serialize (c, num_first_glyphs))) return_trace (false);
819 820 821 822 823
    for (unsigned int i = 0; i < num_first_glyphs; i++)
      if (unlikely (!ligatureSet[i].serialize (c, this).serialize (c,
								   ligatures_list,
								   component_count_list,
								   ligature_per_first_glyph_count_list[i],
B
Behdad Esfahbod 已提交
824
								   component_list))) return_trace (false);
825
    ligature_per_first_glyph_count_list.advance (num_first_glyphs);
B
Behdad Esfahbod 已提交
826 827
    if (unlikely (!coverage.serialize (c, this).serialize (c, first_glyphs, num_first_glyphs))) return_trace (false);
    return_trace (true);
828 829
  }

B
Behdad Esfahbod 已提交
830 831
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
832
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
833
    return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
834 835
  }

836
  protected:
B
Behdad Esfahbod 已提交
837
  USHORT	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
838 839
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
840
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
841
  OffsetArrayOf<LigatureSet>
B
Behdad Esfahbod 已提交
842 843
		ligatureSet;		/* Array LigatureSet tables
					 * ordered by Coverage Index */
844
  public:
845
  DEFINE_SIZE_ARRAY (6, ligatureSet);
B
Behdad Esfahbod 已提交
846
};
847

B
Behdad Esfahbod 已提交
848 849
struct LigatureSubst
{
850 851 852 853 854 855 856 857
  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 已提交
858
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
859
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
860 861 862
    unsigned int format = 1;
    u.format.set (format);
    switch (u.format) {
B
Behdad Esfahbod 已提交
863 864 865 866 867 868 869 870
    case 1: return_trace (u.format1.serialize (c,
					       first_glyphs,
					       ligature_per_first_glyph_count_list,
					       num_first_glyphs,
					       ligatures_list,
					       component_count_list,
					       component_list));
    default:return_trace (false);
871 872 873
    }
  }

B
Behdad Esfahbod 已提交
874 875 876
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
  {
877
    TRACE_DISPATCH (this, u.format);
878
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
879
    switch (u.format) {
B
Behdad Esfahbod 已提交
880 881
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
882 883 884
    }
  }

885
  protected:
886
  union {
B
Behdad Esfahbod 已提交
887
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
888
  LigatureSubstFormat1	format1;
889 890 891
  } u;
};

B
Behdad Esfahbod 已提交
892

B
Minor  
Behdad Esfahbod 已提交
893
struct ContextSubst : Context {};
B
Behdad Esfahbod 已提交
894

B
Minor  
Behdad Esfahbod 已提交
895
struct ChainContextSubst : ChainContext {};
896

B
Behdad Esfahbod 已提交
897
struct ExtensionSubst : Extension<ExtensionSubst>
B
Behdad Esfahbod 已提交
898
{
899
  typedef struct SubstLookupSubTable LookupSubTable;
B
Behdad Esfahbod 已提交
900

B
Behdad Esfahbod 已提交
901
  inline bool is_reverse (void) const;
902 903 904
};


B
Behdad Esfahbod 已提交
905 906
struct ReverseChainSingleSubstFormat1
{
B
Behdad Esfahbod 已提交
907
  inline void closure (hb_closure_context_t *c) const
908
  {
B
Behdad Esfahbod 已提交
909
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
910 911 912 913 914 915 916
    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 已提交
917
        return;
B
Behdad Esfahbod 已提交
918 919 920 921

    count = lookahead.len;
    for (unsigned int i = 0; i < count; i++)
      if (!(this+lookahead[i]).intersects (c->glyphs))
B
Behdad Esfahbod 已提交
922
        return;
B
Behdad Esfahbod 已提交
923 924 925 926 927

    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 已提交
928
	c->glyphs->add (substitute[iter.get_coverage ()]);
B
Behdad Esfahbod 已提交
929
    }
930 931
  }

932 933
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
934 935
    TRACE_COLLECT_GLYPHS (this);

936 937 938 939
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);

    unsigned int count;

B
Minor  
Behdad Esfahbod 已提交
940
    (this+coverage).add_coverage (c->input);
941 942 943

    count = backtrack.len;
    for (unsigned int i = 0; i < count; i++)
B
Minor  
Behdad Esfahbod 已提交
944
      (this+backtrack[i]).add_coverage (c->before);
945 946 947

    count = lookahead.len;
    for (unsigned int i = 0; i < count; i++)
B
Minor  
Behdad Esfahbod 已提交
948
      (this+lookahead[i]).add_coverage (c->after);
949 950 951 952

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

956 957 958 959 960
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

961 962
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
963
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
964
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
965 966
  }

B
Behdad Esfahbod 已提交
967
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
968
  {
B
Behdad Esfahbod 已提交
969
    TRACE_APPLY (this);
970
    if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
B
Behdad Esfahbod 已提交
971
      return_trace (false); /* No chaining to this type */
972

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

976 977
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
978

B
Behdad Esfahbod 已提交
979
    if (match_backtrack (c,
B
Behdad Esfahbod 已提交
980
			 backtrack.len, (USHORT *) backtrack.array,
B
Behdad Esfahbod 已提交
981
			 match_coverage, this) &&
B
Behdad Esfahbod 已提交
982
        match_lookahead (c,
B
Behdad Esfahbod 已提交
983
			 lookahead.len, (USHORT *) lookahead.array,
B
Behdad Esfahbod 已提交
984
			 match_coverage, this,
985 986
			 1))
    {
B
Behdad Esfahbod 已提交
987
      c->replace_glyph_inplace (substitute[index]);
988 989 990
      /* Note: We DON'T decrease buffer->idx.  The main loop does it
       * for us.  This is useful for preventing surprises if someone
       * calls us through a Context lookup. */
B
Behdad Esfahbod 已提交
991
      return_trace (true);
992 993
    }

B
Behdad Esfahbod 已提交
994
    return_trace (false);
995
  }
B
Behdad Esfahbod 已提交
996

B
Behdad Esfahbod 已提交
997 998
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
999
    TRACE_SANITIZE (this);
1000
    if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
B
Behdad Esfahbod 已提交
1001
      return_trace (false);
B
Behdad Esfahbod 已提交
1002
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
B
Behdad Esfahbod 已提交
1003
    if (!lookahead.sanitize (c, this))
B
Behdad Esfahbod 已提交
1004
      return_trace (false);
B
Behdad Esfahbod 已提交
1005
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
B
Behdad Esfahbod 已提交
1006
    return_trace (substitute.sanitize (c));
B
Behdad Esfahbod 已提交
1007 1008
  }

1009
  protected:
B
Behdad Esfahbod 已提交
1010
  USHORT	format;			/* Format identifier--format = 1 */
1011 1012 1013 1014 1015
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of table */
  OffsetArrayOf<Coverage>
		backtrack;		/* Array of coverage tables
B
Behdad Esfahbod 已提交
1016 1017
					 * in backtracking sequence, in  glyph
					 * sequence order */
1018 1019 1020
  OffsetArrayOf<Coverage>
		lookaheadX;		/* Array of coverage tables
					 * in lookahead sequence, in glyph
B
Behdad Esfahbod 已提交
1021
					 * sequence order */
1022 1023 1024
  ArrayOf<GlyphID>
		substituteX;		/* Array of substitute
					 * GlyphIDs--ordered by Coverage Index */
1025
  public:
B
Behdad Esfahbod 已提交
1026
  DEFINE_SIZE_MIN (10);
B
Behdad Esfahbod 已提交
1027 1028
};

B
Behdad Esfahbod 已提交
1029 1030
struct ReverseChainSingleSubst
{
1031
  template <typename context_t>
1032
  inline typename context_t::return_t dispatch (context_t *c) const
1033
  {
1034
    TRACE_DISPATCH (this, u.format);
1035
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1036
    switch (u.format) {
B
Behdad Esfahbod 已提交
1037 1038
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
1039 1040 1041
    }
  }

1042
  protected:
1043 1044
  union {
  USHORT				format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1045
  ReverseChainSingleSubstFormat1	format1;
1046 1047 1048 1049 1050
  } u;
};



B
Behdad Esfahbod 已提交
1051 1052 1053 1054
/*
 * SubstLookup
 */

B
Behdad Esfahbod 已提交
1055 1056
struct SubstLookupSubTable
{
B
Behdad Esfahbod 已提交
1057 1058
  friend struct SubstLookup;

B
Behdad Esfahbod 已提交
1059
  enum Type {
1060 1061 1062 1063 1064 1065 1066
    Single		= 1,
    Multiple		= 2,
    Alternate		= 3,
    Ligature		= 4,
    Context		= 5,
    ChainContext	= 6,
    Extension		= 7,
1067
    ReverseChainSingle	= 8
1068 1069
  };

1070
  template <typename context_t>
1071
  inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
1072
  {
1073
    TRACE_DISPATCH (this, lookup_type);
1074
    if (unlikely (!c->may_dispatch (this, &u.sub_format))) return_trace (c->no_dispatch_return_value ());
1075
    switch (lookup_type) {
B
Behdad Esfahbod 已提交
1076 1077 1078 1079 1080 1081 1082 1083 1084
    case Single:		return_trace (u.single.dispatch (c));
    case Multiple:		return_trace (u.multiple.dispatch (c));
    case Alternate:		return_trace (u.alternate.dispatch (c));
    case Ligature:		return_trace (u.ligature.dispatch (c));
    case Context:		return_trace (u.context.dispatch (c));
    case ChainContext:		return_trace (u.chainContext.dispatch (c));
    case Extension:		return_trace (u.extension.dispatch (c));
    case ReverseChainSingle:	return_trace (u.reverseChainContextSingle.dispatch (c));
    default:			return_trace (c->default_return_value ());
1085 1086 1087
    }
  }

1088
  protected:
B
Behdad Esfahbod 已提交
1089
  union {
B
Minor  
Behdad Esfahbod 已提交
1090
  USHORT			sub_format;
B
Behdad Esfahbod 已提交
1091 1092 1093 1094
  SingleSubst			single;
  MultipleSubst			multiple;
  AlternateSubst		alternate;
  LigatureSubst			ligature;
1095
  ContextSubst			context;
B
Behdad Esfahbod 已提交
1096 1097 1098
  ChainContextSubst		chainContext;
  ExtensionSubst		extension;
  ReverseChainSingleSubst	reverseChainContextSingle;
B
Behdad Esfahbod 已提交
1099
  } u;
B
Behdad Esfahbod 已提交
1100
  public:
B
Minor  
Behdad Esfahbod 已提交
1101
  DEFINE_SIZE_UNION (2, sub_format);
B
Behdad Esfahbod 已提交
1102 1103
};

1104

B
Behdad Esfahbod 已提交
1105 1106
struct SubstLookup : Lookup
{
1107
  inline const SubstLookupSubTable& get_subtable (unsigned int i) const
1108
  { return Lookup::get_subtable<SubstLookupSubTable> (i); }
B
Behdad Esfahbod 已提交
1109

B
Behdad Esfahbod 已提交
1110
  inline static bool lookup_type_is_reverse (unsigned int lookup_type)
1111
  { return lookup_type == SubstLookupSubTable::ReverseChainSingle; }
B
Behdad Esfahbod 已提交
1112 1113

  inline bool is_reverse (void) const
B
Behdad Esfahbod 已提交
1114
  {
B
Behdad Esfahbod 已提交
1115
    unsigned int type = get_type ();
1116
    if (unlikely (type == SubstLookupSubTable::Extension))
1117
      return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
B
Behdad Esfahbod 已提交
1118
    return lookup_type_is_reverse (type);
B
Behdad Esfahbod 已提交
1119
  }
1120

B
Behdad Esfahbod 已提交
1121 1122 1123
  inline bool apply (hb_apply_context_t *c) const
  {
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
1124
    return_trace (dispatch (c));
B
Behdad Esfahbod 已提交
1125 1126
  }

1127 1128
  inline hb_closure_context_t::return_t closure (hb_closure_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1129
    TRACE_CLOSURE (this);
1130
    c->set_recurse_func (dispatch_recurse_func<hb_closure_context_t>);
B
Behdad Esfahbod 已提交
1131
    return_trace (dispatch (c));
B
Behdad Esfahbod 已提交
1132 1133
  }

B
Behdad Esfahbod 已提交
1134
  inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
B
Behdad Esfahbod 已提交
1135 1136
  {
    TRACE_COLLECT_GLYPHS (this);
1137
    c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
B
Behdad Esfahbod 已提交
1138
    return_trace (dispatch (c));
1139 1140
  }

B
Behdad Esfahbod 已提交
1141 1142 1143
  template <typename set_t>
  inline void add_coverage (set_t *glyphs) const
  {
1144 1145
    hb_add_coverage_context_t<set_t> c (glyphs);
    dispatch (&c);
B
Behdad Esfahbod 已提交
1146 1147
  }

1148 1149
  inline bool would_apply (hb_would_apply_context_t *c,
			   const hb_ot_layout_lookup_accelerator_t *accel) const
B
Behdad Esfahbod 已提交
1150
  {
B
Behdad Esfahbod 已提交
1151
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
1152 1153 1154
    if (unlikely (!c->len))  return_trace (false);
    if (!accel->may_have (c->glyphs[0]))  return_trace (false);
      return_trace (dispatch (c));
B
Behdad Esfahbod 已提交
1155 1156
  }

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

1159 1160
  inline SubstLookupSubTable& serialize_subtable (hb_serialize_context_t *c,
						  unsigned int i)
1161
  { return get_subtables<SubstLookupSubTable> ()[i].serialize (c, this); }
1162 1163 1164 1165 1166 1167 1168

  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 已提交
1169
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1170 1171
    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Single, lookup_props, 1))) return_trace (false);
    return_trace (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes, num_glyphs));
1172 1173 1174 1175 1176 1177 1178 1179 1180
  }

  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 已提交
1181
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1182 1183 1184 1185 1186 1187
    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Multiple, lookup_props, 1))) return_trace (false);
    return_trace (serialize_subtable (c, 0).u.multiple.serialize (c,
								  glyphs,
								  substitute_len_list,
								  num_glyphs,
								  substitute_glyphs_list));
1188 1189 1190 1191 1192 1193 1194 1195 1196
  }

  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 已提交
1197
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1198 1199 1200 1201 1202 1203
    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Alternate, lookup_props, 1))) return_trace (false);
    return_trace (serialize_subtable (c, 0).u.alternate.serialize (c,
								   glyphs,
								   alternate_len_list,
								   num_glyphs,
								   alternate_glyphs_list));
1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214
  }

  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 已提交
1215
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1216 1217 1218 1219 1220 1221 1222 1223
    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Ligature, lookup_props, 1))) return_trace (false);
    return_trace (serialize_subtable (c, 0).u.ligature.serialize (c,
								  first_glyphs,
								  ligature_per_first_glyph_count_list,
								  num_first_glyphs,
								  ligatures_list,
								  component_count_list,
								  component_list));
1224 1225
  }

B
Behdad Esfahbod 已提交
1226 1227 1228 1229 1230
  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
1231
  { return Lookup::dispatch<SubstLookupSubTable> (c); }
B
Behdad Esfahbod 已提交
1232

B
Behdad Esfahbod 已提交
1233
  inline bool sanitize (hb_sanitize_context_t *c) const
1234
  {
B
Behdad Esfahbod 已提交
1235
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1236 1237
    if (unlikely (!Lookup::sanitize (c))) return_trace (false);
    if (unlikely (!dispatch (c))) return_trace (false);
B
Behdad Esfahbod 已提交
1238 1239 1240 1241 1242

    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 已提交
1243
       * a reverse type! */
B
Behdad Esfahbod 已提交
1244 1245 1246 1247
      unsigned int type = get_subtable (0).u.extension.get_type ();
      unsigned int count = get_subtable_count ();
      for (unsigned int i = 1; i < count; i++)
        if (get_subtable (i).u.extension.get_type () != type)
B
Behdad Esfahbod 已提交
1248
	  return_trace (false);
B
Behdad Esfahbod 已提交
1249
    }
B
Behdad Esfahbod 已提交
1250
    return_trace (true);
B
Behdad Esfahbod 已提交
1251
  }
B
Behdad Esfahbod 已提交
1252 1253
};

B
Behdad Esfahbod 已提交
1254
typedef OffsetListOf<SubstLookup> SubstLookupList;
1255

B
Minor  
Behdad Esfahbod 已提交
1256
/*
B
Behdad Esfahbod 已提交
1257
 * GSUB -- The Glyph Substitution Table
B
Minor  
Behdad Esfahbod 已提交
1258 1259
 */

B
Behdad Esfahbod 已提交
1260 1261
struct GSUB : GSUBGPOS
{
1262
  static const hb_tag_t tableTag	= HB_OT_TAG_GSUB;
B
Minor  
Behdad Esfahbod 已提交
1263

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

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

B
Behdad Esfahbod 已提交
1269 1270
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1271
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1272
    if (unlikely (!GSUBGPOS::sanitize (c))) return_trace (false);
B
Behdad Esfahbod 已提交
1273
    const OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
B
Behdad Esfahbod 已提交
1274
    return_trace (list.sanitize (c, this));
B
Behdad Esfahbod 已提交
1275
  }
B
Minor  
Behdad Esfahbod 已提交
1276
};
1277 1278


B
Behdad Esfahbod 已提交
1279
void
1280
GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer)
B
Behdad Esfahbod 已提交
1281
{
1282
  _hb_buffer_assert_gsubgpos_vars (buffer);
1283

1284
  const GDEF &gdef = *hb_ot_layout_from_face (font->face)->gdef;
B
Behdad Esfahbod 已提交
1285
  unsigned int count = buffer->len;
1286
  hb_glyph_info_t *info = buffer->info;
B
Behdad Esfahbod 已提交
1287 1288
  for (unsigned int i = 0; i < count; i++)
  {
1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307
    unsigned int props = gdef.get_glyph_props (info[i].codepoint);
    if (!props)
    {
      /* Never mark default-ignorables as marks.
       * They won't get in the way of lookups anyway,
       * but having them as mark will cause them to be skipped
       * over if the lookup-flag says so, but at least for the
       * Mongolian variation selectors, looks like Uniscribe
       * marks them as non-mark.  Some Mongolian fonts without
       * GDEF rely on this.  Another notable character that
       * this applies to is COMBINING GRAPHEME JOINER. */
      props = (_hb_glyph_info_get_general_category (&info[i]) !=
	       HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK ||
	       _hb_glyph_info_is_default_ignorable (&info[i])) ?
	      HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH :
	      HB_OT_LAYOUT_GLYPH_PROPS_MARK;
    }
    _hb_glyph_info_set_glyph_props (&info[i], props);
    _hb_glyph_info_clear_lig_props (&info[i]);
B
Behdad Esfahbod 已提交
1308
    buffer->info[i].syllable() = 0;
1309
  }
B
Behdad Esfahbod 已提交
1310 1311 1312
}


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

1315
/*static*/ inline bool ExtensionSubst::is_reverse (void) const
B
Behdad Esfahbod 已提交
1316 1317
{
  unsigned int type = get_type ();
1318
  if (unlikely (type == SubstLookupSubTable::Extension))
1319
    return CastR<ExtensionSubst> (get_subtable<LookupSubTable>()).is_reverse ();
B
Behdad Esfahbod 已提交
1320 1321 1322
  return SubstLookup::lookup_type_is_reverse (type);
}

1323
template <typename context_t>
1324
/*static*/ inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
1325 1326 1327
{
  const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
  const SubstLookup &l = gsub.get_lookup (lookup_index);
1328
  return l.dispatch (c);
1329 1330
}

1331
/*static*/ inline bool SubstLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
B
Behdad Esfahbod 已提交
1332
{
1333
  const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
1334
  const SubstLookup &l = gsub.get_lookup (lookup_index);
1335
  unsigned int saved_lookup_props = c->lookup_props;
1336 1337 1338
  unsigned int saved_lookup_index = c->lookup_index;
  c->set_lookup_index (lookup_index);
  c->set_lookup_props (l.get_props ());
1339
  bool ret = l.dispatch (c);
1340
  c->set_lookup_index (saved_lookup_index);
1341
  c->set_lookup_props (saved_lookup_props);
1342
  return ret;
1343 1344 1345
}


B
Behdad Esfahbod 已提交
1346
} /* namespace OT */
1347

B
Behdad Esfahbod 已提交
1348

1349
#endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */