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

B
Behdad Esfahbod 已提交
34

35 36
namespace OT {

37

38 39 40 41 42
static inline void SingleSubst_serialize (hb_serialize_context_t *c,
					  Supplier<GlyphID> &glyphs,
					  Supplier<GlyphID> &substitutes,
					  unsigned int num_glyphs);

B
Behdad Esfahbod 已提交
43 44
struct SingleSubstFormat1
{
45 46 47
  inline bool intersects (const hb_set_t *glyphs) const
  { return (this+coverage).intersects (glyphs); }

B
Behdad Esfahbod 已提交
48
  inline void closure (hb_closure_context_t *c) const
49
  {
B
Behdad Esfahbod 已提交
50
    TRACE_CLOSURE (this);
51
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
52 53
    {
      /* TODO Switch to range-based API to work around malicious fonts.
54
       * https://github.com/harfbuzz/harfbuzz/issues/363 */
B
Behdad Esfahbod 已提交
55 56
      hb_codepoint_t glyph_id = iter.get_glyph ();
      if (c->glyphs->has (glyph_id))
57
	c->out->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
B
Behdad Esfahbod 已提交
58
    }
59 60
  }

61 62
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
63
    TRACE_COLLECT_GLYPHS (this);
64
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
65
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
66 67
    {
      /* TODO Switch to range-based API to work around malicious fonts.
68
       * https://github.com/harfbuzz/harfbuzz/issues/363 */
69
      hb_codepoint_t glyph_id = iter.get_glyph ();
70
      c->output->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
71 72 73
    }
  }

74
  inline const Coverage &get_coverage (void) const
75
  { return this+coverage; }
76

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

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

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

B
Behdad Esfahbod 已提交
95
    return_trace (true);
96
  }
B
Behdad Esfahbod 已提交
97

98
  inline bool serialize (hb_serialize_context_t *c,
99
			 Supplier<GlyphID> &glyphs,
100
			 unsigned int num_glyphs,
B
Minor  
Behdad Esfahbod 已提交
101
			 int delta)
102
  {
B
Behdad Esfahbod 已提交
103
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
104 105
    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 已提交
106
    deltaGlyphID.set (delta); /* TODO(serilaize) overflow? */
B
Behdad Esfahbod 已提交
107
    return_trace (true);
108 109
  }

110 111 112
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
113 114
    hb_auto_t<hb_vector_t<GlyphID> > from;
    hb_auto_t<hb_vector_t<GlyphID> > to;
115 116 117
    hb_codepoint_t delta = deltaGlyphID;
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
    {
118 119 120 121
      if (!c->plan->glyphset->has (iter.get_glyph ()))
        continue;
      from.push ()->set (iter.get_glyph ());
      to.push ()->set ((iter.get_glyph () + delta) & 0xFFFF);
122
    }
123 124 125 126 127 128 129 130 131
    c->serializer->err (from.in_error () || to.in_error ());

    Supplier<GlyphID> from_supplier (&from);
    Supplier<GlyphID> to_supplier (&to);
    SingleSubst_serialize (c->serializer,
			   from_supplier,
			   to_supplier,
			   from.len);
    return_trace (from.len);
132 133
  }

B
Behdad Esfahbod 已提交
134 135
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
136
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
137
    return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
B
Behdad Esfahbod 已提交
138 139
  }

140
  protected:
B
Behdad Esfahbod 已提交
141
  HBUINT16	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
142 143
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
144
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
145
  HBINT16	deltaGlyphID;		/* Add to original GlyphID to get
B
Behdad Esfahbod 已提交
146
					 * substitute GlyphID */
147 148
  public:
  DEFINE_SIZE_STATIC (6);
B
Behdad Esfahbod 已提交
149 150
};

B
Behdad Esfahbod 已提交
151 152
struct SingleSubstFormat2
{
153 154 155
  inline bool intersects (const hb_set_t *glyphs) const
  { return (this+coverage).intersects (glyphs); }

B
Behdad Esfahbod 已提交
156
  inline void closure (hb_closure_context_t *c) const
157
  {
B
Behdad Esfahbod 已提交
158
    TRACE_CLOSURE (this);
159
    unsigned int count = substitute.len;
160
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
161 162
    {
      if (unlikely (iter.get_coverage () >= count))
163
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
B
Behdad Esfahbod 已提交
164
      if (c->glyphs->has (iter.get_glyph ()))
165
	c->out->add (substitute[iter.get_coverage ()]);
B
Behdad Esfahbod 已提交
166
    }
167 168
  }

169 170
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
171
    TRACE_COLLECT_GLYPHS (this);
172
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
173
    unsigned int count = substitute.len;
174
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
175 176
    {
      if (unlikely (iter.get_coverage () >= count))
177
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
B
Minor  
Behdad Esfahbod 已提交
178
      c->output->add (substitute[iter.get_coverage ()]);
179 180 181
    }
  }

182
  inline const Coverage &get_coverage (void) const
183
  { return this+coverage; }
184

185 186
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
187
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
188
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
189 190
  }

191
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
192
  {
B
Behdad Esfahbod 已提交
193
    TRACE_APPLY (this);
194
    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
B
Behdad Esfahbod 已提交
195
    if (likely (index == NOT_COVERED)) return_trace (false);
196

B
Behdad Esfahbod 已提交
197
    if (unlikely (index >= substitute.len)) return_trace (false);
198

199
    c->replace_glyph (substitute[index]);
B
Behdad Esfahbod 已提交
200

B
Behdad Esfahbod 已提交
201
    return_trace (true);
202
  }
B
Behdad Esfahbod 已提交
203

B
Behdad Esfahbod 已提交
204
  inline bool serialize (hb_serialize_context_t *c,
205 206
			 Supplier<GlyphID> &glyphs,
			 Supplier<GlyphID> &substitutes,
B
Behdad Esfahbod 已提交
207 208
			 unsigned int num_glyphs)
  {
B
Behdad Esfahbod 已提交
209
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
210 211 212 213
    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 已提交
214 215
  }

216 217 218
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
219 220
    hb_auto_t<hb_vector_t<GlyphID> > from;
    hb_auto_t<hb_vector_t<GlyphID> > to;
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
    {
      if (!c->plan->glyphset->has (iter.get_glyph ()))
        continue;
      from.push ()->set (iter.get_glyph ());
      to.push ()->set (substitute[iter.get_coverage ()]);
    }
    c->serializer->err (from.in_error () || to.in_error ());

    Supplier<GlyphID> from_supplier (&from);
    Supplier<GlyphID> to_supplier (&to);
    SingleSubst_serialize (c->serializer,
			   from_supplier,
			   to_supplier,
			   from.len);
    return_trace (from.len);
237 238
  }

B
Behdad Esfahbod 已提交
239 240
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
241
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
242
    return_trace (coverage.sanitize (c, this) && substitute.sanitize (c));
B
Behdad Esfahbod 已提交
243 244
  }

245
  protected:
B
Behdad Esfahbod 已提交
246
  HBUINT16	format;			/* Format identifier--format = 2 */
B
Behdad Esfahbod 已提交
247 248
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
249
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
250 251 252
  ArrayOf<GlyphID>
		substitute;		/* Array of substitute
					 * GlyphIDs--ordered by Coverage Index */
253
  public:
254
  DEFINE_SIZE_ARRAY (6, substitute);
B
Behdad Esfahbod 已提交
255 256
};

B
Behdad Esfahbod 已提交
257 258
struct SingleSubst
{
B
Behdad Esfahbod 已提交
259
  inline bool serialize (hb_serialize_context_t *c,
260 261
			 Supplier<GlyphID> &glyphs,
			 Supplier<GlyphID> &substitutes,
B
Behdad Esfahbod 已提交
262 263
			 unsigned int num_glyphs)
  {
B
Behdad Esfahbod 已提交
264
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
265
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
B
Behdad Esfahbod 已提交
266
    unsigned int format = 2;
B
Behdad Esfahbod 已提交
267
    int delta = 0;
B
Behdad Esfahbod 已提交
268 269
    if (num_glyphs) {
      format = 1;
B
Minor  
Behdad Esfahbod 已提交
270
      /* TODO(serialize) check for wrap-around */
B
Behdad Esfahbod 已提交
271 272 273 274 275 276 277 278 279
      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 已提交
280 281 282
    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 已提交
283 284 285
    }
  }

B
Behdad Esfahbod 已提交
286 287 288
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
  {
289
    TRACE_DISPATCH (this, u.format);
290
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
291
    switch (u.format) {
B
Behdad Esfahbod 已提交
292 293 294
    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 已提交
295 296 297
    }
  }

298
  protected:
299
  union {
B
Behdad Esfahbod 已提交
300
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
301 302
  SingleSubstFormat1	format1;
  SingleSubstFormat2	format2;
303
  } u;
B
Behdad Esfahbod 已提交
304
};
305

306 307 308 309 310 311 312 313 314 315 316
static inline void
SingleSubst_serialize (hb_serialize_context_t *c,
		       Supplier<GlyphID> &glyphs,
		       Supplier<GlyphID> &substitutes,
		       unsigned int num_glyphs)
{
  c->start_embed<SingleSubst> ()->serialize (c,
					     glyphs,
					     substitutes,
					     num_glyphs);
}
B
Behdad Esfahbod 已提交
317

B
Behdad Esfahbod 已提交
318 319
struct Sequence
{
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
    unsigned int count = substitute.len;
    for (unsigned int i = 0; i < count; i++)
325
      c->out->add (substitute[i]);
326 327
  }

328 329
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
330
    TRACE_COLLECT_GLYPHS (this);
331
    c->output->add_array (substitute.arrayZ, substitute.len);
332 333
  }

334
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
335
  {
B
Behdad Esfahbod 已提交
336
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
337
    unsigned int count = substitute.len;
338

B
Behdad Esfahbod 已提交
339 340 341
    /* Special-case to make it in-place and not consider this
     * as a "multiplied" substitution. */
    if (unlikely (count == 1))
342
    {
343
      c->replace_glyph (substitute.arrayZ[0]);
B
Behdad Esfahbod 已提交
344
      return_trace (true);
345
    }
346
    /* Spec disallows this, but Uniscribe allows it.
347
     * https://github.com/harfbuzz/harfbuzz/issues/253 */
348 349 350 351 352
    else if (unlikely (count == 0))
    {
      c->buffer->delete_glyph ();
      return_trace (true);
    }
B
Behdad Esfahbod 已提交
353 354 355 356 357 358

    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);
359
      c->output_glyph_for_component (substitute.arrayZ[i], klass);
360
    }
B
Behdad Esfahbod 已提交
361
    c->buffer->skip_glyph ();
B
Behdad Esfahbod 已提交
362

B
Behdad Esfahbod 已提交
363
    return_trace (true);
B
Behdad Esfahbod 已提交
364 365
  }

366
  inline bool serialize (hb_serialize_context_t *c,
367
			 Supplier<GlyphID> &glyphs,
368 369
			 unsigned int num_glyphs)
  {
B
Behdad Esfahbod 已提交
370
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
371 372 373
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    if (unlikely (!substitute.serialize (c, glyphs, num_glyphs))) return_trace (false);
    return_trace (true);
374 375
  }

B
Behdad Esfahbod 已提交
376 377
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
378
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
379
    return_trace (substitute.sanitize (c));
B
Behdad Esfahbod 已提交
380 381
  }

382
  protected:
B
Behdad Esfahbod 已提交
383 384
  ArrayOf<GlyphID>
		substitute;		/* String of GlyphIDs to substitute */
385
  public:
386
  DEFINE_SIZE_ARRAY (2, substitute);
B
Behdad Esfahbod 已提交
387 388
};

B
Behdad Esfahbod 已提交
389 390
struct MultipleSubstFormat1
{
391 392 393
  inline bool intersects (const hb_set_t *glyphs) const
  { return (this+coverage).intersects (glyphs); }

B
Behdad Esfahbod 已提交
394
  inline void closure (hb_closure_context_t *c) const
395
  {
B
Behdad Esfahbod 已提交
396
    TRACE_CLOSURE (this);
397
    unsigned int count = sequence.len;
398
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
399 400
    {
      if (unlikely (iter.get_coverage () >= count))
401
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
B
Behdad Esfahbod 已提交
402
      if (c->glyphs->has (iter.get_glyph ()))
B
Behdad Esfahbod 已提交
403
	(this+sequence[iter.get_coverage ()]).closure (c);
B
Behdad Esfahbod 已提交
404
    }
405 406
  }

407 408
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
409
    TRACE_COLLECT_GLYPHS (this);
410
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
411 412
    unsigned int count = sequence.len;
    for (unsigned int i = 0; i < count; i++)
413
      (this+sequence[i]).collect_glyphs (c);
414 415
  }

416
  inline const Coverage &get_coverage (void) const
417
  { return this+coverage; }
418

419 420
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
421
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
422
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
423 424
  }

425
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
426
  {
B
Behdad Esfahbod 已提交
427
    TRACE_APPLY (this);
428

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

B
Behdad Esfahbod 已提交
432
    return_trace ((this+sequence[index]).apply (c));
433
  }
B
Behdad Esfahbod 已提交
434

435
  inline bool serialize (hb_serialize_context_t *c,
436 437
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &substitute_len_list,
438
			 unsigned int num_glyphs,
439
			 Supplier<GlyphID> &substitute_glyphs_list)
440
  {
B
Behdad Esfahbod 已提交
441
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
442 443
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    if (unlikely (!sequence.serialize (c, num_glyphs))) return_trace (false);
444 445 446
    for (unsigned int i = 0; i < num_glyphs; i++)
      if (unlikely (!sequence[i].serialize (c, this).serialize (c,
								substitute_glyphs_list,
B
Behdad Esfahbod 已提交
447
								substitute_len_list[i]))) return_trace (false);
448
    substitute_len_list += num_glyphs;
B
Behdad Esfahbod 已提交
449 450
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
    return_trace (true);
451 452
  }

453 454 455 456 457 458 459
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

B
Behdad Esfahbod 已提交
460 461
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
462
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
463
    return_trace (coverage.sanitize (c, this) && sequence.sanitize (c, this));
B
Behdad Esfahbod 已提交
464 465
  }

466
  protected:
B
Behdad Esfahbod 已提交
467
  HBUINT16	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
468 469
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
470
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
471 472 473
  OffsetArrayOf<Sequence>
		sequence;		/* Array of Sequence tables
					 * ordered by Coverage Index */
474
  public:
475
  DEFINE_SIZE_ARRAY (6, sequence);
B
Behdad Esfahbod 已提交
476
};
477

B
Behdad Esfahbod 已提交
478 479
struct MultipleSubst
{
480
  inline bool serialize (hb_serialize_context_t *c,
481 482
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &substitute_len_list,
483
			 unsigned int num_glyphs,
484
			 Supplier<GlyphID> &substitute_glyphs_list)
485
  {
B
Behdad Esfahbod 已提交
486
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
487
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
488 489 490
    unsigned int format = 1;
    u.format.set (format);
    switch (u.format) {
B
Behdad Esfahbod 已提交
491 492
    case 1: return_trace (u.format1.serialize (c, glyphs, substitute_len_list, num_glyphs, substitute_glyphs_list));
    default:return_trace (false);
493 494 495
    }
  }

B
Behdad Esfahbod 已提交
496 497 498
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
  {
499
    TRACE_DISPATCH (this, u.format);
500
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
501
    switch (u.format) {
B
Behdad Esfahbod 已提交
502 503
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
504 505 506
    }
  }

507
  protected:
508
  union {
B
Behdad Esfahbod 已提交
509
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
510
  MultipleSubstFormat1	format1;
511 512 513
  } u;
};

514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546
struct AlternateSet
{
  inline void closure (hb_closure_context_t *c) const
  {
    TRACE_CLOSURE (this);
    unsigned int count = alternates.len;
    for (unsigned int i = 0; i < count; i++)
      c->out->add (alternates[i]);
  }

  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
    TRACE_COLLECT_GLYPHS (this);
    c->output->add_array (alternates.arrayZ, alternates.len);
  }

  inline bool apply (hb_ot_apply_context_t *c) const
  {
    TRACE_APPLY (this);
    unsigned int count = alternates.len;

    if (unlikely (!count)) return_trace (false);

    hb_mask_t glyph_mask = c->buffer->cur().mask;
    hb_mask_t lookup_mask = c->lookup_mask;

    /* Note: This breaks badly if two features enabled this lookup together. */
    unsigned int shift = hb_ctz (lookup_mask);
    unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);

    if (unlikely (alt_index > count || alt_index == 0)) return_trace (false);

    c->replace_glyph (alternates[alt_index - 1]);
B
Behdad Esfahbod 已提交
547

548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569
    return_trace (true);
  }

  inline bool serialize (hb_serialize_context_t *c,
			 Supplier<GlyphID> &glyphs,
			 unsigned int num_glyphs)
  {
    TRACE_SERIALIZE (this);
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    if (unlikely (!alternates.serialize (c, glyphs, num_glyphs))) return_trace (false);
    return_trace (true);
  }

  inline bool sanitize (hb_sanitize_context_t *c) const
  {
    TRACE_SANITIZE (this);
    return_trace (alternates.sanitize (c));
  }

  protected:
  ArrayOf<GlyphID>
		alternates;		/* Array of alternate GlyphIDs--in
B
Behdad Esfahbod 已提交
570
					 * arbitrary order */
571 572 573
  public:
  DEFINE_SIZE_ARRAY (2, alternates);
};
B
Behdad Esfahbod 已提交
574

B
Behdad Esfahbod 已提交
575 576
struct AlternateSubstFormat1
{
577 578 579
  inline bool intersects (const hb_set_t *glyphs) const
  { return (this+coverage).intersects (glyphs); }

B
Behdad Esfahbod 已提交
580
  inline void closure (hb_closure_context_t *c) const
581
  {
B
Behdad Esfahbod 已提交
582
    TRACE_CLOSURE (this);
583
    unsigned int count = alternateSet.len;
584
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
585 586
    {
      if (unlikely (iter.get_coverage () >= count))
587
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
588 589
      if (c->glyphs->has (iter.get_glyph ()))
	(this+alternateSet[iter.get_coverage ()]).closure (c);
B
Behdad Esfahbod 已提交
590
    }
591 592
  }

593 594
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
595
    TRACE_COLLECT_GLYPHS (this);
596
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
597
    unsigned int count = alternateSet.len;
598
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
599 600
    {
      if (unlikely (iter.get_coverage () >= count))
601
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
602
      (this+alternateSet[iter.get_coverage ()]).collect_glyphs (c);
603 604 605
    }
  }

606
  inline const Coverage &get_coverage (void) const
607
  { return this+coverage; }
608

609 610
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
611
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
612
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
613 614
  }

615
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
616
  {
B
Behdad Esfahbod 已提交
617
    TRACE_APPLY (this);
618

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

622
    return_trace ((this+alternateSet[index]).apply (c));
623
  }
B
Behdad Esfahbod 已提交
624

625
  inline bool serialize (hb_serialize_context_t *c,
626 627
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &alternate_len_list,
628
			 unsigned int num_glyphs,
629
			 Supplier<GlyphID> &alternate_glyphs_list)
630
  {
B
Behdad Esfahbod 已提交
631
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
632 633
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    if (unlikely (!alternateSet.serialize (c, num_glyphs))) return_trace (false);
634 635 636
    for (unsigned int i = 0; i < num_glyphs; i++)
      if (unlikely (!alternateSet[i].serialize (c, this).serialize (c,
								    alternate_glyphs_list,
B
Behdad Esfahbod 已提交
637
								    alternate_len_list[i]))) return_trace (false);
638
    alternate_len_list += num_glyphs;
B
Behdad Esfahbod 已提交
639 640
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
    return_trace (true);
641 642
  }

643 644 645 646 647 648 649
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

B
Behdad Esfahbod 已提交
650 651
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
652
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
653
    return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
654 655
  }

656
  protected:
B
Behdad Esfahbod 已提交
657
  HBUINT16	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
658 659
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
660
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
661 662 663
  OffsetArrayOf<AlternateSet>
		alternateSet;		/* Array of AlternateSet tables
					 * ordered by Coverage Index */
664
  public:
665
  DEFINE_SIZE_ARRAY (6, alternateSet);
B
Behdad Esfahbod 已提交
666
};
667

B
Behdad Esfahbod 已提交
668 669
struct AlternateSubst
{
670
  inline bool serialize (hb_serialize_context_t *c,
671 672
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &alternate_len_list,
673
			 unsigned int num_glyphs,
674
			 Supplier<GlyphID> &alternate_glyphs_list)
675
  {
B
Behdad Esfahbod 已提交
676
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
677
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
678 679 680
    unsigned int format = 1;
    u.format.set (format);
    switch (u.format) {
B
Behdad Esfahbod 已提交
681 682
    case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, num_glyphs, alternate_glyphs_list));
    default:return_trace (false);
683 684 685
    }
  }

B
Behdad Esfahbod 已提交
686 687 688
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
  {
689
    TRACE_DISPATCH (this, u.format);
690
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
691
    switch (u.format) {
B
Behdad Esfahbod 已提交
692 693
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
694 695 696
    }
  }

697
  protected:
698
  union {
B
Behdad Esfahbod 已提交
699
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
700
  AlternateSubstFormat1	format1;
701 702 703
  } u;
};

704

B
Behdad Esfahbod 已提交
705 706
struct Ligature
{
707 708 709 710 711 712 713 714 715
  inline bool intersects (const hb_set_t *glyphs) const
  {
    unsigned int count = component.len;
    for (unsigned int i = 1; i < count; i++)
      if (!glyphs->has (component[i]))
        return false;
    return true;
  }

B
Behdad Esfahbod 已提交
716
  inline void closure (hb_closure_context_t *c) const
717
  {
B
Behdad Esfahbod 已提交
718
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
719 720 721
    unsigned int count = component.len;
    for (unsigned int i = 1; i < count; i++)
      if (!c->glyphs->has (component[i]))
B
Behdad Esfahbod 已提交
722
        return;
723
    c->out->add (ligGlyph);
724 725
  }

726 727
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
728
    TRACE_COLLECT_GLYPHS (this);
729
    c->input->add_array (component.arrayZ, component.len ? component.len - 1 : 0);
B
Minor  
Behdad Esfahbod 已提交
730
    c->output->add (ligGlyph);
731 732
  }

733
  inline bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
734
  {
B
Behdad Esfahbod 已提交
735
    TRACE_WOULD_APPLY (this);
736
    if (c->len != component.len)
B
Behdad Esfahbod 已提交
737
      return_trace (false);
738 739 740

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

B
Behdad Esfahbod 已提交
743
    return_trace (true);
B
Behdad Esfahbod 已提交
744 745
  }

746
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
747
  {
B
Behdad Esfahbod 已提交
748
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
749
    unsigned int count = component.len;
B
Behdad Esfahbod 已提交
750

B
Behdad Esfahbod 已提交
751
    if (unlikely (!count)) return_trace (false);
B
Behdad Esfahbod 已提交
752

753 754 755 756 757
    /* 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 已提交
758
      return_trace (true);
759 760
    }

B
Behdad Esfahbod 已提交
761 762
    bool is_mark_ligature = false;
    unsigned int total_component_count = 0;
763

764
    unsigned int match_length = 0;
765
    unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
766

767 768 769
    if (likely (!match_input (c, count,
			      &component[1],
			      match_glyph,
B
Behdad Esfahbod 已提交
770
			      nullptr,
771 772
			      &match_length,
			      match_positions,
773 774
			      &is_mark_ligature,
			      &total_component_count)))
B
Behdad Esfahbod 已提交
775
      return_trace (false);
776

777 778
    ligate_input (c,
		  count,
779 780
		  match_positions,
		  match_length,
781
		  ligGlyph,
782 783
		  is_mark_ligature,
		  total_component_count);
784

B
Behdad Esfahbod 已提交
785
    return_trace (true);
786
  }
787

788 789 790 791 792
  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 已提交
793
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
794
    if (unlikely (!c->extend_min (*this))) return_trace (false);
795
    ligGlyph = ligature;
B
Behdad Esfahbod 已提交
796 797
    if (unlikely (!component.serialize (c, components, num_components))) return_trace (false);
    return_trace (true);
798 799
  }

B
Behdad Esfahbod 已提交
800
  public:
B
Behdad Esfahbod 已提交
801 802
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
803
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
804
    return_trace (ligGlyph.sanitize (c) && component.sanitize (c));
B
Behdad Esfahbod 已提交
805 806
  }

807
  protected:
808
  GlyphID	ligGlyph;		/* GlyphID of ligature to substitute */
B
Behdad Esfahbod 已提交
809 810
  HeadlessArrayOf<GlyphID>
		component;		/* Array of component GlyphIDs--start
811 812
					 * with the second  component--ordered
					 * in writing direction */
813
  public:
814
  DEFINE_SIZE_ARRAY (4, component);
815
};
B
Behdad Esfahbod 已提交
816

B
Behdad Esfahbod 已提交
817 818
struct LigatureSet
{
819 820 821 822 823 824 825 826 827
  inline bool intersects (const hb_set_t *glyphs) const
  {
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
      if ((this+ligature[i]).intersects (glyphs))
        return true;
    return false;
  }

B
Behdad Esfahbod 已提交
828
  inline void closure (hb_closure_context_t *c) const
829
  {
B
Behdad Esfahbod 已提交
830
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
831 832
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
B
Behdad Esfahbod 已提交
833
      (this+ligature[i]).closure (c);
834 835
  }

836 837
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
838
    TRACE_COLLECT_GLYPHS (this);
839 840 841 842 843
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
      (this+ligature[i]).collect_glyphs (c);
  }

844
  inline bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
845
  {
B
Behdad Esfahbod 已提交
846
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
847 848 849 850
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
    {
      const Ligature &lig = this+ligature[i];
851
      if (lig.would_apply (c))
B
Behdad Esfahbod 已提交
852
        return_trace (true);
B
Behdad Esfahbod 已提交
853
    }
B
Behdad Esfahbod 已提交
854
    return_trace (false);
B
Behdad Esfahbod 已提交
855 856
  }

857
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
858
  {
B
Behdad Esfahbod 已提交
859
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
860
    unsigned int num_ligs = ligature.len;
B
Behdad Esfahbod 已提交
861 862
    for (unsigned int i = 0; i < num_ligs; i++)
    {
B
Behdad Esfahbod 已提交
863
      const Ligature &lig = this+ligature[i];
B
Behdad Esfahbod 已提交
864
      if (lig.apply (c)) return_trace (true);
865 866
    }

B
Behdad Esfahbod 已提交
867
    return_trace (false);
868
  }
B
Behdad Esfahbod 已提交
869

870 871 872 873 874 875
  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 已提交
876
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
877 878
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    if (unlikely (!ligature.serialize (c, num_ligatures))) return_trace (false);
879 880 881 882
    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 已提交
883
								component_count_list[i]))) return_trace (false);
884 885
    ligatures += num_ligatures;
    component_count_list += num_ligatures;
B
Behdad Esfahbod 已提交
886
    return_trace (true);
887 888
  }

B
Behdad Esfahbod 已提交
889 890
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
891
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
892
    return_trace (ligature.sanitize (c, this));
B
Behdad Esfahbod 已提交
893 894
  }

895
  protected:
B
Behdad Esfahbod 已提交
896 897 898
  OffsetArrayOf<Ligature>
		ligature;		/* Array LigatureSet tables
					 * ordered by preference */
899
  public:
900
  DEFINE_SIZE_ARRAY (2, ligature);
B
Behdad Esfahbod 已提交
901 902
};

B
Behdad Esfahbod 已提交
903 904
struct LigatureSubstFormat1
{
905 906 907 908 909 910 911 912 913 914 915 916 917 918
  inline bool intersects (const hb_set_t *glyphs) const
  {
    unsigned int count = ligatureSet.len;
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
    {
      if (unlikely (iter.get_coverage () >= count))
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
      if (glyphs->has (iter.get_glyph ()) &&
	  (this+ligatureSet[iter.get_coverage ()]).intersects (glyphs))
        return true;
    }
    return false;
  }

B
Behdad Esfahbod 已提交
919
  inline void closure (hb_closure_context_t *c) const
920
  {
B
Behdad Esfahbod 已提交
921
    TRACE_CLOSURE (this);
922
    unsigned int count = ligatureSet.len;
923
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
924 925
    {
      if (unlikely (iter.get_coverage () >= count))
926
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
B
Behdad Esfahbod 已提交
927
      if (c->glyphs->has (iter.get_glyph ()))
B
Behdad Esfahbod 已提交
928
	(this+ligatureSet[iter.get_coverage ()]).closure (c);
B
Behdad Esfahbod 已提交
929
    }
930 931
  }

932 933
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
934
    TRACE_COLLECT_GLYPHS (this);
935
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
936
    unsigned int count = ligatureSet.len;
937
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
938 939
    {
      if (unlikely (iter.get_coverage () >= count))
940
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
941 942 943 944
      (this+ligatureSet[iter.get_coverage ()]).collect_glyphs (c);
    }
  }

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

948
  inline bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
949
  {
B
Behdad Esfahbod 已提交
950
    TRACE_WOULD_APPLY (this);
951
    unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
B
Behdad Esfahbod 已提交
952
    if (likely (index == NOT_COVERED)) return_trace (false);
953 954

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

958
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
959
  {
B
Behdad Esfahbod 已提交
960
    TRACE_APPLY (this);
961

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

B
Behdad Esfahbod 已提交
965
    const LigatureSet &lig_set = this+ligatureSet[index];
B
Behdad Esfahbod 已提交
966
    return_trace (lig_set.apply (c));
967
  }
B
Behdad Esfahbod 已提交
968

969 970 971 972 973 974 975 976
  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 已提交
977
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
978 979
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    if (unlikely (!ligatureSet.serialize (c, num_first_glyphs))) return_trace (false);
980 981 982 983 984
    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 已提交
985
								   component_list))) return_trace (false);
986
    ligature_per_first_glyph_count_list += num_first_glyphs;
B
Behdad Esfahbod 已提交
987 988
    if (unlikely (!coverage.serialize (c, this).serialize (c, first_glyphs, num_first_glyphs))) return_trace (false);
    return_trace (true);
989 990
  }

991 992 993 994 995 996 997
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

B
Behdad Esfahbod 已提交
998 999
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1000
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1001
    return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
1002 1003
  }

1004
  protected:
B
Behdad Esfahbod 已提交
1005
  HBUINT16	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
1006 1007
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
1008
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
1009
  OffsetArrayOf<LigatureSet>
B
Behdad Esfahbod 已提交
1010 1011
		ligatureSet;		/* Array LigatureSet tables
					 * ordered by Coverage Index */
1012
  public:
1013
  DEFINE_SIZE_ARRAY (6, ligatureSet);
B
Behdad Esfahbod 已提交
1014
};
1015

B
Behdad Esfahbod 已提交
1016 1017
struct LigatureSubst
{
1018 1019 1020 1021 1022 1023 1024 1025
  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 已提交
1026
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1027
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
1028 1029 1030
    unsigned int format = 1;
    u.format.set (format);
    switch (u.format) {
B
Behdad Esfahbod 已提交
1031 1032 1033 1034 1035 1036 1037 1038
    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);
1039 1040 1041
    }
  }

B
Behdad Esfahbod 已提交
1042 1043 1044
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
  {
1045
    TRACE_DISPATCH (this, u.format);
1046
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
1047
    switch (u.format) {
B
Behdad Esfahbod 已提交
1048 1049
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
1050 1051 1052
    }
  }

1053
  protected:
1054
  union {
B
Behdad Esfahbod 已提交
1055
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1056
  LigatureSubstFormat1	format1;
1057 1058 1059
  } u;
};

B
Behdad Esfahbod 已提交
1060

B
Minor  
Behdad Esfahbod 已提交
1061
struct ContextSubst : Context {};
B
Behdad Esfahbod 已提交
1062

B
Minor  
Behdad Esfahbod 已提交
1063
struct ChainContextSubst : ChainContext {};
1064

B
Behdad Esfahbod 已提交
1065
struct ExtensionSubst : Extension<ExtensionSubst>
B
Behdad Esfahbod 已提交
1066
{
B
Behdad Esfahbod 已提交
1067
  typedef struct SubstLookupSubTable SubTable;
B
Behdad Esfahbod 已提交
1068

B
Behdad Esfahbod 已提交
1069
  inline bool is_reverse (void) const;
1070 1071 1072
};


B
Behdad Esfahbod 已提交
1073 1074
struct ReverseChainSingleSubstFormat1
{
1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096
  inline bool intersects (const hb_set_t *glyphs) const
  {
    if (!(this+coverage).intersects (glyphs))
      return false;

    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 (glyphs))
        return false;

    count = lookahead.len;
    for (unsigned int i = 0; i < count; i++)
      if (!(this+lookahead[i]).intersects (glyphs))
        return false;

    return true;
  }

B
Behdad Esfahbod 已提交
1097
  inline void closure (hb_closure_context_t *c) const
1098
  {
B
Behdad Esfahbod 已提交
1099
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
1100 1101 1102 1103 1104 1105 1106
    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 已提交
1107
        return;
B
Behdad Esfahbod 已提交
1108 1109 1110 1111

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

    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
1115
    count = substitute.len;
1116
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
1117 1118
    {
      if (unlikely (iter.get_coverage () >= count))
1119
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
B
Behdad Esfahbod 已提交
1120
      if (c->glyphs->has (iter.get_glyph ()))
1121
	c->out->add (substitute[iter.get_coverage ()]);
B
Behdad Esfahbod 已提交
1122
    }
1123 1124
  }

1125 1126
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1127
    TRACE_COLLECT_GLYPHS (this);
1128
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
1129 1130 1131 1132 1133

    unsigned int count;

    count = backtrack.len;
    for (unsigned int i = 0; i < count; i++)
1134
      if (unlikely (!(this+backtrack[i]).add_coverage (c->before))) return;
1135

1136
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1137 1138
    count = lookahead.len;
    for (unsigned int i = 0; i < count; i++)
1139
      if (unlikely (!(this+lookahead[i]).add_coverage (c->after))) return;
1140 1141 1142

    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
    count = substitute.len;
1143
    c->output->add_array (substitute.arrayZ, substitute.len);
1144 1145
  }

1146
  inline const Coverage &get_coverage (void) const
1147
  { return this+coverage; }
1148

1149 1150
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1151
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
1152
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
1153 1154
  }

1155
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1156
  {
B
Behdad Esfahbod 已提交
1157
    TRACE_APPLY (this);
1158
    if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
B
Behdad Esfahbod 已提交
1159
      return_trace (false); /* No chaining to this type */
1160

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

1164 1165
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
1166

1167
  unsigned int start_index = 0, end_index = 0;
B
Behdad Esfahbod 已提交
1168
    if (match_backtrack (c,
1169
			 backtrack.len, (HBUINT16 *) backtrack.arrayZ,
1170 1171
			 match_coverage, this,
			 &start_index) &&
B
Behdad Esfahbod 已提交
1172
        match_lookahead (c,
1173
			 lookahead.len, (HBUINT16 *) lookahead.arrayZ,
B
Behdad Esfahbod 已提交
1174
			 match_coverage, this,
1175
			 1, &end_index))
1176
    {
1177
      c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index);
B
Behdad Esfahbod 已提交
1178
      c->replace_glyph_inplace (substitute[index]);
1179 1180 1181
      /* 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 已提交
1182
      return_trace (true);
1183 1184
    }

B
Behdad Esfahbod 已提交
1185
    return_trace (false);
1186
  }
B
Behdad Esfahbod 已提交
1187

1188 1189 1190 1191 1192 1193 1194
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

B
Behdad Esfahbod 已提交
1195 1196
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1197
    TRACE_SANITIZE (this);
1198
    if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
B
Behdad Esfahbod 已提交
1199
      return_trace (false);
B
Behdad Esfahbod 已提交
1200
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
B
Behdad Esfahbod 已提交
1201
    if (!lookahead.sanitize (c, this))
B
Behdad Esfahbod 已提交
1202
      return_trace (false);
B
Behdad Esfahbod 已提交
1203
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
B
Behdad Esfahbod 已提交
1204
    return_trace (substitute.sanitize (c));
B
Behdad Esfahbod 已提交
1205 1206
  }

1207
  protected:
B
Behdad Esfahbod 已提交
1208
  HBUINT16	format;			/* Format identifier--format = 1 */
1209 1210 1211 1212 1213
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of table */
  OffsetArrayOf<Coverage>
		backtrack;		/* Array of coverage tables
1214
					 * in backtracking sequence, in glyph
B
Behdad Esfahbod 已提交
1215
					 * sequence order */
1216 1217 1218
  OffsetArrayOf<Coverage>
		lookaheadX;		/* Array of coverage tables
					 * in lookahead sequence, in glyph
B
Behdad Esfahbod 已提交
1219
					 * sequence order */
1220 1221 1222
  ArrayOf<GlyphID>
		substituteX;		/* Array of substitute
					 * GlyphIDs--ordered by Coverage Index */
1223
  public:
B
Behdad Esfahbod 已提交
1224
  DEFINE_SIZE_MIN (10);
B
Behdad Esfahbod 已提交
1225 1226
};

B
Behdad Esfahbod 已提交
1227 1228
struct ReverseChainSingleSubst
{
1229
  template <typename context_t>
1230
  inline typename context_t::return_t dispatch (context_t *c) const
1231
  {
1232
    TRACE_DISPATCH (this, u.format);
1233
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1234
    switch (u.format) {
B
Behdad Esfahbod 已提交
1235 1236
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
1237 1238 1239
    }
  }

1240
  protected:
1241
  union {
B
Behdad Esfahbod 已提交
1242
  HBUINT16				format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1243
  ReverseChainSingleSubstFormat1	format1;
1244 1245 1246 1247 1248
  } u;
};



B
Behdad Esfahbod 已提交
1249 1250 1251 1252
/*
 * SubstLookup
 */

B
Behdad Esfahbod 已提交
1253 1254
struct SubstLookupSubTable
{
B
Behdad Esfahbod 已提交
1255
  friend struct Lookup;
B
Behdad Esfahbod 已提交
1256 1257
  friend struct SubstLookup;

B
Behdad Esfahbod 已提交
1258
  enum Type {
1259 1260 1261 1262 1263 1264 1265
    Single		= 1,
    Multiple		= 2,
    Alternate		= 3,
    Ligature		= 4,
    Context		= 5,
    ChainContext	= 6,
    Extension		= 7,
1266
    ReverseChainSingle	= 8
1267 1268
  };

1269
  template <typename context_t>
1270
  inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
1271
  {
1272
    TRACE_DISPATCH (this, lookup_type);
1273
    if (unlikely (!c->may_dispatch (this, &u.sub_format))) return_trace (c->no_dispatch_return_value ());
1274
    switch (lookup_type) {
B
Behdad Esfahbod 已提交
1275 1276 1277 1278 1279 1280 1281 1282 1283
    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 ());
1284 1285 1286
    }
  }

1287
  protected:
B
Behdad Esfahbod 已提交
1288
  union {
B
Behdad Esfahbod 已提交
1289
  HBUINT16			sub_format;
B
Behdad Esfahbod 已提交
1290 1291 1292 1293
  SingleSubst			single;
  MultipleSubst			multiple;
  AlternateSubst		alternate;
  LigatureSubst			ligature;
1294
  ContextSubst			context;
B
Behdad Esfahbod 已提交
1295 1296 1297
  ChainContextSubst		chainContext;
  ExtensionSubst		extension;
  ReverseChainSingleSubst	reverseChainContextSingle;
B
Behdad Esfahbod 已提交
1298
  } u;
B
Behdad Esfahbod 已提交
1299
  public:
B
Minor  
Behdad Esfahbod 已提交
1300
  DEFINE_SIZE_UNION (2, sub_format);
B
Behdad Esfahbod 已提交
1301 1302
};

1303

B
Behdad Esfahbod 已提交
1304 1305
struct SubstLookup : Lookup
{
B
Behdad Esfahbod 已提交
1306 1307 1308 1309
  typedef SubstLookupSubTable SubTable;

  inline const SubTable& get_subtable (unsigned int i) const
  { return Lookup::get_subtable<SubTable> (i); }
B
Behdad Esfahbod 已提交
1310

B
Behdad Esfahbod 已提交
1311
  inline static bool lookup_type_is_reverse (unsigned int lookup_type)
B
Behdad Esfahbod 已提交
1312
  { return lookup_type == SubTable::ReverseChainSingle; }
B
Behdad Esfahbod 已提交
1313 1314

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

1322
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1323 1324
  {
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
1325
    return_trace (dispatch (c));
B
Behdad Esfahbod 已提交
1326 1327
  }

1328 1329 1330 1331 1332 1333
  inline bool intersects (const hb_set_t *glyphs) const
  {
    hb_intersects_context_t c (glyphs);
    return dispatch (&c);
  }

1334
  inline hb_closure_context_t::return_t closure (hb_closure_context_t *c, unsigned int this_index) const
1335
  {
B
Behdad Esfahbod 已提交
1336
    TRACE_CLOSURE (this);
1337
    if (!c->should_visit_lookup (this_index))
1338 1339 1340
      return_trace (HB_VOID);

    c->set_recurse_func (dispatch_closure_recurse_func);
1341 1342 1343 1344 1345 1346

    hb_closure_context_t::return_t ret = dispatch (c);

    c->flush ();

    return_trace (ret);
B
Behdad Esfahbod 已提交
1347 1348
  }

B
Behdad Esfahbod 已提交
1349
  inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
B
Behdad Esfahbod 已提交
1350 1351
  {
    TRACE_COLLECT_GLYPHS (this);
1352
    c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
B
Behdad Esfahbod 已提交
1353
    return_trace (dispatch (c));
1354 1355
  }

B
Behdad Esfahbod 已提交
1356 1357 1358
  template <typename set_t>
  inline void add_coverage (set_t *glyphs) const
  {
1359 1360
    hb_add_coverage_context_t<set_t> c (glyphs);
    dispatch (&c);
B
Behdad Esfahbod 已提交
1361 1362
  }

1363 1364
  inline bool would_apply (hb_would_apply_context_t *c,
			   const hb_ot_layout_lookup_accelerator_t *accel) const
B
Behdad Esfahbod 已提交
1365
  {
B
Behdad Esfahbod 已提交
1366
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
1367 1368 1369
    if (unlikely (!c->len))  return_trace (false);
    if (!accel->may_have (c->glyphs[0]))  return_trace (false);
      return_trace (dispatch (c));
B
Behdad Esfahbod 已提交
1370 1371
  }

1372
  static bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index);
B
Behdad Esfahbod 已提交
1373

B
Behdad Esfahbod 已提交
1374 1375 1376
  inline SubTable& serialize_subtable (hb_serialize_context_t *c,
				       unsigned int i)
  { return get_subtables<SubTable> ()[i].serialize (c, this); }
1377 1378 1379 1380 1381 1382 1383

  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 已提交
1384
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1385
    if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1386
    return_trace (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes, num_glyphs));
1387 1388 1389 1390 1391 1392 1393 1394 1395
  }

  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 已提交
1396
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1397
    if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1398 1399 1400 1401 1402
    return_trace (serialize_subtable (c, 0).u.multiple.serialize (c,
								  glyphs,
								  substitute_len_list,
								  num_glyphs,
								  substitute_glyphs_list));
1403 1404 1405 1406 1407 1408 1409 1410 1411
  }

  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 已提交
1412
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1413
    if (unlikely (!Lookup::serialize (c, SubTable::Alternate, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1414 1415 1416 1417 1418
    return_trace (serialize_subtable (c, 0).u.alternate.serialize (c,
								   glyphs,
								   alternate_len_list,
								   num_glyphs,
								   alternate_glyphs_list));
1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429
  }

  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 已提交
1430
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1431
    if (unlikely (!Lookup::serialize (c, SubTable::Ligature, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1432 1433 1434 1435 1436 1437 1438
    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));
1439 1440
  }

B
Behdad Esfahbod 已提交
1441 1442 1443
  template <typename context_t>
  static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);

B
Behdad Esfahbod 已提交
1444
  static inline hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned int lookup_index)
1445
  {
1446
    if (!c->should_visit_lookup (lookup_index))
1447
      return HB_VOID;
1448 1449 1450 1451 1452 1453

    hb_closure_context_t::return_t ret = dispatch_recurse_func (c, lookup_index);

    c->flush ();

    return ret;
1454 1455
  }

B
Behdad Esfahbod 已提交
1456 1457
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
B
Behdad Esfahbod 已提交
1458 1459 1460
  { return Lookup::dispatch<SubTable> (c); }

  inline bool subset (hb_subset_context_t *c) const
1461
  { return Lookup::subset<SubTable> (c); }
B
Behdad Esfahbod 已提交
1462

B
Behdad Esfahbod 已提交
1463
  inline bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
1464
  { return Lookup::sanitize<SubTable> (c); }
B
Behdad Esfahbod 已提交
1465 1466
};

B
Minor  
Behdad Esfahbod 已提交
1467
/*
1468 1469
 * GSUB -- Glyph Substitution
 * https://docs.microsoft.com/en-us/typography/opentype/spec/gsub
B
Minor  
Behdad Esfahbod 已提交
1470 1471
 */

B
Behdad Esfahbod 已提交
1472 1473
struct GSUB : GSUBGPOS
{
1474
  static const hb_tag_t tableTag	= HB_OT_TAG_GSUB;
B
Minor  
Behdad Esfahbod 已提交
1475

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

1479
  inline bool subset (hb_subset_context_t *c) const
1480
  { return GSUBGPOS::subset<SubstLookup> (c); }
1481

B
Behdad Esfahbod 已提交
1482
  inline bool sanitize (hb_sanitize_context_t *c) const
1483
  { return GSUBGPOS::sanitize<SubstLookup> (c); }
B
WIP  
Behdad Esfahbod 已提交
1484 1485

  typedef GSUBGPOS::accelerator_t<GSUB> accelerator_t;
B
Minor  
Behdad Esfahbod 已提交
1486
};
1487 1488


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

1491
/*static*/ inline bool ExtensionSubst::is_reverse (void) const
B
Behdad Esfahbod 已提交
1492 1493
{
  unsigned int type = get_type ();
B
Behdad Esfahbod 已提交
1494 1495
  if (unlikely (type == SubTable::Extension))
    return CastR<ExtensionSubst> (get_subtable<SubTable>()).is_reverse ();
B
Behdad Esfahbod 已提交
1496 1497 1498
  return SubstLookup::lookup_type_is_reverse (type);
}

1499
template <typename context_t>
1500
/*static*/ inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
1501
{
1502
  const SubstLookup &l = _get_gsub_relaxed (c->face).get_lookup (lookup_index);
1503
  return l.dispatch (c);
1504 1505
}

1506
/*static*/ inline bool SubstLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index)
B
Behdad Esfahbod 已提交
1507
{
1508
  const SubstLookup &l = _get_gsub_relaxed (c->face).get_lookup (lookup_index);
1509
  unsigned int saved_lookup_props = c->lookup_props;
1510 1511 1512
  unsigned int saved_lookup_index = c->lookup_index;
  c->set_lookup_index (lookup_index);
  c->set_lookup_props (l.get_props ());
1513
  bool ret = l.dispatch (c);
1514
  c->set_lookup_index (saved_lookup_index);
1515
  c->set_lookup_props (saved_lookup_props);
1516
  return ret;
1517 1518
}

1519
struct GSUB_accelerator_t : GSUB::accelerator_t {};
1520

B
Behdad Esfahbod 已提交
1521
} /* namespace OT */
1522

B
Behdad Esfahbod 已提交
1523

1524
#endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */