hb-ot-layout-gsub-table.hh 40.8 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);
70
    return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
71 72
  }

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

80 81
    /* 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

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

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

B
Behdad Esfahbod 已提交
100 101
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
102
    TRACE_SANITIZE (this);
103
    return TRACE_RETURN (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);
147
    return TRACE_RETURN (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);
155
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
156

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

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

162
    return TRACE_RETURN (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
    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
    if (unlikely (!substitute.serialize (c, substitutes, num_glyphs))) return TRACE_RETURN (false);
173
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
174 175 176
    return TRACE_RETURN (true);
  }

B
Behdad Esfahbod 已提交
177 178
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
179
    TRACE_SANITIZE (this);
180
    return TRACE_RETURN (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 204
    if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false);
    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 218 219 220 221 222 223
      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 已提交
224 225 226
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
  {
227
    TRACE_DISPATCH (this, u.format);
B
Behdad Esfahbod 已提交
228
    if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
B
Behdad Esfahbod 已提交
229 230 231 232 233 234 235
    switch (u.format) {
    case 1: return TRACE_RETURN (c->dispatch (u.format1));
    case 2: return TRACE_RETURN (c->dispatch (u.format2));
    default:return TRACE_RETURN (c->default_return_value ());
    }
  }

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 268 269 270 271 272 273 274 275

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

B
Behdad Esfahbod 已提交
278 279 280
    /* Special-case to make it in-place and not consider this
     * as a "multiplied" substitution. */
    if (unlikely (count == 1))
281 282
    {
      c->replace_glyph (substitute.array[0]);
B
Behdad Esfahbod 已提交
283
      return TRACE_RETURN (true);
284
    }
B
Behdad Esfahbod 已提交
285 286 287 288 289 290

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

295
    return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
296 297
  }

298
  inline bool serialize (hb_serialize_context_t *c,
299
			 Supplier<GlyphID> &glyphs,
300 301
			 unsigned int num_glyphs)
  {
B
Behdad Esfahbod 已提交
302
    TRACE_SERIALIZE (this);
303 304 305 306 307
    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 已提交
308 309
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
310
    TRACE_SANITIZE (this);
311
    return TRACE_RETURN (substitute.sanitize (c));
B
Behdad Esfahbod 已提交
312 313
  }

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

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

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

342 343 344 345 346
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

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

B
Behdad Esfahbod 已提交
353
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
354
  {
B
Behdad Esfahbod 已提交
355
    TRACE_APPLY (this);
356

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

360
    return TRACE_RETURN ((this+sequence[index]).apply (c));
361
  }
B
Behdad Esfahbod 已提交
362

363
  inline bool serialize (hb_serialize_context_t *c,
364 365
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &substitute_len_list,
366
			 unsigned int num_glyphs,
367
			 Supplier<GlyphID> &substitute_glyphs_list)
368
  {
B
Behdad Esfahbod 已提交
369
    TRACE_SERIALIZE (this);
370 371
    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
    if (unlikely (!sequence.serialize (c, num_glyphs))) return TRACE_RETURN (false);
372 373 374 375 376
    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);
377
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
378 379 380
    return TRACE_RETURN (true);
  }

B
Behdad Esfahbod 已提交
381 382
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
383
    TRACE_SANITIZE (this);
384
    return TRACE_RETURN (coverage.sanitize (c, this) && sequence.sanitize (c, this));
B
Behdad Esfahbod 已提交
385 386
  }

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

B
Behdad Esfahbod 已提交
399 400
struct MultipleSubst
{
401
  inline bool serialize (hb_serialize_context_t *c,
402 403
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &substitute_len_list,
404
			 unsigned int num_glyphs,
405
			 Supplier<GlyphID> &substitute_glyphs_list)
406
  {
B
Behdad Esfahbod 已提交
407
    TRACE_SERIALIZE (this);
408 409 410 411 412 413 414 415 416
    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 已提交
417 418 419
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
  {
420
    TRACE_DISPATCH (this, u.format);
B
Behdad Esfahbod 已提交
421
    if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
B
Behdad Esfahbod 已提交
422 423 424 425 426 427
    switch (u.format) {
    case 1: return TRACE_RETURN (c->dispatch (u.format1));
    default:return TRACE_RETURN (c->default_return_value ());
    }
  }

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

B
Behdad Esfahbod 已提交
435

B
Behdad Esfahbod 已提交
436
typedef ArrayOf<GlyphID> AlternateSet;	/* Array of alternate GlyphIDs--in
B
Behdad Esfahbod 已提交
437 438
					 * arbitrary order */

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

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

468 469 470 471 472
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

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

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

484
    unsigned int index = (this+coverage).get_coverage (glyph_id);
485
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
486

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

489
    if (unlikely (!alt_set.len)) return TRACE_RETURN (false);
490

491
    hb_mask_t glyph_mask = c->buffer->cur().mask;
B
Behdad Esfahbod 已提交
492 493
    hb_mask_t lookup_mask = c->lookup_mask;

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

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

B
Behdad Esfahbod 已提交
500
    glyph_id = alt_set[alt_index - 1];
501

502
    c->replace_glyph (glyph_id);
503

504
    return TRACE_RETURN (true);
505
  }
B
Behdad Esfahbod 已提交
506

507
  inline bool serialize (hb_serialize_context_t *c,
508 509
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &alternate_len_list,
510
			 unsigned int num_glyphs,
511
			 Supplier<GlyphID> &alternate_glyphs_list)
512
  {
B
Behdad Esfahbod 已提交
513
    TRACE_SERIALIZE (this);
514 515
    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
    if (unlikely (!alternateSet.serialize (c, num_glyphs))) return TRACE_RETURN (false);
516 517 518 519 520
    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);
521
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false);
522 523 524
    return TRACE_RETURN (true);
  }

B
Behdad Esfahbod 已提交
525 526
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
527
    TRACE_SANITIZE (this);
528
    return TRACE_RETURN (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
529 530
  }

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

B
Behdad Esfahbod 已提交
543 544
struct AlternateSubst
{
545
  inline bool serialize (hb_serialize_context_t *c,
546 547
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &alternate_len_list,
548
			 unsigned int num_glyphs,
549
			 Supplier<GlyphID> &alternate_glyphs_list)
550
  {
B
Behdad Esfahbod 已提交
551
    TRACE_SERIALIZE (this);
552 553 554 555 556 557 558 559 560
    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 已提交
561 562 563
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
  {
564
    TRACE_DISPATCH (this, u.format);
B
Behdad Esfahbod 已提交
565
    if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
B
Behdad Esfahbod 已提交
566 567 568 569 570 571
    switch (u.format) {
    case 1: return TRACE_RETURN (c->dispatch (u.format1));
    default:return TRACE_RETURN (c->default_return_value ());
    }
  }

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

579

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

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

601
  inline bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
602
  {
B
Behdad Esfahbod 已提交
603
    TRACE_WOULD_APPLY (this);
604
    if (c->len != component.len)
605
      return TRACE_RETURN (false);
606 607 608

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

611
    return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
612 613
  }

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

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

621 622 623 624 625 626 627 628
    /* Special-case to make it in-place and not consider this
     * as a "ligated" substitution. */
    if (unlikely (count == 1))
    {
      c->replace_glyph (ligGlyph);
      return TRACE_RETURN (true);
    }

B
Behdad Esfahbod 已提交
629 630
    bool is_mark_ligature = false;
    unsigned int total_component_count = 0;
631

632 633 634
    unsigned int match_length = 0;
    unsigned int match_positions[MAX_CONTEXT_LENGTH];

635 636 637 638
    if (likely (!match_input (c, count,
			      &component[1],
			      match_glyph,
			      NULL,
639 640
			      &match_length,
			      match_positions,
641 642 643
			      &is_mark_ligature,
			      &total_component_count)))
      return TRACE_RETURN (false);
644

645 646
    ligate_input (c,
		  count,
647 648
		  match_positions,
		  match_length,
649
		  ligGlyph,
650 651
		  is_mark_ligature,
		  total_component_count);
652

653
    return TRACE_RETURN (true);
654
  }
655

656 657 658 659 660
  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 已提交
661
    TRACE_SERIALIZE (this);
662
    if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false);
663
    ligGlyph = ligature;
664 665 666 667
    if (unlikely (!component.serialize (c, components, num_components))) return TRACE_RETURN (false);
    return TRACE_RETURN (true);
  }

B
Behdad Esfahbod 已提交
668
  public:
B
Behdad Esfahbod 已提交
669 670
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
671
    TRACE_SANITIZE (this);
672
    return TRACE_RETURN (ligGlyph.sanitize (c) && component.sanitize (c));
B
Behdad Esfahbod 已提交
673 674
  }

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

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

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

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

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

726
    return TRACE_RETURN (false);
727
  }
B
Behdad Esfahbod 已提交
728

729 730 731 732 733 734
  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 已提交
735
    TRACE_SERIALIZE (this);
736 737 738 739 740 741 742
    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);
743
    ligatures.advance (num_ligatures);
744 745 746 747
    component_count_list.advance (num_ligatures);
    return TRACE_RETURN (true);
  }

B
Behdad Esfahbod 已提交
748 749
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
750
    TRACE_SANITIZE (this);
751
    return TRACE_RETURN (ligature.sanitize (c, this));
B
Behdad Esfahbod 已提交
752 753
  }

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

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

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

784 785 786 787 788
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

789
  inline bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
790
  {
B
Behdad Esfahbod 已提交
791
    TRACE_WOULD_APPLY (this);
792
    unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
793 794 795 796
    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 已提交
797 798
  }

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

804
    unsigned int index = (this+coverage).get_coverage (glyph_id);
805
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
806

B
Behdad Esfahbod 已提交
807
    const LigatureSet &lig_set = this+ligatureSet[index];
808
    return TRACE_RETURN (lig_set.apply (c));
809
  }
B
Behdad Esfahbod 已提交
810

811 812 813 814 815 816 817 818
  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 已提交
819
    TRACE_SERIALIZE (this);
820 821 822 823 824 825 826 827 828
    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);
829
    if (unlikely (!coverage.serialize (c, this).serialize (c, first_glyphs, num_first_glyphs))) return TRACE_RETURN (false);
830 831 832
    return TRACE_RETURN (true);
  }

B
Behdad Esfahbod 已提交
833 834
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
835
    TRACE_SANITIZE (this);
836
    return TRACE_RETURN (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
837 838
  }

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

B
Behdad Esfahbod 已提交
851 852
struct LigatureSubst
{
853 854 855 856 857 858 859 860
  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 已提交
861
    TRACE_SERIALIZE (this);
862 863 864 865 866 867 868 869 870 871
    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 已提交
872 873 874
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
  {
875
    TRACE_DISPATCH (this, u.format);
B
Behdad Esfahbod 已提交
876
    if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
B
Behdad Esfahbod 已提交
877 878 879 880 881 882
    switch (u.format) {
    case 1: return TRACE_RETURN (c->dispatch (u.format1));
    default:return TRACE_RETURN (c->default_return_value ());
    }
  }

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

B
Behdad Esfahbod 已提交
890

B
Minor  
Behdad Esfahbod 已提交
891
struct ContextSubst : Context {};
B
Behdad Esfahbod 已提交
892

B
Minor  
Behdad Esfahbod 已提交
893
struct ChainContextSubst : ChainContext {};
894

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

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


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

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

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

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

934 935 936 937
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);

    unsigned int count;

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

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

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

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

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

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

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

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

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

B
Behdad Esfahbod 已提交
977
    if (match_backtrack (c,
B
Behdad Esfahbod 已提交
978
			 backtrack.len, (USHORT *) backtrack.array,
B
Behdad Esfahbod 已提交
979
			 match_coverage, this) &&
B
Behdad Esfahbod 已提交
980
        match_lookahead (c,
B
Behdad Esfahbod 已提交
981
			 lookahead.len, (USHORT *) lookahead.array,
B
Behdad Esfahbod 已提交
982
			 match_coverage, this,
983 984
			 1))
    {
B
Behdad Esfahbod 已提交
985
      c->replace_glyph_inplace (substitute[index]);
986 987 988
      /* 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. */
989
      return TRACE_RETURN (true);
990 991
    }

992
    return TRACE_RETURN (false);
993
  }
B
Behdad Esfahbod 已提交
994

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

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

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

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



B
Behdad Esfahbod 已提交
1049 1050 1051 1052
/*
 * SubstLookup
 */

B
Behdad Esfahbod 已提交
1053 1054
struct SubstLookupSubTable
{
B
Behdad Esfahbod 已提交
1055 1056
  friend struct SubstLookup;

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

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

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

1103

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

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

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

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

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

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

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

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

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

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

  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 已提交
1168
    TRACE_SERIALIZE (this);
1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179
    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 已提交
1180
    TRACE_SERIALIZE (this);
1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192
    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 已提交
1193
    TRACE_SERIALIZE (this);
1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207
    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 已提交
1208
    TRACE_SERIALIZE (this);
1209 1210 1211 1212 1213
    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Ligature, lookup_props, 1))) return TRACE_RETURN (false);
    return TRACE_RETURN (serialize_subtable (c, 0).u.ligature.serialize (c, first_glyphs, ligature_per_first_glyph_count_list, num_first_glyphs,
									 ligatures_list, component_count_list, component_list));
  }

B
Behdad Esfahbod 已提交
1214 1215 1216 1217 1218
  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
1219
  { return Lookup::dispatch<SubstLookupSubTable> (c); }
B
Behdad Esfahbod 已提交
1220

B
Behdad Esfahbod 已提交
1221
  inline bool sanitize (hb_sanitize_context_t *c) const
1222
  {
B
Behdad Esfahbod 已提交
1223
    TRACE_SANITIZE (this);
1224
    if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false);
1225
    if (unlikely (!dispatch (c))) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1226 1227 1228 1229 1230

    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 已提交
1231
       * a reverse type! */
B
Behdad Esfahbod 已提交
1232 1233 1234 1235 1236 1237 1238
      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 已提交
1239
  }
B
Behdad Esfahbod 已提交
1240 1241
};

B
Behdad Esfahbod 已提交
1242
typedef OffsetListOf<SubstLookup> SubstLookupList;
1243

B
Minor  
Behdad Esfahbod 已提交
1244
/*
B
Behdad Esfahbod 已提交
1245
 * GSUB -- The Glyph Substitution Table
B
Minor  
Behdad Esfahbod 已提交
1246 1247
 */

B
Behdad Esfahbod 已提交
1248 1249
struct GSUB : GSUBGPOS
{
1250
  static const hb_tag_t tableTag	= HB_OT_TAG_GSUB;
B
Minor  
Behdad Esfahbod 已提交
1251

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

1255 1256
  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 已提交
1257

B
Behdad Esfahbod 已提交
1258 1259
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1260
    TRACE_SANITIZE (this);
1261
    if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1262
    const OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
1263
    return TRACE_RETURN (list.sanitize (c, this));
B
Behdad Esfahbod 已提交
1264
  }
1265 1266
  public:
  DEFINE_SIZE_STATIC (10);
B
Minor  
Behdad Esfahbod 已提交
1267
};
1268 1269


B
Behdad Esfahbod 已提交
1270
void
1271
GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer)
B
Behdad Esfahbod 已提交
1272
{
1273
  _hb_buffer_assert_gsubgpos_vars (buffer);
1274

1275
  const GDEF &gdef = *hb_ot_layout_from_face (font->face)->gdef;
B
Behdad Esfahbod 已提交
1276
  unsigned int count = buffer->len;
B
Behdad Esfahbod 已提交
1277 1278
  for (unsigned int i = 0; i < count; i++)
  {
1279
    _hb_glyph_info_set_glyph_props (&buffer->info[i], gdef.get_glyph_props (buffer->info[i].codepoint));
B
Behdad Esfahbod 已提交
1280 1281
    _hb_glyph_info_clear_lig_props (&buffer->info[i]);
    buffer->info[i].syllable() = 0;
1282
  }
B
Behdad Esfahbod 已提交
1283 1284 1285
}

void
1286
GSUB::substitute_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSED)
B
Behdad Esfahbod 已提交
1287 1288 1289 1290
{
}


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

1293
/*static*/ inline bool ExtensionSubst::is_reverse (void) const
B
Behdad Esfahbod 已提交
1294 1295
{
  unsigned int type = get_type ();
1296
  if (unlikely (type == SubstLookupSubTable::Extension))
1297
    return CastR<ExtensionSubst> (get_subtable<LookupSubTable>()).is_reverse ();
B
Behdad Esfahbod 已提交
1298 1299 1300
  return SubstLookup::lookup_type_is_reverse (type);
}

1301
template <typename context_t>
1302
/*static*/ inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
1303 1304 1305
{
  const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
  const SubstLookup &l = gsub.get_lookup (lookup_index);
1306
  return l.dispatch (c);
1307 1308
}

1309
/*static*/ inline bool SubstLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
B
Behdad Esfahbod 已提交
1310
{
1311
  const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
1312
  const SubstLookup &l = gsub.get_lookup (lookup_index);
1313
  unsigned int saved_lookup_props = c->lookup_props;
1314
  c->set_lookup (l);
1315
  bool ret = l.dispatch (c);
1316
  c->set_lookup_props (saved_lookup_props);
1317
  return ret;
1318 1319 1320
}


B
Behdad Esfahbod 已提交
1321
} /* namespace OT */
1322

B
Behdad Esfahbod 已提交
1323

1324
#endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */