hb-ot-layout-gsub-table.hh 44.3 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
  {
49
    for (/*TODO(C++11)auto*/Coverage::iter_t iter = (this+coverage).iter (); iter; iter++)
50 51
    {
      /* TODO Switch to range-based API to work around malicious fonts.
52
       * https://github.com/harfbuzz/harfbuzz/issues/363 */
B
Behdad Esfahbod 已提交
53 54
      hb_codepoint_t glyph_id = iter.get_glyph ();
      if (c->glyphs->has (glyph_id))
55
	c->out->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
B
Behdad Esfahbod 已提交
56
    }
57 58
  }

59
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
60
  {
61
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
62
    for (/*TODO(C++11)auto*/Coverage::iter_t iter = (this+coverage).iter (); iter; iter++)
63 64
    {
      /* TODO Switch to range-based API to work around malicious fonts.
65
       * https://github.com/harfbuzz/harfbuzz/issues/363 */
66
      hb_codepoint_t glyph_id = iter.get_glyph ();
67
      c->output->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
68 69 70
    }
  }

71
  const Coverage &get_coverage () const { return this+coverage; }
72

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

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

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

B
Behdad Esfahbod 已提交
91
    return_trace (true);
92
  }
B
Behdad Esfahbod 已提交
93

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

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

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

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

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

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

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

170
  const Coverage &get_coverage () const { return this+coverage; }
171

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

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

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

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

B
Behdad Esfahbod 已提交
188
    return_trace (true);
189
  }
B
Behdad Esfahbod 已提交
190

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

202
  bool subset (hb_subset_context_t *c) const
203 204
  {
    TRACE_SUBSET (this);
B
Behdad Esfahbod 已提交
205
    const hb_set_t &glyphset = *c->plan->glyphset;
206
    const hb_map_t &glyph_map = *c->plan->glyph_map;
207 208
    hb_vector_t<GlyphID> from;
    hb_vector_t<GlyphID> to;
209
    for (/*TODO(C++11)auto*/Coverage::iter_t iter = (this+coverage).iter (); iter; iter++)
210
    {
B
Behdad Esfahbod 已提交
211
      if (!glyphset.has (iter.get_glyph ())) continue;
212 213
      from.push ()->set (glyph_map[iter.get_glyph ()]);
      to.push ()->set (glyph_map[substitute[iter.get_coverage ()]]);
214
    }
215
    c->serializer->propagate_error (from, to);
B
Behdad Esfahbod 已提交
216
    SingleSubst_serialize (c->serializer, from, to);
217
    return_trace (from.length);
218 219
  }

220
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
221
  {
B
Behdad Esfahbod 已提交
222
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
223
    return_trace (coverage.sanitize (c, this) && substitute.sanitize (c));
B
Behdad Esfahbod 已提交
224 225
  }

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

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

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

279
  protected:
280
  union {
B
Behdad Esfahbod 已提交
281
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
282 283
  SingleSubstFormat1	format1;
  SingleSubstFormat2	format2;
284
  } u;
B
Behdad Esfahbod 已提交
285
};
286

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

B
Behdad Esfahbod 已提交
293 294
struct Sequence
{
295
  void closure (hb_closure_context_t *c) const
296
  {
B
Behdad Esfahbod 已提交
297 298
    unsigned int count = substitute.len;
    for (unsigned int i = 0; i < count; i++)
299
      c->out->add (substitute[i]);
300 301
  }

302
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
B
Behdad Esfahbod 已提交
303
  { c->output->add_array (substitute.arrayZ, substitute.len); }
304

305
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
306
  {
B
Behdad Esfahbod 已提交
307
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
308
    unsigned int count = substitute.len;
309

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

    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);
330
      c->output_glyph_for_component (substitute.arrayZ[i], klass);
331
    }
B
Behdad Esfahbod 已提交
332
    c->buffer->skip_glyph ();
B
Behdad Esfahbod 已提交
333

B
Behdad Esfahbod 已提交
334
    return_trace (true);
B
Behdad Esfahbod 已提交
335 336
  }

337
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
338
		  hb_array_t<const GlyphID> glyphs)
339
  {
B
Behdad Esfahbod 已提交
340
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
341
    return_trace (substitute.serialize (c, glyphs));
342 343
  }

344
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
345
  {
B
Behdad Esfahbod 已提交
346
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
347
    return_trace (substitute.sanitize (c));
B
Behdad Esfahbod 已提交
348 349
  }

350
  protected:
B
Behdad Esfahbod 已提交
351 352
  ArrayOf<GlyphID>
		substitute;		/* String of GlyphIDs to substitute */
353
  public:
354
  DEFINE_SIZE_ARRAY (2, substitute);
B
Behdad Esfahbod 已提交
355 356
};

B
Behdad Esfahbod 已提交
357 358
struct MultipleSubstFormat1
{
359
  bool intersects (const hb_set_t *glyphs) const
360 361
  { return (this+coverage).intersects (glyphs); }

362
  void closure (hb_closure_context_t *c) const
363
  {
364
    unsigned int count = sequence.len;
365
    for (/*TODO(C++11)auto*/Coverage::iter_t iter = (this+coverage).iter (); iter; iter++)
366 367
    {
      if (unlikely (iter.get_coverage () >= count))
368
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
B
Behdad Esfahbod 已提交
369
      if (c->glyphs->has (iter.get_glyph ()))
B
Behdad Esfahbod 已提交
370
	(this+sequence[iter.get_coverage ()]).closure (c);
B
Behdad Esfahbod 已提交
371
    }
372 373
  }

374
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
375
  {
376
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
377 378
    unsigned int count = sequence.len;
    for (unsigned int i = 0; i < count; i++)
379
      (this+sequence[i]).collect_glyphs (c);
380 381
  }

382
  const Coverage &get_coverage () const { return this+coverage; }
383

384
  bool would_apply (hb_would_apply_context_t *c) const
385
  {
B
Behdad Esfahbod 已提交
386
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
387
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
388 389
  }

390
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
391
  {
B
Behdad Esfahbod 已提交
392
    TRACE_APPLY (this);
393

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

B
Behdad Esfahbod 已提交
397
    return_trace ((this+sequence[index]).apply (c));
398
  }
B
Behdad Esfahbod 已提交
399

400
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
401 402 403
		  hb_array_t<const GlyphID> glyphs,
		  hb_array_t<const unsigned int> substitute_len_list,
		  hb_array_t<const GlyphID> substitute_glyphs_list)
404
  {
B
Behdad Esfahbod 已提交
405
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
406
    if (unlikely (!c->extend_min (*this))) return_trace (false);
407 408
    if (unlikely (!sequence.serialize (c, glyphs.length))) return_trace (false);
    for (unsigned int i = 0; i < glyphs.length; i++)
B
Behdad Esfahbod 已提交
409 410 411 412 413 414 415 416
    {
      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));
417 418
  }

419
  bool subset (hb_subset_context_t *c) const
420 421 422 423 424 425
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

426
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
427
  {
B
Behdad Esfahbod 已提交
428
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
429
    return_trace (coverage.sanitize (c, this) && sequence.sanitize (c, this));
B
Behdad Esfahbod 已提交
430 431
  }

432
  protected:
B
Behdad Esfahbod 已提交
433
  HBUINT16	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
434 435
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
436
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
437 438 439
  OffsetArrayOf<Sequence>
		sequence;		/* Array of Sequence tables
					 * ordered by Coverage Index */
440
  public:
441
  DEFINE_SIZE_ARRAY (6, sequence);
B
Behdad Esfahbod 已提交
442
};
443

B
Behdad Esfahbod 已提交
444 445
struct MultipleSubst
{
446
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
447 448 449
		  hb_array_t<const GlyphID> glyphs,
		  hb_array_t<const unsigned int> substitute_len_list,
		  hb_array_t<const GlyphID> substitute_glyphs_list)
450
  {
B
Behdad Esfahbod 已提交
451
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
452
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
453 454 455
    unsigned int format = 1;
    u.format.set (format);
    switch (u.format) {
B
Behdad Esfahbod 已提交
456
    case 1: return_trace (u.format1.serialize (c, glyphs, substitute_len_list, substitute_glyphs_list));
B
Behdad Esfahbod 已提交
457
    default:return_trace (false);
458 459 460
    }
  }

B
Behdad Esfahbod 已提交
461
  template <typename context_t>
462
  typename context_t::return_t dispatch (context_t *c) const
B
Behdad Esfahbod 已提交
463
  {
464
    TRACE_DISPATCH (this, u.format);
465
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
466
    switch (u.format) {
B
Behdad Esfahbod 已提交
467 468
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
469 470 471
    }
  }

472
  protected:
473
  union {
B
Behdad Esfahbod 已提交
474
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
475
  MultipleSubstFormat1	format1;
476 477 478
  } u;
};

479 480
struct AlternateSet
{
481
  void closure (hb_closure_context_t *c) const
482 483 484 485 486 487
  {
    unsigned int count = alternates.len;
    for (unsigned int i = 0; i < count; i++)
      c->out->add (alternates[i]);
  }

488
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
B
Behdad Esfahbod 已提交
489
  { c->output->add_array (alternates.arrayZ, alternates.len); }
490

491
  bool apply (hb_ot_apply_context_t *c) const
492 493 494 495 496 497
  {
    TRACE_APPLY (this);
    unsigned int count = alternates.len;

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

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

501 502 503
    /* 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);
504

505 506
    /* 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 已提交
507
      alt_index = c->random_number () % count + 1;
B
Behdad Esfahbod 已提交
508

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

511 512
    c->replace_glyph (alternates[alt_index - 1]);

513 514 515
    return_trace (true);
  }

516
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
517
		  hb_array_t<const GlyphID> glyphs)
518 519
  {
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
520
    return_trace (alternates.serialize (c, glyphs));
521 522
  }

523
  bool sanitize (hb_sanitize_context_t *c) const
524 525 526 527 528 529 530 531
  {
    TRACE_SANITIZE (this);
    return_trace (alternates.sanitize (c));
  }

  protected:
  ArrayOf<GlyphID>
		alternates;		/* Array of alternate GlyphIDs--in
B
Behdad Esfahbod 已提交
532
					 * arbitrary order */
533 534 535
  public:
  DEFINE_SIZE_ARRAY (2, alternates);
};
B
Behdad Esfahbod 已提交
536

B
Behdad Esfahbod 已提交
537 538
struct AlternateSubstFormat1
{
539
  bool intersects (const hb_set_t *glyphs) const
540 541
  { return (this+coverage).intersects (glyphs); }

542
  void closure (hb_closure_context_t *c) const
543
  {
544
    unsigned int count = alternateSet.len;
545
    for (/*TODO(C++11)auto*/Coverage::iter_t iter = (this+coverage).iter (); iter; iter++)
546 547
    {
      if (unlikely (iter.get_coverage () >= count))
E
Ebrahim Byagowi 已提交
548
	break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
549 550
      if (c->glyphs->has (iter.get_glyph ()))
	(this+alternateSet[iter.get_coverage ()]).closure (c);
B
Behdad Esfahbod 已提交
551
    }
552 553
  }

554
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
555
  {
556
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
557
    unsigned int count = alternateSet.len;
558
    for (/*TODO(C++11)auto*/Coverage::iter_t iter = (this+coverage).iter (); iter; iter++)
559 560
    {
      if (unlikely (iter.get_coverage () >= count))
E
Ebrahim Byagowi 已提交
561
	break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
562
      (this+alternateSet[iter.get_coverage ()]).collect_glyphs (c);
563 564 565
    }
  }

566
  const Coverage &get_coverage () const { return this+coverage; }
567

568
  bool would_apply (hb_would_apply_context_t *c) const
569
  {
B
Behdad Esfahbod 已提交
570
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
571
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
572 573
  }

574
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
575
  {
B
Behdad Esfahbod 已提交
576
    TRACE_APPLY (this);
577

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

581
    return_trace ((this+alternateSet[index]).apply (c));
582
  }
B
Behdad Esfahbod 已提交
583

584
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
585 586 587
		  hb_array_t<const GlyphID> glyphs,
		  hb_array_t<const unsigned int> alternate_len_list,
		  hb_array_t<const GlyphID> alternate_glyphs_list)
588
  {
B
Behdad Esfahbod 已提交
589
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
590
    if (unlikely (!c->extend_min (*this))) return_trace (false);
591 592
    if (unlikely (!alternateSet.serialize (c, glyphs.length))) return_trace (false);
    for (unsigned int i = 0; i < glyphs.length; i++)
B
Behdad Esfahbod 已提交
593 594 595 596 597 598 599 600
    {
      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));
601 602
  }

603
  bool subset (hb_subset_context_t *c) const
604 605 606 607 608 609
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

610
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
611
  {
B
Behdad Esfahbod 已提交
612
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
613
    return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
614 615
  }

616
  protected:
B
Behdad Esfahbod 已提交
617
  HBUINT16	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
618 619
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
620
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
621 622 623
  OffsetArrayOf<AlternateSet>
		alternateSet;		/* Array of AlternateSet tables
					 * ordered by Coverage Index */
624
  public:
625
  DEFINE_SIZE_ARRAY (6, alternateSet);
B
Behdad Esfahbod 已提交
626
};
627

B
Behdad Esfahbod 已提交
628 629
struct AlternateSubst
{
630
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
631 632 633
		  hb_array_t<const GlyphID> glyphs,
		  hb_array_t<const unsigned int> alternate_len_list,
		  hb_array_t<const GlyphID> alternate_glyphs_list)
634
  {
B
Behdad Esfahbod 已提交
635
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
636
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
637 638 639
    unsigned int format = 1;
    u.format.set (format);
    switch (u.format) {
B
Behdad Esfahbod 已提交
640
    case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, alternate_glyphs_list));
B
Behdad Esfahbod 已提交
641
    default:return_trace (false);
642 643 644
    }
  }

B
Behdad Esfahbod 已提交
645
  template <typename context_t>
646
  typename context_t::return_t dispatch (context_t *c) const
B
Behdad Esfahbod 已提交
647
  {
648
    TRACE_DISPATCH (this, u.format);
649
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
650
    switch (u.format) {
B
Behdad Esfahbod 已提交
651 652
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
653 654 655
    }
  }

656
  protected:
657
  union {
B
Behdad Esfahbod 已提交
658
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
659
  AlternateSubstFormat1	format1;
660 661 662
  } u;
};

663

B
Behdad Esfahbod 已提交
664 665
struct Ligature
{
666
  bool intersects (const hb_set_t *glyphs) const
667
  {
668
    unsigned int count = component.lenP1;
669 670 671 672 673 674
    for (unsigned int i = 1; i < count; i++)
      if (!glyphs->has (component[i]))
        return false;
    return true;
  }

675
  void closure (hb_closure_context_t *c) const
676
  {
677
    unsigned int count = component.lenP1;
B
Behdad Esfahbod 已提交
678 679
    for (unsigned int i = 1; i < count; i++)
      if (!c->glyphs->has (component[i]))
B
Behdad Esfahbod 已提交
680
        return;
681
    c->out->add (ligGlyph);
682 683
  }

684
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
685
  {
686
    c->input->add_array (component.arrayZ, component.lenP1 ? component.lenP1 - 1 : 0);
B
Minor  
Behdad Esfahbod 已提交
687
    c->output->add (ligGlyph);
688 689
  }

690
  bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
691
  {
B
Behdad Esfahbod 已提交
692
    TRACE_WOULD_APPLY (this);
693
    if (c->len != component.lenP1)
B
Behdad Esfahbod 已提交
694
      return_trace (false);
695 696 697

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

B
Behdad Esfahbod 已提交
700
    return_trace (true);
B
Behdad Esfahbod 已提交
701 702
  }

703
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
704
  {
B
Behdad Esfahbod 已提交
705
    TRACE_APPLY (this);
706
    unsigned int count = component.lenP1;
B
Behdad Esfahbod 已提交
707

B
Behdad Esfahbod 已提交
708
    if (unlikely (!count)) return_trace (false);
B
Behdad Esfahbod 已提交
709

710 711 712 713 714
    /* 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 已提交
715
      return_trace (true);
716 717
    }

B
Behdad Esfahbod 已提交
718
    unsigned int total_component_count = 0;
719

720
    unsigned int match_length = 0;
721
    unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
722

723 724 725
    if (likely (!match_input (c, count,
			      &component[1],
			      match_glyph,
B
Behdad Esfahbod 已提交
726
			      nullptr,
727 728
			      &match_length,
			      match_positions,
729
			      &total_component_count)))
B
Behdad Esfahbod 已提交
730
      return_trace (false);
731

732 733
    ligate_input (c,
		  count,
734 735
		  match_positions,
		  match_length,
736
		  ligGlyph,
737
		  total_component_count);
738

B
Behdad Esfahbod 已提交
739
    return_trace (true);
740
  }
741

742 743
  bool serialize (hb_serialize_context_t *c,
		  GlyphID ligature,
B
Behdad Esfahbod 已提交
744
		  hb_array_t<const GlyphID> components /* Starting from second */)
745
  {
B
Behdad Esfahbod 已提交
746
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
747
    if (unlikely (!c->extend_min (*this))) return_trace (false);
748
    ligGlyph = ligature;
B
Behdad Esfahbod 已提交
749
    if (unlikely (!component.serialize (c, components))) return_trace (false);
B
Behdad Esfahbod 已提交
750
    return_trace (true);
751 752
  }

B
Behdad Esfahbod 已提交
753
  public:
754
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
755
  {
B
Behdad Esfahbod 已提交
756
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
757
    return_trace (ligGlyph.sanitize (c) && component.sanitize (c));
B
Behdad Esfahbod 已提交
758 759
  }

760
  protected:
761
  GlyphID	ligGlyph;		/* GlyphID of ligature to substitute */
B
Behdad Esfahbod 已提交
762 763
  HeadlessArrayOf<GlyphID>
		component;		/* Array of component GlyphIDs--start
764 765
					 * with the second  component--ordered
					 * in writing direction */
766
  public:
767
  DEFINE_SIZE_ARRAY (4, component);
768
};
B
Behdad Esfahbod 已提交
769

B
Behdad Esfahbod 已提交
770 771
struct LigatureSet
{
772
  bool intersects (const hb_set_t *glyphs) const
773 774 775 776 777 778 779 780
  {
    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;
  }

781
  void closure (hb_closure_context_t *c) const
782
  {
B
Behdad Esfahbod 已提交
783 784
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
B
Behdad Esfahbod 已提交
785
      (this+ligature[i]).closure (c);
786 787
  }

788
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
789 790 791 792 793 794
  {
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
      (this+ligature[i]).collect_glyphs (c);
  }

795
  bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
796
  {
B
Behdad Esfahbod 已提交
797
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
798 799 800 801
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
    {
      const Ligature &lig = this+ligature[i];
802
      if (lig.would_apply (c))
B
Behdad Esfahbod 已提交
803
        return_trace (true);
B
Behdad Esfahbod 已提交
804
    }
B
Behdad Esfahbod 已提交
805
    return_trace (false);
B
Behdad Esfahbod 已提交
806 807
  }

808
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
809
  {
B
Behdad Esfahbod 已提交
810
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
811
    unsigned int num_ligs = ligature.len;
B
Behdad Esfahbod 已提交
812 813
    for (unsigned int i = 0; i < num_ligs; i++)
    {
B
Behdad Esfahbod 已提交
814
      const Ligature &lig = this+ligature[i];
B
Behdad Esfahbod 已提交
815
      if (lig.apply (c)) return_trace (true);
816 817
    }

B
Behdad Esfahbod 已提交
818
    return_trace (false);
819
  }
B
Behdad Esfahbod 已提交
820

821
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
822 823
		  hb_array_t<const GlyphID> ligatures,
		  hb_array_t<const unsigned int> component_count_list,
824
		  hb_array_t<const GlyphID> &component_list /* Starting from second for each ligature */)
825
  {
B
Behdad Esfahbod 已提交
826
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
827
    if (unlikely (!c->extend_min (*this))) return_trace (false);
828 829
    if (unlikely (!ligature.serialize (c, ligatures.length))) return_trace (false);
    for (unsigned int i = 0; i < ligatures.length; i++)
B
Behdad Esfahbod 已提交
830 831 832 833 834 835 836 837 838
    {
      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 已提交
839
    return_trace (true);
840 841
  }

842
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
843
  {
B
Behdad Esfahbod 已提交
844
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
845
    return_trace (ligature.sanitize (c, this));
B
Behdad Esfahbod 已提交
846 847
  }

848
  protected:
B
Behdad Esfahbod 已提交
849 850 851
  OffsetArrayOf<Ligature>
		ligature;		/* Array LigatureSet tables
					 * ordered by preference */
852
  public:
853
  DEFINE_SIZE_ARRAY (2, ligature);
B
Behdad Esfahbod 已提交
854 855
};

B
Behdad Esfahbod 已提交
856 857
struct LigatureSubstFormat1
{
858
  bool intersects (const hb_set_t *glyphs) const
859 860
  {
    unsigned int count = ligatureSet.len;
861
    for (/*TODO(C++11)auto*/Coverage::iter_t iter = (this+coverage).iter (); iter; iter++)
862 863 864 865 866 867 868 869 870 871
    {
      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;
  }

872
  void closure (hb_closure_context_t *c) const
873
  {
874
    unsigned int count = ligatureSet.len;
875
    for (/*TODO(C++11)auto*/Coverage::iter_t iter = (this+coverage).iter (); iter; iter++)
876 877
    {
      if (unlikely (iter.get_coverage () >= count))
878
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
B
Behdad Esfahbod 已提交
879
      if (c->glyphs->has (iter.get_glyph ()))
B
Behdad Esfahbod 已提交
880
	(this+ligatureSet[iter.get_coverage ()]).closure (c);
B
Behdad Esfahbod 已提交
881
    }
882 883
  }

884
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
885
  {
886
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
887
    unsigned int count = ligatureSet.len;
888
    for (/*TODO(C++11)auto*/Coverage::iter_t iter = (this+coverage).iter (); iter; iter++)
889 890
    {
      if (unlikely (iter.get_coverage () >= count))
891
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
892 893 894 895
      (this+ligatureSet[iter.get_coverage ()]).collect_glyphs (c);
    }
  }

896
  const Coverage &get_coverage () const { return this+coverage; }
897

898
  bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
899
  {
B
Behdad Esfahbod 已提交
900
    TRACE_WOULD_APPLY (this);
901
    unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
B
Behdad Esfahbod 已提交
902
    if (likely (index == NOT_COVERED)) return_trace (false);
903 904

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

908
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
909
  {
B
Behdad Esfahbod 已提交
910
    TRACE_APPLY (this);
911

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

B
Behdad Esfahbod 已提交
915
    const LigatureSet &lig_set = this+ligatureSet[index];
B
Behdad Esfahbod 已提交
916
    return_trace (lig_set.apply (c));
917
  }
B
Behdad Esfahbod 已提交
918

919
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
920 921 922 923 924
		  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 */)
925
  {
B
Behdad Esfahbod 已提交
926
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
927
    if (unlikely (!c->extend_min (*this))) return_trace (false);
928 929
    if (unlikely (!ligatureSet.serialize (c, first_glyphs.length))) return_trace (false);
    for (unsigned int i = 0; i < first_glyphs.length; i++)
B
Behdad Esfahbod 已提交
930 931 932 933 934 935 936 937 938 939 940
    {
      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;
    }
    return_trace (coverage.serialize (c, this).serialize (c, first_glyphs));
941 942
  }

943
  bool subset (hb_subset_context_t *c) const
944 945 946 947 948 949
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

950
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
951
  {
B
Behdad Esfahbod 已提交
952
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
953
    return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
954 955
  }

956
  protected:
B
Behdad Esfahbod 已提交
957
  HBUINT16	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
958 959
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
960
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
961
  OffsetArrayOf<LigatureSet>
B
Behdad Esfahbod 已提交
962 963
		ligatureSet;		/* Array LigatureSet tables
					 * ordered by Coverage Index */
964
  public:
965
  DEFINE_SIZE_ARRAY (6, ligatureSet);
B
Behdad Esfahbod 已提交
966
};
967

B
Behdad Esfahbod 已提交
968 969
struct LigatureSubst
{
970
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
971 972 973 974 975
		  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 */)
976
  {
B
Behdad Esfahbod 已提交
977
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
978
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
979 980 981
    unsigned int format = 1;
    u.format.set (format);
    switch (u.format) {
B
Behdad Esfahbod 已提交
982 983 984 985 986 987 988
    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);
989 990 991
    }
  }

B
Behdad Esfahbod 已提交
992
  template <typename context_t>
993
  typename context_t::return_t dispatch (context_t *c) const
B
Behdad Esfahbod 已提交
994
  {
995
    TRACE_DISPATCH (this, u.format);
996
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
997
    switch (u.format) {
B
Behdad Esfahbod 已提交
998 999
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
1000 1001 1002
    }
  }

1003
  protected:
1004
  union {
B
Behdad Esfahbod 已提交
1005
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1006
  LigatureSubstFormat1	format1;
1007 1008 1009
  } u;
};

B
Behdad Esfahbod 已提交
1010

B
Minor  
Behdad Esfahbod 已提交
1011
struct ContextSubst : Context {};
B
Behdad Esfahbod 已提交
1012

B
Minor  
Behdad Esfahbod 已提交
1013
struct ChainContextSubst : ChainContext {};
1014

B
Behdad Esfahbod 已提交
1015
struct ExtensionSubst : Extension<ExtensionSubst>
B
Behdad Esfahbod 已提交
1016
{
B
Behdad Esfahbod 已提交
1017
  typedef struct SubstLookupSubTable SubTable;
B
Behdad Esfahbod 已提交
1018

1019
  bool is_reverse () const;
1020 1021 1022
};


B
Behdad Esfahbod 已提交
1023 1024
struct ReverseChainSingleSubstFormat1
{
1025
  bool intersects (const hb_set_t *glyphs) const
1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046
  {
    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;
  }

1047
  void closure (hb_closure_context_t *c) const
1048
  {
B
Behdad Esfahbod 已提交
1049 1050 1051 1052 1053 1054 1055
    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 已提交
1056
        return;
B
Behdad Esfahbod 已提交
1057 1058 1059 1060

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

    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
1064
    count = substitute.len;
1065
    for (/*TODO(C++11)auto*/Coverage::iter_t iter = (this+coverage).iter (); iter; iter++)
1066 1067
    {
      if (unlikely (iter.get_coverage () >= count))
1068
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
B
Behdad Esfahbod 已提交
1069
      if (c->glyphs->has (iter.get_glyph ()))
1070
	c->out->add (substitute[iter.get_coverage ()]);
B
Behdad Esfahbod 已提交
1071
    }
1072 1073
  }

1074
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
1075
  {
1076
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
1077 1078 1079 1080 1081

    unsigned int count;

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

1084
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1085 1086
    count = lookahead.len;
    for (unsigned int i = 0; i < count; i++)
1087
      if (unlikely (!(this+lookahead[i]).add_coverage (c->after))) return;
1088 1089 1090

    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
    count = substitute.len;
1091
    c->output->add_array (substitute.arrayZ, substitute.len);
1092 1093
  }

1094
  const Coverage &get_coverage () const { return this+coverage; }
1095

1096
  bool would_apply (hb_would_apply_context_t *c) const
1097
  {
B
Behdad Esfahbod 已提交
1098
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
1099
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
1100 1101
  }

1102
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1103
  {
B
Behdad Esfahbod 已提交
1104
    TRACE_APPLY (this);
1105
    if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
B
Behdad Esfahbod 已提交
1106
      return_trace (false); /* No chaining to this type */
1107

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

1111 1112
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
1113

1114
  unsigned int start_index = 0, end_index = 0;
B
Behdad Esfahbod 已提交
1115
    if (match_backtrack (c,
1116
			 backtrack.len, (HBUINT16 *) backtrack.arrayZ,
1117 1118
			 match_coverage, this,
			 &start_index) &&
B
Behdad Esfahbod 已提交
1119
        match_lookahead (c,
1120
			 lookahead.len, (HBUINT16 *) lookahead.arrayZ,
B
Behdad Esfahbod 已提交
1121
			 match_coverage, this,
1122
			 1, &end_index))
1123
    {
1124
      c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index);
B
Behdad Esfahbod 已提交
1125
      c->replace_glyph_inplace (substitute[index]);
1126 1127 1128
      /* 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 已提交
1129
      return_trace (true);
1130 1131
    }

B
Behdad Esfahbod 已提交
1132
    return_trace (false);
1133
  }
B
Behdad Esfahbod 已提交
1134

1135
  bool subset (hb_subset_context_t *c) const
1136 1137 1138 1139 1140 1141
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

1142
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
1143
  {
B
Behdad Esfahbod 已提交
1144
    TRACE_SANITIZE (this);
1145
    if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
B
Behdad Esfahbod 已提交
1146
      return_trace (false);
B
Behdad Esfahbod 已提交
1147
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
B
Behdad Esfahbod 已提交
1148
    if (!lookahead.sanitize (c, this))
B
Behdad Esfahbod 已提交
1149
      return_trace (false);
B
Behdad Esfahbod 已提交
1150
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
B
Behdad Esfahbod 已提交
1151
    return_trace (substitute.sanitize (c));
B
Behdad Esfahbod 已提交
1152 1153
  }

1154
  protected:
B
Behdad Esfahbod 已提交
1155
  HBUINT16	format;			/* Format identifier--format = 1 */
1156 1157 1158 1159 1160
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of table */
  OffsetArrayOf<Coverage>
		backtrack;		/* Array of coverage tables
1161
					 * in backtracking sequence, in glyph
B
Behdad Esfahbod 已提交
1162
					 * sequence order */
1163 1164 1165
  OffsetArrayOf<Coverage>
		lookaheadX;		/* Array of coverage tables
					 * in lookahead sequence, in glyph
B
Behdad Esfahbod 已提交
1166
					 * sequence order */
1167 1168 1169
  ArrayOf<GlyphID>
		substituteX;		/* Array of substitute
					 * GlyphIDs--ordered by Coverage Index */
1170
  public:
B
Behdad Esfahbod 已提交
1171
  DEFINE_SIZE_MIN (10);
B
Behdad Esfahbod 已提交
1172 1173
};

B
Behdad Esfahbod 已提交
1174 1175
struct ReverseChainSingleSubst
{
1176
  template <typename context_t>
1177
  typename context_t::return_t dispatch (context_t *c) const
1178
  {
1179
    TRACE_DISPATCH (this, u.format);
1180
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1181
    switch (u.format) {
B
Behdad Esfahbod 已提交
1182 1183
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
1184 1185 1186
    }
  }

1187
  protected:
1188
  union {
B
Behdad Esfahbod 已提交
1189
  HBUINT16				format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1190
  ReverseChainSingleSubstFormat1	format1;
1191 1192 1193 1194 1195
  } u;
};



B
Behdad Esfahbod 已提交
1196 1197 1198 1199
/*
 * SubstLookup
 */

B
Behdad Esfahbod 已提交
1200 1201
struct SubstLookupSubTable
{
B
Behdad Esfahbod 已提交
1202
  friend struct Lookup;
B
Behdad Esfahbod 已提交
1203 1204
  friend struct SubstLookup;

B
Behdad Esfahbod 已提交
1205
  enum Type {
1206 1207 1208 1209 1210 1211 1212
    Single		= 1,
    Multiple		= 2,
    Alternate		= 3,
    Ligature		= 4,
    Context		= 5,
    ChainContext	= 6,
    Extension		= 7,
1213
    ReverseChainSingle	= 8
1214 1215
  };

1216
  template <typename context_t>
1217
  typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
1218
  {
1219
    TRACE_DISPATCH (this, lookup_type);
1220
    switch (lookup_type) {
B
Behdad Esfahbod 已提交
1221 1222 1223 1224 1225 1226 1227 1228 1229
    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 ());
1230 1231 1232
    }
  }

1233
  protected:
B
Behdad Esfahbod 已提交
1234
  union {
B
Behdad Esfahbod 已提交
1235 1236 1237 1238
  SingleSubst			single;
  MultipleSubst			multiple;
  AlternateSubst		alternate;
  LigatureSubst			ligature;
1239
  ContextSubst			context;
B
Behdad Esfahbod 已提交
1240 1241 1242
  ChainContextSubst		chainContext;
  ExtensionSubst		extension;
  ReverseChainSingleSubst	reverseChainContextSingle;
B
Behdad Esfahbod 已提交
1243
  } u;
B
Behdad Esfahbod 已提交
1244
  public:
B
Behdad Esfahbod 已提交
1245
  DEFINE_SIZE_MIN (0);
B
Behdad Esfahbod 已提交
1246 1247
};

1248

B
Behdad Esfahbod 已提交
1249 1250
struct SubstLookup : Lookup
{
B
Behdad Esfahbod 已提交
1251 1252
  typedef SubstLookupSubTable SubTable;

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

1256
  static bool lookup_type_is_reverse (unsigned int lookup_type)
B
Behdad Esfahbod 已提交
1257
  { return lookup_type == SubTable::ReverseChainSingle; }
B
Behdad Esfahbod 已提交
1258

1259
  bool is_reverse () const
B
Behdad Esfahbod 已提交
1260
  {
B
Behdad Esfahbod 已提交
1261
    unsigned int type = get_type ();
B
Behdad Esfahbod 已提交
1262
    if (unlikely (type == SubTable::Extension))
1263
      return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
B
Behdad Esfahbod 已提交
1264
    return lookup_type_is_reverse (type);
B
Behdad Esfahbod 已提交
1265
  }
1266

1267
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1268 1269
  {
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
1270
    return_trace (dispatch (c));
B
Behdad Esfahbod 已提交
1271 1272
  }

1273
  bool intersects (const hb_set_t *glyphs) const
1274 1275 1276 1277 1278
  {
    hb_intersects_context_t c (glyphs);
    return dispatch (&c);
  }

1279
  hb_closure_context_t::return_t closure (hb_closure_context_t *c, unsigned int this_index) const
1280
  {
1281
    if (!c->should_visit_lookup (this_index))
B
Behdad Esfahbod 已提交
1282
      return hb_closure_context_t::default_return_value ();
1283 1284

    c->set_recurse_func (dispatch_closure_recurse_func);
1285 1286 1287 1288 1289

    hb_closure_context_t::return_t ret = dispatch (c);

    c->flush ();

B
Behdad Esfahbod 已提交
1290
    return ret;
B
Behdad Esfahbod 已提交
1291 1292
  }

1293
  hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
B
Behdad Esfahbod 已提交
1294
  {
1295
    c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
B
Behdad Esfahbod 已提交
1296
    return dispatch (c);
1297 1298
  }

B
Behdad Esfahbod 已提交
1299
  template <typename set_t>
1300
  void add_coverage (set_t *glyphs) const
B
Behdad Esfahbod 已提交
1301
  {
1302 1303
    hb_add_coverage_context_t<set_t> c (glyphs);
    dispatch (&c);
B
Behdad Esfahbod 已提交
1304 1305
  }

1306 1307
  bool would_apply (hb_would_apply_context_t *c,
		    const hb_ot_layout_lookup_accelerator_t *accel) const
B
Behdad Esfahbod 已提交
1308
  {
B
Behdad Esfahbod 已提交
1309
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
1310 1311 1312
    if (unlikely (!c->len))  return_trace (false);
    if (!accel->may_have (c->glyphs[0]))  return_trace (false);
      return_trace (dispatch (c));
B
Behdad Esfahbod 已提交
1313 1314
  }

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

1317
  SubTable& serialize_subtable (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
1318 1319
				       unsigned int i)
  { return get_subtables<SubTable> ()[i].serialize (c, this); }
1320

1321 1322
  bool serialize_single (hb_serialize_context_t *c,
			 uint32_t lookup_props,
B
Behdad Esfahbod 已提交
1323 1324
		         hb_array_t<const GlyphID> glyphs,
		         hb_array_t<const GlyphID> substitutes)
1325
  {
B
Behdad Esfahbod 已提交
1326
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1327
    if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1328
    return_trace (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes));
1329 1330
  }

1331 1332
  bool serialize_multiple (hb_serialize_context_t *c,
			   uint32_t lookup_props,
B
Behdad Esfahbod 已提交
1333 1334 1335
			   hb_array_t<const GlyphID> glyphs,
			   hb_array_t<const unsigned int> substitute_len_list,
			   hb_array_t<const GlyphID> substitute_glyphs_list)
1336
  {
B
Behdad Esfahbod 已提交
1337
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1338
    if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1339 1340 1341 1342
    return_trace (serialize_subtable (c, 0).u.multiple.serialize (c,
								  glyphs,
								  substitute_len_list,
								  substitute_glyphs_list));
1343 1344
  }

1345 1346
  bool serialize_alternate (hb_serialize_context_t *c,
			    uint32_t lookup_props,
B
Behdad Esfahbod 已提交
1347 1348 1349
			    hb_array_t<const GlyphID> glyphs,
			    hb_array_t<const unsigned int> alternate_len_list,
			    hb_array_t<const GlyphID> alternate_glyphs_list)
1350
  {
B
Behdad Esfahbod 已提交
1351
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1352
    if (unlikely (!Lookup::serialize (c, SubTable::Alternate, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1353 1354 1355 1356
    return_trace (serialize_subtable (c, 0).u.alternate.serialize (c,
								   glyphs,
								   alternate_len_list,
								   alternate_glyphs_list));
1357 1358
  }

1359 1360
  bool serialize_ligature (hb_serialize_context_t *c,
			   uint32_t lookup_props,
B
Behdad Esfahbod 已提交
1361 1362 1363 1364 1365
			   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 */)
1366
  {
B
Behdad Esfahbod 已提交
1367
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1368
    if (unlikely (!Lookup::serialize (c, SubTable::Ligature, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1369 1370 1371 1372 1373 1374
    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));
1375 1376
  }

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

1380
  static hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned int lookup_index)
1381
  {
1382
    if (!c->should_visit_lookup (lookup_index))
1383
      return hb_void_t ();
1384 1385 1386

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

1387 1388 1389 1390
    /* 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 ();
1391 1392

    return ret;
1393 1394
  }

B
Behdad Esfahbod 已提交
1395
  template <typename context_t>
1396
  typename context_t::return_t dispatch (context_t *c) const
B
Behdad Esfahbod 已提交
1397 1398
  { return Lookup::dispatch<SubTable> (c); }

1399
  bool subset (hb_subset_context_t *c) const
1400
  { return Lookup::subset<SubTable> (c); }
B
Behdad Esfahbod 已提交
1401

1402
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
1403
  { return Lookup::sanitize<SubTable> (c); }
B
Behdad Esfahbod 已提交
1404 1405
};

B
Minor  
Behdad Esfahbod 已提交
1406
/*
1407 1408
 * GSUB -- Glyph Substitution
 * https://docs.microsoft.com/en-us/typography/opentype/spec/gsub
B
Minor  
Behdad Esfahbod 已提交
1409 1410
 */

B
Behdad Esfahbod 已提交
1411 1412
struct GSUB : GSUBGPOS
{
1413
  enum { tableTag = HB_OT_TAG_GSUB };
B
Minor  
Behdad Esfahbod 已提交
1414

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

1418
  bool subset (hb_subset_context_t *c) const
1419
  { return GSUBGPOS::subset<SubstLookup> (c); }
1420

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

1424 1425 1426
  HB_INTERNAL bool is_blacklisted (hb_blob_t *blob,
				   hb_face_t *face) const;

B
WIP  
Behdad Esfahbod 已提交
1427
  typedef GSUBGPOS::accelerator_t<GSUB> accelerator_t;
B
Minor  
Behdad Esfahbod 已提交
1428
};
1429 1430


B
Behdad Esfahbod 已提交
1431 1432 1433
struct GSUB_accelerator_t : GSUB::accelerator_t {};


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

1436
/*static*/ inline bool ExtensionSubst::is_reverse () const
B
Behdad Esfahbod 已提交
1437 1438
{
  unsigned int type = get_type ();
B
Behdad Esfahbod 已提交
1439 1440
  if (unlikely (type == SubTable::Extension))
    return CastR<ExtensionSubst> (get_subtable<SubTable>()).is_reverse ();
B
Behdad Esfahbod 已提交
1441 1442 1443
  return SubstLookup::lookup_type_is_reverse (type);
}

1444
template <typename context_t>
1445
/*static*/ inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
1446
{
B
Behdad Esfahbod 已提交
1447
  const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index);
1448
  return l.dispatch (c);
1449 1450
}

1451
/*static*/ inline bool SubstLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index)
B
Behdad Esfahbod 已提交
1452
{
B
Behdad Esfahbod 已提交
1453
  const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index);
1454
  unsigned int saved_lookup_props = c->lookup_props;
1455 1456 1457
  unsigned int saved_lookup_index = c->lookup_index;
  c->set_lookup_index (lookup_index);
  c->set_lookup_props (l.get_props ());
1458
  bool ret = l.dispatch (c);
1459
  c->set_lookup_index (saved_lookup_index);
1460
  c->set_lookup_props (saved_lookup_props);
1461
  return ret;
1462 1463
}

B
Behdad Esfahbod 已提交
1464
} /* namespace OT */
1465

B
Behdad Esfahbod 已提交
1466

1467
#endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */