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

B
Behdad Esfahbod 已提交
34

35 36
namespace OT {

37

38
static inline void SingleSubst_serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
39 40
					  hb_array_t<const GlyphID> glyphs,
					  hb_array_t<const GlyphID> substitutes);
41

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

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

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

73
  const Coverage &get_coverage () const { return this+coverage; }
74

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

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

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

B
Behdad Esfahbod 已提交
93
    return_trace (true);
94
  }
B
Behdad Esfahbod 已提交
95

96
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
97
		  hb_array_t<const GlyphID> glyphs,
98
		  int delta)
99
  {
B
Behdad Esfahbod 已提交
100
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
101
    if (unlikely (!c->extend_min (*this))) return_trace (false);
B
Behdad Esfahbod 已提交
102
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs))) return_trace (false);
B
Bruce Mitchener 已提交
103
    deltaGlyphID.set (delta); /* TODO(serialize) overflow? */
B
Behdad Esfahbod 已提交
104
    return_trace (true);
105 106
  }

107
  bool subset (hb_subset_context_t *c) const
108 109
  {
    TRACE_SUBSET (this);
B
Behdad Esfahbod 已提交
110
    const hb_set_t &glyphset = *c->plan->glyphset;
111
    const hb_map_t &glyph_map = *c->plan->glyph_map;
112 113
    hb_vector_t<GlyphID> from;
    hb_vector_t<GlyphID> to;
114
    hb_codepoint_t delta = deltaGlyphID;
115
    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
116
    {
B
Behdad Esfahbod 已提交
117
      if (!glyphset.has (iter.get_glyph ())) continue;
118 119
      from.push ()->set (glyph_map[iter.get_glyph ()]);
      to.push ()->set (glyph_map[(iter.get_glyph () + delta) & 0xFFFF]);
120
    }
121
    c->serializer->propagate_error (from, to);
B
Behdad Esfahbod 已提交
122
    SingleSubst_serialize (c->serializer, from, to);
123
    return_trace (from.len);
124 125
  }

126
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
127
  {
B
Behdad Esfahbod 已提交
128
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
129
    return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
B
Behdad Esfahbod 已提交
130 131
  }

132
  protected:
B
Behdad Esfahbod 已提交
133
  HBUINT16	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
134 135
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
136
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
137
  HBINT16	deltaGlyphID;		/* Add to original GlyphID to get
B
Behdad Esfahbod 已提交
138
					 * substitute GlyphID */
139 140
  public:
  DEFINE_SIZE_STATIC (6);
B
Behdad Esfahbod 已提交
141 142
};

B
Behdad Esfahbod 已提交
143 144
struct SingleSubstFormat2
{
145
  bool intersects (const hb_set_t *glyphs) const
146 147
  { return (this+coverage).intersects (glyphs); }

148
  void closure (hb_closure_context_t *c) const
149
  {
B
Behdad Esfahbod 已提交
150
    TRACE_CLOSURE (this);
151
    unsigned int count = substitute.len;
152
    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
153 154
    {
      if (unlikely (iter.get_coverage () >= count))
155
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
B
Behdad Esfahbod 已提交
156
      if (c->glyphs->has (iter.get_glyph ()))
157
	c->out->add (substitute[iter.get_coverage ()]);
B
Behdad Esfahbod 已提交
158
    }
159 160
  }

161
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
162
  {
B
Behdad Esfahbod 已提交
163
    TRACE_COLLECT_GLYPHS (this);
164
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
165
    unsigned int count = substitute.len;
166
    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
167 168
    {
      if (unlikely (iter.get_coverage () >= count))
169
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
B
Minor  
Behdad Esfahbod 已提交
170
      c->output->add (substitute[iter.get_coverage ()]);
171 172 173
    }
  }

174
  const Coverage &get_coverage () const { return this+coverage; }
175

176
  bool would_apply (hb_would_apply_context_t *c) const
177
  {
B
Behdad Esfahbod 已提交
178
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
179
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
180 181
  }

182
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
183
  {
B
Behdad Esfahbod 已提交
184
    TRACE_APPLY (this);
185
    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
B
Behdad Esfahbod 已提交
186
    if (likely (index == NOT_COVERED)) return_trace (false);
187

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

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

B
Behdad Esfahbod 已提交
192
    return_trace (true);
193
  }
B
Behdad Esfahbod 已提交
194

195
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
196 197
		  hb_array_t<const GlyphID> glyphs,
		  hb_array_t<const GlyphID> substitutes)
B
Behdad Esfahbod 已提交
198
  {
B
Behdad Esfahbod 已提交
199
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
200
    if (unlikely (!c->extend_min (*this))) return_trace (false);
B
Behdad Esfahbod 已提交
201 202
    if (unlikely (!substitute.serialize (c, substitutes))) return_trace (false);
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs))) return_trace (false);
B
Behdad Esfahbod 已提交
203
    return_trace (true);
B
Behdad Esfahbod 已提交
204 205
  }

206
  bool subset (hb_subset_context_t *c) const
207 208
  {
    TRACE_SUBSET (this);
B
Behdad Esfahbod 已提交
209
    const hb_set_t &glyphset = *c->plan->glyphset;
210
    const hb_map_t &glyph_map = *c->plan->glyph_map;
211 212
    hb_vector_t<GlyphID> from;
    hb_vector_t<GlyphID> to;
213
    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
214
    {
B
Behdad Esfahbod 已提交
215
      if (!glyphset.has (iter.get_glyph ())) continue;
216 217
      from.push ()->set (glyph_map[iter.get_glyph ()]);
      to.push ()->set (glyph_map[substitute[iter.get_coverage ()]]);
218
    }
219
    c->serializer->propagate_error (from, to);
B
Behdad Esfahbod 已提交
220
    SingleSubst_serialize (c->serializer, from, to);
221
    return_trace (from.len);
222 223
  }

224
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
225
  {
B
Behdad Esfahbod 已提交
226
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
227
    return_trace (coverage.sanitize (c, this) && substitute.sanitize (c));
B
Behdad Esfahbod 已提交
228 229
  }

230
  protected:
B
Behdad Esfahbod 已提交
231
  HBUINT16	format;			/* Format identifier--format = 2 */
B
Behdad Esfahbod 已提交
232 233
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
234
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
235 236 237
  ArrayOf<GlyphID>
		substitute;		/* Array of substitute
					 * GlyphIDs--ordered by Coverage Index */
238
  public:
239
  DEFINE_SIZE_ARRAY (6, substitute);
B
Behdad Esfahbod 已提交
240 241
};

B
Behdad Esfahbod 已提交
242 243
struct SingleSubst
{
244
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
245 246
		  hb_array_t<const GlyphID> glyphs,
		  hb_array_t<const GlyphID> substitutes)
B
Behdad Esfahbod 已提交
247
  {
B
Behdad Esfahbod 已提交
248
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
249
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
B
Behdad Esfahbod 已提交
250
    unsigned int format = 2;
B
Behdad Esfahbod 已提交
251
    int delta = 0;
B
Behdad Esfahbod 已提交
252 253
    if (glyphs.len)
    {
B
Behdad Esfahbod 已提交
254
      format = 1;
B
Minor  
Behdad Esfahbod 已提交
255
      /* TODO(serialize) check for wrap-around */
B
Behdad Esfahbod 已提交
256
      delta = substitutes[0] - glyphs[0];
B
Behdad Esfahbod 已提交
257
      for (unsigned int i = 1; i < glyphs.len; i++)
B
Minor  
Behdad Esfahbod 已提交
258
	if (delta != (int) (substitutes[i] - glyphs[i])) {
B
Behdad Esfahbod 已提交
259 260 261 262 263 264
	  format = 2;
	  break;
	}
    }
    u.format.set (format);
    switch (u.format) {
B
Behdad Esfahbod 已提交
265 266
    case 1: return_trace (u.format1.serialize (c, glyphs, delta));
    case 2: return_trace (u.format2.serialize (c, glyphs, substitutes));
B
Behdad Esfahbod 已提交
267
    default:return_trace (false);
B
Behdad Esfahbod 已提交
268 269 270
    }
  }

B
Behdad Esfahbod 已提交
271
  template <typename context_t>
272
  typename context_t::return_t dispatch (context_t *c) const
B
Behdad Esfahbod 已提交
273
  {
274
    TRACE_DISPATCH (this, u.format);
275
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
276
    switch (u.format) {
B
Behdad Esfahbod 已提交
277 278 279
    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 已提交
280 281 282
    }
  }

283
  protected:
284
  union {
B
Behdad Esfahbod 已提交
285
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
286 287
  SingleSubstFormat1	format1;
  SingleSubstFormat2	format2;
288
  } u;
B
Behdad Esfahbod 已提交
289
};
290

291 292
static inline void
SingleSubst_serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
293 294 295
		       hb_array_t<const GlyphID> glyphs,
		       hb_array_t<const GlyphID> substitutes)
{ c->start_embed<SingleSubst> ()->serialize (c, glyphs, substitutes); }
B
Behdad Esfahbod 已提交
296

B
Behdad Esfahbod 已提交
297 298
struct Sequence
{
299
  void closure (hb_closure_context_t *c) const
300
  {
B
Behdad Esfahbod 已提交
301
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
302 303
    unsigned int count = substitute.len;
    for (unsigned int i = 0; i < count; i++)
304
      c->out->add (substitute[i]);
305 306
  }

307
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
308
  {
B
Behdad Esfahbod 已提交
309
    TRACE_COLLECT_GLYPHS (this);
310
    c->output->add_array (substitute.arrayZ, substitute.len);
311 312
  }

313
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
314
  {
B
Behdad Esfahbod 已提交
315
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
316
    unsigned int count = substitute.len;
317

B
Behdad Esfahbod 已提交
318 319 320
    /* Special-case to make it in-place and not consider this
     * as a "multiplied" substitution. */
    if (unlikely (count == 1))
321
    {
322
      c->replace_glyph (substitute.arrayZ[0]);
B
Behdad Esfahbod 已提交
323
      return_trace (true);
324
    }
325
    /* Spec disallows this, but Uniscribe allows it.
326
     * https://github.com/harfbuzz/harfbuzz/issues/253 */
327 328 329 330 331
    else if (unlikely (count == 0))
    {
      c->buffer->delete_glyph ();
      return_trace (true);
    }
B
Behdad Esfahbod 已提交
332 333 334 335 336 337

    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);
338
      c->output_glyph_for_component (substitute.arrayZ[i], klass);
339
    }
B
Behdad Esfahbod 已提交
340
    c->buffer->skip_glyph ();
B
Behdad Esfahbod 已提交
341

B
Behdad Esfahbod 已提交
342
    return_trace (true);
B
Behdad Esfahbod 已提交
343 344
  }

345
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
346
		  hb_array_t<const GlyphID> glyphs)
347
  {
B
Behdad Esfahbod 已提交
348
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
349
    return_trace (substitute.serialize (c, glyphs));
350 351
  }

352
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
353
  {
B
Behdad Esfahbod 已提交
354
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
355
    return_trace (substitute.sanitize (c));
B
Behdad Esfahbod 已提交
356 357
  }

358
  protected:
B
Behdad Esfahbod 已提交
359 360
  ArrayOf<GlyphID>
		substitute;		/* String of GlyphIDs to substitute */
361
  public:
362
  DEFINE_SIZE_ARRAY (2, substitute);
B
Behdad Esfahbod 已提交
363 364
};

B
Behdad Esfahbod 已提交
365 366
struct MultipleSubstFormat1
{
367
  bool intersects (const hb_set_t *glyphs) const
368 369
  { return (this+coverage).intersects (glyphs); }

370
  void closure (hb_closure_context_t *c) const
371
  {
B
Behdad Esfahbod 已提交
372
    TRACE_CLOSURE (this);
373
    unsigned int count = sequence.len;
374
    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
375 376
    {
      if (unlikely (iter.get_coverage () >= count))
377
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
B
Behdad Esfahbod 已提交
378
      if (c->glyphs->has (iter.get_glyph ()))
B
Behdad Esfahbod 已提交
379
	(this+sequence[iter.get_coverage ()]).closure (c);
B
Behdad Esfahbod 已提交
380
    }
381 382
  }

383
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
384
  {
B
Behdad Esfahbod 已提交
385
    TRACE_COLLECT_GLYPHS (this);
386
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
387 388
    unsigned int count = sequence.len;
    for (unsigned int i = 0; i < count; i++)
389
      (this+sequence[i]).collect_glyphs (c);
390 391
  }

392
  const Coverage &get_coverage () const { return this+coverage; }
393

394
  bool would_apply (hb_would_apply_context_t *c) const
395
  {
B
Behdad Esfahbod 已提交
396
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
397
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
398 399
  }

400
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
401
  {
B
Behdad Esfahbod 已提交
402
    TRACE_APPLY (this);
403

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

B
Behdad Esfahbod 已提交
407
    return_trace ((this+sequence[index]).apply (c));
408
  }
B
Behdad Esfahbod 已提交
409

410
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
411 412 413
		  hb_array_t<const GlyphID> glyphs,
		  hb_array_t<const unsigned int> substitute_len_list,
		  hb_array_t<const GlyphID> substitute_glyphs_list)
414
  {
B
Behdad Esfahbod 已提交
415
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
416
    if (unlikely (!c->extend_min (*this))) return_trace (false);
B
Behdad Esfahbod 已提交
417 418 419 420 421 422 423 424 425 426
    if (unlikely (!sequence.serialize (c, glyphs.len))) return_trace (false);
    for (unsigned int i = 0; i < glyphs.len; i++)
    {
      unsigned int substitute_len = substitute_len_list[i];
      if (unlikely (!sequence[i].serialize (c, this)
				.serialize (c, substitute_glyphs_list.sub_array (0, substitute_len))))
	return_trace (false);
      substitute_glyphs_list += substitute_len;
    }
    return_trace (coverage.serialize (c, this).serialize (c, glyphs));
427 428
  }

429
  bool subset (hb_subset_context_t *c) const
430 431 432 433 434 435
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

436
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
437
  {
B
Behdad Esfahbod 已提交
438
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
439
    return_trace (coverage.sanitize (c, this) && sequence.sanitize (c, this));
B
Behdad Esfahbod 已提交
440 441
  }

442
  protected:
B
Behdad Esfahbod 已提交
443
  HBUINT16	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
444 445
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
446
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
447 448 449
  OffsetArrayOf<Sequence>
		sequence;		/* Array of Sequence tables
					 * ordered by Coverage Index */
450
  public:
451
  DEFINE_SIZE_ARRAY (6, sequence);
B
Behdad Esfahbod 已提交
452
};
453

B
Behdad Esfahbod 已提交
454 455
struct MultipleSubst
{
456
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
457 458 459
		  hb_array_t<const GlyphID> glyphs,
		  hb_array_t<const unsigned int> substitute_len_list,
		  hb_array_t<const GlyphID> substitute_glyphs_list)
460
  {
B
Behdad Esfahbod 已提交
461
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
462
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
463 464 465
    unsigned int format = 1;
    u.format.set (format);
    switch (u.format) {
B
Behdad Esfahbod 已提交
466
    case 1: return_trace (u.format1.serialize (c, glyphs, substitute_len_list, substitute_glyphs_list));
B
Behdad Esfahbod 已提交
467
    default:return_trace (false);
468 469 470
    }
  }

B
Behdad Esfahbod 已提交
471
  template <typename context_t>
472
  typename context_t::return_t dispatch (context_t *c) const
B
Behdad Esfahbod 已提交
473
  {
474
    TRACE_DISPATCH (this, u.format);
475
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
476
    switch (u.format) {
B
Behdad Esfahbod 已提交
477 478
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
479 480 481
    }
  }

482
  protected:
483
  union {
B
Behdad Esfahbod 已提交
484
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
485
  MultipleSubstFormat1	format1;
486 487 488
  } u;
};

489 490
struct AlternateSet
{
491
  void closure (hb_closure_context_t *c) const
492 493 494 495 496 497 498
  {
    TRACE_CLOSURE (this);
    unsigned int count = alternates.len;
    for (unsigned int i = 0; i < count; i++)
      c->out->add (alternates[i]);
  }

499
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
500 501 502 503 504
  {
    TRACE_COLLECT_GLYPHS (this);
    c->output->add_array (alternates.arrayZ, alternates.len);
  }

505
  bool apply (hb_ot_apply_context_t *c) const
506 507 508 509 510 511
  {
    TRACE_APPLY (this);
    unsigned int count = alternates.len;

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

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

515 516 517
    /* 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);
518

519 520
    /* If alt_index is MAX, randomize feature if it is the rand feature. */
    if (alt_index == HB_OT_MAP_MAX_VALUE && c->random)
B
Behdad Esfahbod 已提交
521
      alt_index = c->random_number () % count + 1;
B
Behdad Esfahbod 已提交
522

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

525 526
    c->replace_glyph (alternates[alt_index - 1]);

527 528 529
    return_trace (true);
  }

530
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
531
		  hb_array_t<const GlyphID> glyphs)
532 533
  {
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
534
    return_trace (alternates.serialize (c, glyphs));
535 536
  }

537
  bool sanitize (hb_sanitize_context_t *c) const
538 539 540 541 542 543 544 545
  {
    TRACE_SANITIZE (this);
    return_trace (alternates.sanitize (c));
  }

  protected:
  ArrayOf<GlyphID>
		alternates;		/* Array of alternate GlyphIDs--in
B
Behdad Esfahbod 已提交
546
					 * arbitrary order */
547 548 549
  public:
  DEFINE_SIZE_ARRAY (2, alternates);
};
B
Behdad Esfahbod 已提交
550

B
Behdad Esfahbod 已提交
551 552
struct AlternateSubstFormat1
{
553
  bool intersects (const hb_set_t *glyphs) const
554 555
  { return (this+coverage).intersects (glyphs); }

556
  void closure (hb_closure_context_t *c) const
557
  {
B
Behdad Esfahbod 已提交
558
    TRACE_CLOSURE (this);
559
    unsigned int count = alternateSet.len;
560
    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
561 562
    {
      if (unlikely (iter.get_coverage () >= count))
E
Ebrahim Byagowi 已提交
563
	break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
564 565
      if (c->glyphs->has (iter.get_glyph ()))
	(this+alternateSet[iter.get_coverage ()]).closure (c);
B
Behdad Esfahbod 已提交
566
    }
567 568
  }

569
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
570
  {
B
Behdad Esfahbod 已提交
571
    TRACE_COLLECT_GLYPHS (this);
572
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
573
    unsigned int count = alternateSet.len;
574
    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
575 576
    {
      if (unlikely (iter.get_coverage () >= count))
E
Ebrahim Byagowi 已提交
577
	break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
578
      (this+alternateSet[iter.get_coverage ()]).collect_glyphs (c);
579 580 581
    }
  }

582
  const Coverage &get_coverage () const { return this+coverage; }
583

584
  bool would_apply (hb_would_apply_context_t *c) const
585
  {
B
Behdad Esfahbod 已提交
586
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
587
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
588 589
  }

590
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
591
  {
B
Behdad Esfahbod 已提交
592
    TRACE_APPLY (this);
593

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

597
    return_trace ((this+alternateSet[index]).apply (c));
598
  }
B
Behdad Esfahbod 已提交
599

600
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
601 602 603
		  hb_array_t<const GlyphID> glyphs,
		  hb_array_t<const unsigned int> alternate_len_list,
		  hb_array_t<const GlyphID> alternate_glyphs_list)
604
  {
B
Behdad Esfahbod 已提交
605
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
606
    if (unlikely (!c->extend_min (*this))) return_trace (false);
B
Behdad Esfahbod 已提交
607 608 609 610 611 612 613 614 615 616
    if (unlikely (!alternateSet.serialize (c, glyphs.len))) return_trace (false);
    for (unsigned int i = 0; i < glyphs.len; i++)
    {
      unsigned int alternate_len = alternate_len_list[i];
      if (unlikely (!alternateSet[i].serialize (c, this)
				    .serialize (c, alternate_glyphs_list.sub_array (0, alternate_len))))
	return_trace (false);
      alternate_glyphs_list += alternate_len;
    }
    return_trace (coverage.serialize (c, this).serialize (c, glyphs));
617 618
  }

619
  bool subset (hb_subset_context_t *c) const
620 621 622 623 624 625
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

626
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
627
  {
B
Behdad Esfahbod 已提交
628
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
629
    return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
630 631
  }

632
  protected:
B
Behdad Esfahbod 已提交
633
  HBUINT16	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
634 635
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
636
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
637 638 639
  OffsetArrayOf<AlternateSet>
		alternateSet;		/* Array of AlternateSet tables
					 * ordered by Coverage Index */
640
  public:
641
  DEFINE_SIZE_ARRAY (6, alternateSet);
B
Behdad Esfahbod 已提交
642
};
643

B
Behdad Esfahbod 已提交
644 645
struct AlternateSubst
{
646
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
647 648 649
		  hb_array_t<const GlyphID> glyphs,
		  hb_array_t<const unsigned int> alternate_len_list,
		  hb_array_t<const GlyphID> alternate_glyphs_list)
650
  {
B
Behdad Esfahbod 已提交
651
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
652
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
653 654 655
    unsigned int format = 1;
    u.format.set (format);
    switch (u.format) {
B
Behdad Esfahbod 已提交
656
    case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, alternate_glyphs_list));
B
Behdad Esfahbod 已提交
657
    default:return_trace (false);
658 659 660
    }
  }

B
Behdad Esfahbod 已提交
661
  template <typename context_t>
662
  typename context_t::return_t dispatch (context_t *c) const
B
Behdad Esfahbod 已提交
663
  {
664
    TRACE_DISPATCH (this, u.format);
665
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
666
    switch (u.format) {
B
Behdad Esfahbod 已提交
667 668
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
669 670 671
    }
  }

672
  protected:
673
  union {
B
Behdad Esfahbod 已提交
674
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
675
  AlternateSubstFormat1	format1;
676 677 678
  } u;
};

679

B
Behdad Esfahbod 已提交
680 681
struct Ligature
{
682
  bool intersects (const hb_set_t *glyphs) const
683
  {
684
    unsigned int count = component.lenP1;
685 686 687 688 689 690
    for (unsigned int i = 1; i < count; i++)
      if (!glyphs->has (component[i]))
        return false;
    return true;
  }

691
  void closure (hb_closure_context_t *c) const
692
  {
B
Behdad Esfahbod 已提交
693
    TRACE_CLOSURE (this);
694
    unsigned int count = component.lenP1;
B
Behdad Esfahbod 已提交
695 696
    for (unsigned int i = 1; i < count; i++)
      if (!c->glyphs->has (component[i]))
B
Behdad Esfahbod 已提交
697
        return;
698
    c->out->add (ligGlyph);
699 700
  }

701
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
702
  {
B
Behdad Esfahbod 已提交
703
    TRACE_COLLECT_GLYPHS (this);
704
    c->input->add_array (component.arrayZ, component.lenP1 ? component.lenP1 - 1 : 0);
B
Minor  
Behdad Esfahbod 已提交
705
    c->output->add (ligGlyph);
706 707
  }

708
  bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
709
  {
B
Behdad Esfahbod 已提交
710
    TRACE_WOULD_APPLY (this);
711
    if (c->len != component.lenP1)
B
Behdad Esfahbod 已提交
712
      return_trace (false);
713 714 715

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

B
Behdad Esfahbod 已提交
718
    return_trace (true);
B
Behdad Esfahbod 已提交
719 720
  }

721
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
722
  {
B
Behdad Esfahbod 已提交
723
    TRACE_APPLY (this);
724
    unsigned int count = component.lenP1;
B
Behdad Esfahbod 已提交
725

B
Behdad Esfahbod 已提交
726
    if (unlikely (!count)) return_trace (false);
B
Behdad Esfahbod 已提交
727

728 729 730 731 732
    /* 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 已提交
733
      return_trace (true);
734 735
    }

B
Behdad Esfahbod 已提交
736
    unsigned int total_component_count = 0;
737

738
    unsigned int match_length = 0;
739
    unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
740

741 742 743
    if (likely (!match_input (c, count,
			      &component[1],
			      match_glyph,
B
Behdad Esfahbod 已提交
744
			      nullptr,
745 746
			      &match_length,
			      match_positions,
747
			      &total_component_count)))
B
Behdad Esfahbod 已提交
748
      return_trace (false);
749

750 751
    ligate_input (c,
		  count,
752 753
		  match_positions,
		  match_length,
754
		  ligGlyph,
755
		  total_component_count);
756

B
Behdad Esfahbod 已提交
757
    return_trace (true);
758
  }
759

760 761
  bool serialize (hb_serialize_context_t *c,
		  GlyphID ligature,
B
Behdad Esfahbod 已提交
762
		  hb_array_t<const GlyphID> components /* Starting from second */)
763
  {
B
Behdad Esfahbod 已提交
764
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
765
    if (unlikely (!c->extend_min (*this))) return_trace (false);
766
    ligGlyph = ligature;
B
Behdad Esfahbod 已提交
767
    if (unlikely (!component.serialize (c, components))) return_trace (false);
B
Behdad Esfahbod 已提交
768
    return_trace (true);
769 770
  }

B
Behdad Esfahbod 已提交
771
  public:
772
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
773
  {
B
Behdad Esfahbod 已提交
774
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
775
    return_trace (ligGlyph.sanitize (c) && component.sanitize (c));
B
Behdad Esfahbod 已提交
776 777
  }

778
  protected:
779
  GlyphID	ligGlyph;		/* GlyphID of ligature to substitute */
B
Behdad Esfahbod 已提交
780 781
  HeadlessArrayOf<GlyphID>
		component;		/* Array of component GlyphIDs--start
782 783
					 * with the second  component--ordered
					 * in writing direction */
784
  public:
785
  DEFINE_SIZE_ARRAY (4, component);
786
};
B
Behdad Esfahbod 已提交
787

B
Behdad Esfahbod 已提交
788 789
struct LigatureSet
{
790
  bool intersects (const hb_set_t *glyphs) const
791 792 793 794 795 796 797 798
  {
    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;
  }

799
  void closure (hb_closure_context_t *c) const
800
  {
B
Behdad Esfahbod 已提交
801
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
802 803
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
B
Behdad Esfahbod 已提交
804
      (this+ligature[i]).closure (c);
805 806
  }

807
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
808
  {
B
Behdad Esfahbod 已提交
809
    TRACE_COLLECT_GLYPHS (this);
810 811 812 813 814
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
      (this+ligature[i]).collect_glyphs (c);
  }

815
  bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
816
  {
B
Behdad Esfahbod 已提交
817
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
818 819 820 821
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
    {
      const Ligature &lig = this+ligature[i];
822
      if (lig.would_apply (c))
B
Behdad Esfahbod 已提交
823
        return_trace (true);
B
Behdad Esfahbod 已提交
824
    }
B
Behdad Esfahbod 已提交
825
    return_trace (false);
B
Behdad Esfahbod 已提交
826 827
  }

828
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
829
  {
B
Behdad Esfahbod 已提交
830
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
831
    unsigned int num_ligs = ligature.len;
B
Behdad Esfahbod 已提交
832 833
    for (unsigned int i = 0; i < num_ligs; i++)
    {
B
Behdad Esfahbod 已提交
834
      const Ligature &lig = this+ligature[i];
B
Behdad Esfahbod 已提交
835
      if (lig.apply (c)) return_trace (true);
836 837
    }

B
Behdad Esfahbod 已提交
838
    return_trace (false);
839
  }
B
Behdad Esfahbod 已提交
840

841
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
842 843 844
		  hb_array_t<const GlyphID> ligatures,
		  hb_array_t<const unsigned int> component_count_list,
		  hb_array_t<const GlyphID> component_list /* Starting from second for each ligature */)
845
  {
B
Behdad Esfahbod 已提交
846
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
847
    if (unlikely (!c->extend_min (*this))) return_trace (false);
B
Behdad Esfahbod 已提交
848 849 850 851 852 853 854 855 856 857 858
    if (unlikely (!ligature.serialize (c, ligatures.len))) return_trace (false);
    for (unsigned int i = 0; i < ligatures.len; i++)
    {
      unsigned int component_count = MAX<int> (component_count_list[i] - 1, 0);
      if (unlikely (!ligature[i].serialize (c, this)
				.serialize (c,
					    ligatures[i],
					    component_list.sub_array (0, component_count))))
	return_trace (false);
      component_list += component_count;
    }
B
Behdad Esfahbod 已提交
859
    return_trace (true);
860 861
  }

862
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
863
  {
B
Behdad Esfahbod 已提交
864
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
865
    return_trace (ligature.sanitize (c, this));
B
Behdad Esfahbod 已提交
866 867
  }

868
  protected:
B
Behdad Esfahbod 已提交
869 870 871
  OffsetArrayOf<Ligature>
		ligature;		/* Array LigatureSet tables
					 * ordered by preference */
872
  public:
873
  DEFINE_SIZE_ARRAY (2, ligature);
B
Behdad Esfahbod 已提交
874 875
};

B
Behdad Esfahbod 已提交
876 877
struct LigatureSubstFormat1
{
878
  bool intersects (const hb_set_t *glyphs) const
879 880
  {
    unsigned int count = ligatureSet.len;
881
    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
882 883 884 885 886 887 888 889 890 891
    {
      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;
  }

892
  void closure (hb_closure_context_t *c) const
893
  {
B
Behdad Esfahbod 已提交
894
    TRACE_CLOSURE (this);
895
    unsigned int count = ligatureSet.len;
896
    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
897 898
    {
      if (unlikely (iter.get_coverage () >= count))
899
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
B
Behdad Esfahbod 已提交
900
      if (c->glyphs->has (iter.get_glyph ()))
B
Behdad Esfahbod 已提交
901
	(this+ligatureSet[iter.get_coverage ()]).closure (c);
B
Behdad Esfahbod 已提交
902
    }
903 904
  }

905
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
906
  {
B
Behdad Esfahbod 已提交
907
    TRACE_COLLECT_GLYPHS (this);
908
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
909
    unsigned int count = ligatureSet.len;
910
    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
911 912
    {
      if (unlikely (iter.get_coverage () >= count))
913
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
914 915 916 917
      (this+ligatureSet[iter.get_coverage ()]).collect_glyphs (c);
    }
  }

918
  const Coverage &get_coverage () const { return this+coverage; }
919

920
  bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
921
  {
B
Behdad Esfahbod 已提交
922
    TRACE_WOULD_APPLY (this);
923
    unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
B
Behdad Esfahbod 已提交
924
    if (likely (index == NOT_COVERED)) return_trace (false);
925 926

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

930
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
931
  {
B
Behdad Esfahbod 已提交
932
    TRACE_APPLY (this);
933

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

B
Behdad Esfahbod 已提交
937
    const LigatureSet &lig_set = this+ligatureSet[index];
B
Behdad Esfahbod 已提交
938
    return_trace (lig_set.apply (c));
939
  }
B
Behdad Esfahbod 已提交
940

941
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
942 943 944 945 946
		  hb_array_t<const GlyphID> first_glyphs,
		  hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
		  hb_array_t<const GlyphID> ligatures_list,
		  hb_array_t<const unsigned int> component_count_list,
		  hb_array_t<const GlyphID> component_list /* Starting from second for each ligature */)
947
  {
B
Behdad Esfahbod 已提交
948
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
949
    if (unlikely (!c->extend_min (*this))) return_trace (false);
B
Behdad Esfahbod 已提交
950 951 952 953 954 955 956 957 958 959 960 961 962 963 964
    if (unlikely (!ligatureSet.serialize (c, first_glyphs.len))) return_trace (false);
    for (unsigned int i = 0; i < first_glyphs.len; i++)
    {
      unsigned int ligature_count = ligature_per_first_glyph_count_list[i];
      if (unlikely (!ligatureSet[i].serialize (c, this)
				   .serialize (c,
					       ligatures_list.sub_array (0, ligature_count),
					       component_count_list.sub_array (0, ligature_count),
					       component_list))) return_trace (false);
      ligatures_list += ligature_count;
      component_count_list += ligature_count;
      for (unsigned int i = 0; i < ligature_count; i++)
	component_list += MAX<int> (component_count_list[i] - 1, 0);
    }
    return_trace (coverage.serialize (c, this).serialize (c, first_glyphs));
965 966
  }

967
  bool subset (hb_subset_context_t *c) const
968 969 970 971 972 973
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

974
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
975
  {
B
Behdad Esfahbod 已提交
976
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
977
    return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
978 979
  }

980
  protected:
B
Behdad Esfahbod 已提交
981
  HBUINT16	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
982 983
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
984
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
985
  OffsetArrayOf<LigatureSet>
B
Behdad Esfahbod 已提交
986 987
		ligatureSet;		/* Array LigatureSet tables
					 * ordered by Coverage Index */
988
  public:
989
  DEFINE_SIZE_ARRAY (6, ligatureSet);
B
Behdad Esfahbod 已提交
990
};
991

B
Behdad Esfahbod 已提交
992 993
struct LigatureSubst
{
994
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
995 996 997 998 999
		  hb_array_t<const GlyphID> first_glyphs,
		  hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
		  hb_array_t<const GlyphID> ligatures_list,
		  hb_array_t<const unsigned int> component_count_list,
		  hb_array_t<const GlyphID> component_list /* Starting from second for each ligature */)
1000
  {
B
Behdad Esfahbod 已提交
1001
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1002
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
1003 1004 1005
    unsigned int format = 1;
    u.format.set (format);
    switch (u.format) {
B
Behdad Esfahbod 已提交
1006 1007 1008 1009 1010 1011 1012
    case 1: return_trace (u.format1.serialize (c,
					       first_glyphs,
					       ligature_per_first_glyph_count_list,
					       ligatures_list,
					       component_count_list,
					       component_list));
    default:return_trace (false);
1013 1014 1015
    }
  }

B
Behdad Esfahbod 已提交
1016
  template <typename context_t>
1017
  typename context_t::return_t dispatch (context_t *c) const
B
Behdad Esfahbod 已提交
1018
  {
1019
    TRACE_DISPATCH (this, u.format);
1020
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
1021
    switch (u.format) {
B
Behdad Esfahbod 已提交
1022 1023
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
1024 1025 1026
    }
  }

1027
  protected:
1028
  union {
B
Behdad Esfahbod 已提交
1029
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1030
  LigatureSubstFormat1	format1;
1031 1032 1033
  } u;
};

B
Behdad Esfahbod 已提交
1034

B
Minor  
Behdad Esfahbod 已提交
1035
struct ContextSubst : Context {};
B
Behdad Esfahbod 已提交
1036

B
Minor  
Behdad Esfahbod 已提交
1037
struct ChainContextSubst : ChainContext {};
1038

B
Behdad Esfahbod 已提交
1039
struct ExtensionSubst : Extension<ExtensionSubst>
B
Behdad Esfahbod 已提交
1040
{
B
Behdad Esfahbod 已提交
1041
  typedef struct SubstLookupSubTable SubTable;
B
Behdad Esfahbod 已提交
1042

1043
  bool is_reverse () const;
1044 1045 1046
};


B
Behdad Esfahbod 已提交
1047 1048
struct ReverseChainSingleSubstFormat1
{
1049
  bool intersects (const hb_set_t *glyphs) const
1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070
  {
    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;
  }

1071
  void closure (hb_closure_context_t *c) const
1072
  {
B
Behdad Esfahbod 已提交
1073
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
1074 1075 1076 1077 1078 1079 1080
    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 已提交
1081
        return;
B
Behdad Esfahbod 已提交
1082 1083 1084 1085

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

    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
1089
    count = substitute.len;
1090
    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
1091 1092
    {
      if (unlikely (iter.get_coverage () >= count))
1093
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
B
Behdad Esfahbod 已提交
1094
      if (c->glyphs->has (iter.get_glyph ()))
1095
	c->out->add (substitute[iter.get_coverage ()]);
B
Behdad Esfahbod 已提交
1096
    }
1097 1098
  }

1099
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
1100
  {
B
Behdad Esfahbod 已提交
1101
    TRACE_COLLECT_GLYPHS (this);
1102
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
1103 1104 1105 1106 1107

    unsigned int count;

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

1110
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1111 1112
    count = lookahead.len;
    for (unsigned int i = 0; i < count; i++)
1113
      if (unlikely (!(this+lookahead[i]).add_coverage (c->after))) return;
1114 1115 1116

    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
    count = substitute.len;
1117
    c->output->add_array (substitute.arrayZ, substitute.len);
1118 1119
  }

1120
  const Coverage &get_coverage () const { return this+coverage; }
1121

1122
  bool would_apply (hb_would_apply_context_t *c) const
1123
  {
B
Behdad Esfahbod 已提交
1124
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
1125
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
1126 1127
  }

1128
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1129
  {
B
Behdad Esfahbod 已提交
1130
    TRACE_APPLY (this);
1131
    if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
B
Behdad Esfahbod 已提交
1132
      return_trace (false); /* No chaining to this type */
1133

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

1137 1138
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
1139

1140
  unsigned int start_index = 0, end_index = 0;
B
Behdad Esfahbod 已提交
1141
    if (match_backtrack (c,
1142
			 backtrack.len, (HBUINT16 *) backtrack.arrayZ,
1143 1144
			 match_coverage, this,
			 &start_index) &&
B
Behdad Esfahbod 已提交
1145
        match_lookahead (c,
1146
			 lookahead.len, (HBUINT16 *) lookahead.arrayZ,
B
Behdad Esfahbod 已提交
1147
			 match_coverage, this,
1148
			 1, &end_index))
1149
    {
1150
      c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index);
B
Behdad Esfahbod 已提交
1151
      c->replace_glyph_inplace (substitute[index]);
1152 1153 1154
      /* 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 已提交
1155
      return_trace (true);
1156 1157
    }

B
Behdad Esfahbod 已提交
1158
    return_trace (false);
1159
  }
B
Behdad Esfahbod 已提交
1160

1161
  bool subset (hb_subset_context_t *c) const
1162 1163 1164 1165 1166 1167
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

1168
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
1169
  {
B
Behdad Esfahbod 已提交
1170
    TRACE_SANITIZE (this);
1171
    if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
B
Behdad Esfahbod 已提交
1172
      return_trace (false);
B
Behdad Esfahbod 已提交
1173
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
B
Behdad Esfahbod 已提交
1174
    if (!lookahead.sanitize (c, this))
B
Behdad Esfahbod 已提交
1175
      return_trace (false);
B
Behdad Esfahbod 已提交
1176
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
B
Behdad Esfahbod 已提交
1177
    return_trace (substitute.sanitize (c));
B
Behdad Esfahbod 已提交
1178 1179
  }

1180
  protected:
B
Behdad Esfahbod 已提交
1181
  HBUINT16	format;			/* Format identifier--format = 1 */
1182 1183 1184 1185 1186
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of table */
  OffsetArrayOf<Coverage>
		backtrack;		/* Array of coverage tables
1187
					 * in backtracking sequence, in glyph
B
Behdad Esfahbod 已提交
1188
					 * sequence order */
1189 1190 1191
  OffsetArrayOf<Coverage>
		lookaheadX;		/* Array of coverage tables
					 * in lookahead sequence, in glyph
B
Behdad Esfahbod 已提交
1192
					 * sequence order */
1193 1194 1195
  ArrayOf<GlyphID>
		substituteX;		/* Array of substitute
					 * GlyphIDs--ordered by Coverage Index */
1196
  public:
B
Behdad Esfahbod 已提交
1197
  DEFINE_SIZE_MIN (10);
B
Behdad Esfahbod 已提交
1198 1199
};

B
Behdad Esfahbod 已提交
1200 1201
struct ReverseChainSingleSubst
{
1202
  template <typename context_t>
1203
  typename context_t::return_t dispatch (context_t *c) const
1204
  {
1205
    TRACE_DISPATCH (this, u.format);
1206
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1207
    switch (u.format) {
B
Behdad Esfahbod 已提交
1208 1209
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
1210 1211 1212
    }
  }

1213
  protected:
1214
  union {
B
Behdad Esfahbod 已提交
1215
  HBUINT16				format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1216
  ReverseChainSingleSubstFormat1	format1;
1217 1218 1219 1220 1221
  } u;
};



B
Behdad Esfahbod 已提交
1222 1223 1224 1225
/*
 * SubstLookup
 */

B
Behdad Esfahbod 已提交
1226 1227
struct SubstLookupSubTable
{
B
Behdad Esfahbod 已提交
1228
  friend struct Lookup;
B
Behdad Esfahbod 已提交
1229 1230
  friend struct SubstLookup;

B
Behdad Esfahbod 已提交
1231
  enum Type {
1232 1233 1234 1235 1236 1237 1238
    Single		= 1,
    Multiple		= 2,
    Alternate		= 3,
    Ligature		= 4,
    Context		= 5,
    ChainContext	= 6,
    Extension		= 7,
1239
    ReverseChainSingle	= 8
1240 1241
  };

1242
  template <typename context_t>
1243
  typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
1244
  {
1245
    TRACE_DISPATCH (this, lookup_type);
1246
    switch (lookup_type) {
B
Behdad Esfahbod 已提交
1247 1248 1249 1250 1251 1252 1253 1254 1255
    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 ());
1256 1257 1258
    }
  }

1259
  protected:
B
Behdad Esfahbod 已提交
1260
  union {
B
Behdad Esfahbod 已提交
1261 1262 1263 1264
  SingleSubst			single;
  MultipleSubst			multiple;
  AlternateSubst		alternate;
  LigatureSubst			ligature;
1265
  ContextSubst			context;
B
Behdad Esfahbod 已提交
1266 1267 1268
  ChainContextSubst		chainContext;
  ExtensionSubst		extension;
  ReverseChainSingleSubst	reverseChainContextSingle;
B
Behdad Esfahbod 已提交
1269
  } u;
B
Behdad Esfahbod 已提交
1270
  public:
B
Behdad Esfahbod 已提交
1271
  DEFINE_SIZE_MIN (0);
B
Behdad Esfahbod 已提交
1272 1273
};

1274

B
Behdad Esfahbod 已提交
1275 1276
struct SubstLookup : Lookup
{
B
Behdad Esfahbod 已提交
1277 1278
  typedef SubstLookupSubTable SubTable;

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

1282
  static bool lookup_type_is_reverse (unsigned int lookup_type)
B
Behdad Esfahbod 已提交
1283
  { return lookup_type == SubTable::ReverseChainSingle; }
B
Behdad Esfahbod 已提交
1284

1285
  bool is_reverse () const
B
Behdad Esfahbod 已提交
1286
  {
B
Behdad Esfahbod 已提交
1287
    unsigned int type = get_type ();
B
Behdad Esfahbod 已提交
1288
    if (unlikely (type == SubTable::Extension))
1289
      return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
B
Behdad Esfahbod 已提交
1290
    return lookup_type_is_reverse (type);
B
Behdad Esfahbod 已提交
1291
  }
1292

1293
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1294 1295
  {
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
1296
    return_trace (dispatch (c));
B
Behdad Esfahbod 已提交
1297 1298
  }

1299
  bool intersects (const hb_set_t *glyphs) const
1300 1301 1302 1303 1304
  {
    hb_intersects_context_t c (glyphs);
    return dispatch (&c);
  }

1305
  hb_closure_context_t::return_t closure (hb_closure_context_t *c, unsigned int this_index) const
1306
  {
B
Behdad Esfahbod 已提交
1307
    TRACE_CLOSURE (this);
1308
    if (!c->should_visit_lookup (this_index))
1309 1310 1311
      return_trace (HB_VOID);

    c->set_recurse_func (dispatch_closure_recurse_func);
1312 1313 1314 1315 1316 1317

    hb_closure_context_t::return_t ret = dispatch (c);

    c->flush ();

    return_trace (ret);
B
Behdad Esfahbod 已提交
1318 1319
  }

1320
  hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
B
Behdad Esfahbod 已提交
1321 1322
  {
    TRACE_COLLECT_GLYPHS (this);
1323
    c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
B
Behdad Esfahbod 已提交
1324
    return_trace (dispatch (c));
1325 1326
  }

B
Behdad Esfahbod 已提交
1327
  template <typename set_t>
1328
  void add_coverage (set_t *glyphs) const
B
Behdad Esfahbod 已提交
1329
  {
1330 1331
    hb_add_coverage_context_t<set_t> c (glyphs);
    dispatch (&c);
B
Behdad Esfahbod 已提交
1332 1333
  }

1334 1335
  bool would_apply (hb_would_apply_context_t *c,
		    const hb_ot_layout_lookup_accelerator_t *accel) const
B
Behdad Esfahbod 已提交
1336
  {
B
Behdad Esfahbod 已提交
1337
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
1338 1339 1340
    if (unlikely (!c->len))  return_trace (false);
    if (!accel->may_have (c->glyphs[0]))  return_trace (false);
      return_trace (dispatch (c));
B
Behdad Esfahbod 已提交
1341 1342
  }

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

1345
  SubTable& serialize_subtable (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
1346 1347
				       unsigned int i)
  { return get_subtables<SubTable> ()[i].serialize (c, this); }
1348

1349 1350
  bool serialize_single (hb_serialize_context_t *c,
			 uint32_t lookup_props,
B
Behdad Esfahbod 已提交
1351 1352
		         hb_array_t<const GlyphID> glyphs,
		         hb_array_t<const GlyphID> substitutes)
1353
  {
B
Behdad Esfahbod 已提交
1354
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1355
    if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1356
    return_trace (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes));
1357 1358
  }

1359 1360
  bool serialize_multiple (hb_serialize_context_t *c,
			   uint32_t lookup_props,
B
Behdad Esfahbod 已提交
1361 1362 1363
			   hb_array_t<const GlyphID> glyphs,
			   hb_array_t<const unsigned int> substitute_len_list,
			   hb_array_t<const GlyphID> substitute_glyphs_list)
1364
  {
B
Behdad Esfahbod 已提交
1365
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1366
    if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1367 1368 1369 1370
    return_trace (serialize_subtable (c, 0).u.multiple.serialize (c,
								  glyphs,
								  substitute_len_list,
								  substitute_glyphs_list));
1371 1372
  }

1373 1374
  bool serialize_alternate (hb_serialize_context_t *c,
			    uint32_t lookup_props,
B
Behdad Esfahbod 已提交
1375 1376 1377
			    hb_array_t<const GlyphID> glyphs,
			    hb_array_t<const unsigned int> alternate_len_list,
			    hb_array_t<const GlyphID> alternate_glyphs_list)
1378
  {
B
Behdad Esfahbod 已提交
1379
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1380
    if (unlikely (!Lookup::serialize (c, SubTable::Alternate, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1381 1382 1383 1384
    return_trace (serialize_subtable (c, 0).u.alternate.serialize (c,
								   glyphs,
								   alternate_len_list,
								   alternate_glyphs_list));
1385 1386
  }

1387 1388
  bool serialize_ligature (hb_serialize_context_t *c,
			   uint32_t lookup_props,
B
Behdad Esfahbod 已提交
1389 1390 1391 1392 1393
			   hb_array_t<const GlyphID> first_glyphs,
			   hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
			   hb_array_t<const GlyphID> ligatures_list,
			   hb_array_t<const unsigned int> component_count_list,
			   hb_array_t<const GlyphID> component_list /* Starting from second for each ligature */)
1394
  {
B
Behdad Esfahbod 已提交
1395
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1396
    if (unlikely (!Lookup::serialize (c, SubTable::Ligature, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1397 1398 1399 1400 1401 1402
    return_trace (serialize_subtable (c, 0).u.ligature.serialize (c,
								  first_glyphs,
								  ligature_per_first_glyph_count_list,
								  ligatures_list,
								  component_count_list,
								  component_list));
1403 1404
  }

B
Behdad Esfahbod 已提交
1405
  template <typename context_t>
1406
  static typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
B
Behdad Esfahbod 已提交
1407

1408
  static hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned int lookup_index)
1409
  {
1410
    if (!c->should_visit_lookup (lookup_index))
1411
      return HB_VOID;
1412 1413 1414

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

1415 1416 1417 1418
    /* While in theory we should flush here, it will cause timeouts because a recursive
     * lookup can keep growing the glyph set.  Skip, and outer loop will retry up to
     * HB_CLOSURE_MAX_STAGES time, which should be enough for every realistic font. */
    //c->flush ();
1419 1420

    return ret;
1421 1422
  }

B
Behdad Esfahbod 已提交
1423
  template <typename context_t>
1424
  typename context_t::return_t dispatch (context_t *c) const
B
Behdad Esfahbod 已提交
1425 1426
  { return Lookup::dispatch<SubTable> (c); }

1427
  bool subset (hb_subset_context_t *c) const
1428
  { return Lookup::subset<SubTable> (c); }
B
Behdad Esfahbod 已提交
1429

1430
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
1431
  { return Lookup::sanitize<SubTable> (c); }
B
Behdad Esfahbod 已提交
1432 1433
};

B
Minor  
Behdad Esfahbod 已提交
1434
/*
1435 1436
 * GSUB -- Glyph Substitution
 * https://docs.microsoft.com/en-us/typography/opentype/spec/gsub
B
Minor  
Behdad Esfahbod 已提交
1437 1438
 */

B
Behdad Esfahbod 已提交
1439 1440
struct GSUB : GSUBGPOS
{
1441
  enum { tableTag = HB_OT_TAG_GSUB };
B
Minor  
Behdad Esfahbod 已提交
1442

1443
  const SubstLookup& get_lookup (unsigned int i) const
1444
  { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); }
B
Behdad Esfahbod 已提交
1445

1446
  bool subset (hb_subset_context_t *c) const
1447
  { return GSUBGPOS::subset<SubstLookup> (c); }
1448

1449
  bool sanitize (hb_sanitize_context_t *c) const
1450
  { return GSUBGPOS::sanitize<SubstLookup> (c); }
B
WIP  
Behdad Esfahbod 已提交
1451

1452 1453 1454
  HB_INTERNAL bool is_blacklisted (hb_blob_t *blob,
				   hb_face_t *face) const;

B
WIP  
Behdad Esfahbod 已提交
1455
  typedef GSUBGPOS::accelerator_t<GSUB> accelerator_t;
B
Minor  
Behdad Esfahbod 已提交
1456
};
1457 1458


B
Behdad Esfahbod 已提交
1459 1460 1461
struct GSUB_accelerator_t : GSUB::accelerator_t {};


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

1464
/*static*/ inline bool ExtensionSubst::is_reverse () const
B
Behdad Esfahbod 已提交
1465 1466
{
  unsigned int type = get_type ();
B
Behdad Esfahbod 已提交
1467 1468
  if (unlikely (type == SubTable::Extension))
    return CastR<ExtensionSubst> (get_subtable<SubTable>()).is_reverse ();
B
Behdad Esfahbod 已提交
1469 1470 1471
  return SubstLookup::lookup_type_is_reverse (type);
}

1472
template <typename context_t>
1473
/*static*/ inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
1474
{
B
Behdad Esfahbod 已提交
1475
  const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index);
1476
  return l.dispatch (c);
1477 1478
}

1479
/*static*/ inline bool SubstLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index)
B
Behdad Esfahbod 已提交
1480
{
B
Behdad Esfahbod 已提交
1481
  const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index);
1482
  unsigned int saved_lookup_props = c->lookup_props;
1483 1484 1485
  unsigned int saved_lookup_index = c->lookup_index;
  c->set_lookup_index (lookup_index);
  c->set_lookup_props (l.get_props ());
1486
  bool ret = l.dispatch (c);
1487
  c->set_lookup_index (saved_lookup_index);
1488
  c->set_lookup_props (saved_lookup_props);
1489
  return ret;
1490 1491
}

B
Behdad Esfahbod 已提交
1492
} /* namespace OT */
1493

B
Behdad Esfahbod 已提交
1494

1495
#endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */