hb-ot-layout-gsub-table.hh 42.0 KB
Newer Older
B
Behdad Esfahbod 已提交
1
/*
B
Behdad Esfahbod 已提交
2
 * Copyright © 2007,2008,2009,2010  Red Hat, Inc.
3
 * Copyright © 2010,2012,2013  Google, Inc.
B
Behdad Esfahbod 已提交
4
 *
B
Behdad Esfahbod 已提交
5
 *  This is part of HarfBuzz, a text shaping library.
B
Behdad Esfahbod 已提交
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 *
 * Permission is hereby granted, without written agreement and without
 * license or royalty fees, to use, copy, modify, and distribute this
 * software and its documentation for any purpose, provided that the
 * above copyright notice and the following two paragraphs appear in
 * all copies of this software.
 *
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 *
 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
 *
 * Red Hat Author(s): Behdad Esfahbod
26
 * Google Author(s): Behdad Esfahbod
B
Behdad Esfahbod 已提交
27 28
 */

29 30
#ifndef HB_OT_LAYOUT_GSUB_TABLE_HH
#define HB_OT_LAYOUT_GSUB_TABLE_HH
B
Behdad Esfahbod 已提交
31

32
#include "hb-ot-layout-gsubgpos.hh"
B
Behdad Esfahbod 已提交
33

B
Behdad Esfahbod 已提交
34

35 36
namespace OT {

37

B
Behdad Esfahbod 已提交
38 39
struct SingleSubstFormat1
{
B
Behdad Esfahbod 已提交
40
  inline void closure (hb_closure_context_t *c) const
41
  {
B
Behdad Esfahbod 已提交
42
    TRACE_CLOSURE (this);
43
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
44 45
    {
      /* TODO Switch to range-based API to work around malicious fonts.
46
       * https://github.com/harfbuzz/harfbuzz/issues/363 */
B
Behdad Esfahbod 已提交
47 48
      hb_codepoint_t glyph_id = iter.get_glyph ();
      if (c->glyphs->has (glyph_id))
49
	c->out->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
B
Behdad Esfahbod 已提交
50
    }
51 52
  }

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

66 67 68 69 70
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

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

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

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

B
Behdad Esfahbod 已提交
89
    return_trace (true);
90
  }
B
Behdad Esfahbod 已提交
91

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

B
Behdad Esfahbod 已提交
104 105
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
106
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
107
    return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
B
Behdad Esfahbod 已提交
108 109
  }

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

B
Behdad Esfahbod 已提交
121 122
struct SingleSubstFormat2
{
B
Behdad Esfahbod 已提交
123
  inline void closure (hb_closure_context_t *c) const
124
  {
B
Behdad Esfahbod 已提交
125
    TRACE_CLOSURE (this);
126
    unsigned int count = substitute.len;
127
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
128 129
    {
      if (unlikely (iter.get_coverage () >= count))
130
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
B
Behdad Esfahbod 已提交
131
      if (c->glyphs->has (iter.get_glyph ()))
132
	c->out->add (substitute[iter.get_coverage ()]);
B
Behdad Esfahbod 已提交
133
    }
134 135
  }

136 137
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
138
    TRACE_COLLECT_GLYPHS (this);
139
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
140
    unsigned int count = substitute.len;
141
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
142 143
    {
      if (unlikely (iter.get_coverage () >= count))
144
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
B
Minor  
Behdad Esfahbod 已提交
145
      c->output->add (substitute[iter.get_coverage ()]);
146 147 148
    }
  }

149 150 151 152 153
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

154 155
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
156
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
157
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
158 159
  }

160
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
161
  {
B
Behdad Esfahbod 已提交
162
    TRACE_APPLY (this);
163
    hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
164
    unsigned int index = (this+coverage).get_coverage (glyph_id);
B
Behdad Esfahbod 已提交
165
    if (likely (index == NOT_COVERED)) return_trace (false);
166

B
Behdad Esfahbod 已提交
167
    if (unlikely (index >= substitute.len)) return_trace (false);
168 169

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

B
Behdad Esfahbod 已提交
172
    return_trace (true);
173
  }
B
Behdad Esfahbod 已提交
174

B
Behdad Esfahbod 已提交
175
  inline bool serialize (hb_serialize_context_t *c,
176 177
			 Supplier<GlyphID> &glyphs,
			 Supplier<GlyphID> &substitutes,
B
Behdad Esfahbod 已提交
178 179
			 unsigned int num_glyphs)
  {
B
Behdad Esfahbod 已提交
180
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
181 182 183 184
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    if (unlikely (!substitute.serialize (c, substitutes, num_glyphs))) return_trace (false);
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
    return_trace (true);
B
Behdad Esfahbod 已提交
185 186
  }

B
Behdad Esfahbod 已提交
187 188
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
189
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
190
    return_trace (coverage.sanitize (c, this) && substitute.sanitize (c));
B
Behdad Esfahbod 已提交
191 192
  }

193
  protected:
B
Behdad Esfahbod 已提交
194
  HBUINT16	format;			/* Format identifier--format = 2 */
B
Behdad Esfahbod 已提交
195 196
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
197
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
198 199 200
  ArrayOf<GlyphID>
		substitute;		/* Array of substitute
					 * GlyphIDs--ordered by Coverage Index */
201
  public:
202
  DEFINE_SIZE_ARRAY (6, substitute);
B
Behdad Esfahbod 已提交
203 204
};

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

B
Behdad Esfahbod 已提交
234 235 236
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
  {
237
    TRACE_DISPATCH (this, u.format);
238
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
239
    switch (u.format) {
B
Behdad Esfahbod 已提交
240 241 242
    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 已提交
243 244 245
    }
  }

246
  protected:
247
  union {
B
Behdad Esfahbod 已提交
248
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
249 250
  SingleSubstFormat1	format1;
  SingleSubstFormat2	format2;
251
  } u;
B
Behdad Esfahbod 已提交
252
};
253

B
Behdad Esfahbod 已提交
254

B
Behdad Esfahbod 已提交
255 256
struct Sequence
{
B
Behdad Esfahbod 已提交
257
  inline void closure (hb_closure_context_t *c) const
258
  {
B
Behdad Esfahbod 已提交
259
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
260 261
    unsigned int count = substitute.len;
    for (unsigned int i = 0; i < count; i++)
262
      c->out->add (substitute[i]);
263 264
  }

265 266
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
267
    TRACE_COLLECT_GLYPHS (this);
268
    c->output->add_array (substitute.arrayZ, substitute.len);
269 270
  }

271
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
272
  {
B
Behdad Esfahbod 已提交
273
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
274
    unsigned int count = substitute.len;
275

B
Behdad Esfahbod 已提交
276 277 278
    /* Special-case to make it in-place and not consider this
     * as a "multiplied" substitution. */
    if (unlikely (count == 1))
279
    {
280
      c->replace_glyph (substitute.arrayZ[0]);
B
Behdad Esfahbod 已提交
281
      return_trace (true);
282
    }
283
    /* Spec disallows this, but Uniscribe allows it.
284
     * https://github.com/harfbuzz/harfbuzz/issues/253 */
285 286 287 288 289
    else if (unlikely (count == 0))
    {
      c->buffer->delete_glyph ();
      return_trace (true);
    }
B
Behdad Esfahbod 已提交
290 291 292 293 294 295

    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);
296
      c->output_glyph_for_component (substitute.arrayZ[i], klass);
297
    }
B
Behdad Esfahbod 已提交
298
    c->buffer->skip_glyph ();
B
Behdad Esfahbod 已提交
299

B
Behdad Esfahbod 已提交
300
    return_trace (true);
B
Behdad Esfahbod 已提交
301 302
  }

303
  inline bool serialize (hb_serialize_context_t *c,
304
			 Supplier<GlyphID> &glyphs,
305 306
			 unsigned int num_glyphs)
  {
B
Behdad Esfahbod 已提交
307
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
308 309 310
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    if (unlikely (!substitute.serialize (c, glyphs, num_glyphs))) return_trace (false);
    return_trace (true);
311 312
  }

B
Behdad Esfahbod 已提交
313 314
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
315
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
316
    return_trace (substitute.sanitize (c));
B
Behdad Esfahbod 已提交
317 318
  }

319
  protected:
B
Behdad Esfahbod 已提交
320 321
  ArrayOf<GlyphID>
		substitute;		/* String of GlyphIDs to substitute */
322
  public:
323
  DEFINE_SIZE_ARRAY (2, substitute);
B
Behdad Esfahbod 已提交
324 325
};

B
Behdad Esfahbod 已提交
326 327
struct MultipleSubstFormat1
{
B
Behdad Esfahbod 已提交
328
  inline void closure (hb_closure_context_t *c) const
329
  {
B
Behdad Esfahbod 已提交
330
    TRACE_CLOSURE (this);
331
    unsigned int count = sequence.len;
332
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
333 334
    {
      if (unlikely (iter.get_coverage () >= count))
335
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
B
Behdad Esfahbod 已提交
336
      if (c->glyphs->has (iter.get_glyph ()))
B
Behdad Esfahbod 已提交
337
	(this+sequence[iter.get_coverage ()]).closure (c);
B
Behdad Esfahbod 已提交
338
    }
339 340
  }

341 342
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
343
    TRACE_COLLECT_GLYPHS (this);
344
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
345 346 347 348 349
    unsigned int count = sequence.len;
    for (unsigned int i = 0; i < count; i++)
	(this+sequence[i]).collect_glyphs (c);
  }

350 351 352 353 354
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

355 356
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
357
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
358
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
359 360
  }

361
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
362
  {
B
Behdad Esfahbod 已提交
363
    TRACE_APPLY (this);
364

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

B
Behdad Esfahbod 已提交
368
    return_trace ((this+sequence[index]).apply (c));
369
  }
B
Behdad Esfahbod 已提交
370

371
  inline bool serialize (hb_serialize_context_t *c,
372 373
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &substitute_len_list,
374
			 unsigned int num_glyphs,
375
			 Supplier<GlyphID> &substitute_glyphs_list)
376
  {
B
Behdad Esfahbod 已提交
377
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
378 379
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    if (unlikely (!sequence.serialize (c, num_glyphs))) return_trace (false);
380 381 382
    for (unsigned int i = 0; i < num_glyphs; i++)
      if (unlikely (!sequence[i].serialize (c, this).serialize (c,
								substitute_glyphs_list,
B
Behdad Esfahbod 已提交
383
								substitute_len_list[i]))) return_trace (false);
384
    substitute_len_list += num_glyphs;
B
Behdad Esfahbod 已提交
385 386
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
    return_trace (true);
387 388
  }

B
Behdad Esfahbod 已提交
389 390
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
391
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
392
    return_trace (coverage.sanitize (c, this) && sequence.sanitize (c, this));
B
Behdad Esfahbod 已提交
393 394
  }

395
  protected:
B
Behdad Esfahbod 已提交
396
  HBUINT16	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
397 398
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
399
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
400 401 402
  OffsetArrayOf<Sequence>
		sequence;		/* Array of Sequence tables
					 * ordered by Coverage Index */
403
  public:
404
  DEFINE_SIZE_ARRAY (6, sequence);
B
Behdad Esfahbod 已提交
405
};
406

B
Behdad Esfahbod 已提交
407 408
struct MultipleSubst
{
409
  inline bool serialize (hb_serialize_context_t *c,
410 411
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &substitute_len_list,
412
			 unsigned int num_glyphs,
413
			 Supplier<GlyphID> &substitute_glyphs_list)
414
  {
B
Behdad Esfahbod 已提交
415
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
416
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
417 418 419
    unsigned int format = 1;
    u.format.set (format);
    switch (u.format) {
B
Behdad Esfahbod 已提交
420 421
    case 1: return_trace (u.format1.serialize (c, glyphs, substitute_len_list, num_glyphs, substitute_glyphs_list));
    default:return_trace (false);
422 423 424
    }
  }

B
Behdad Esfahbod 已提交
425 426 427
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
  {
428
    TRACE_DISPATCH (this, u.format);
429
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
430
    switch (u.format) {
B
Behdad Esfahbod 已提交
431 432
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
433 434 435
    }
  }

436
  protected:
437
  union {
B
Behdad Esfahbod 已提交
438
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
439
  MultipleSubstFormat1	format1;
440 441 442
  } u;
};

B
Behdad Esfahbod 已提交
443

B
Behdad Esfahbod 已提交
444
typedef ArrayOf<GlyphID> AlternateSet;	/* Array of alternate GlyphIDs--in
B
Behdad Esfahbod 已提交
445 446
					 * arbitrary order */

B
Behdad Esfahbod 已提交
447 448
struct AlternateSubstFormat1
{
B
Behdad Esfahbod 已提交
449
  inline void closure (hb_closure_context_t *c) const
450
  {
B
Behdad Esfahbod 已提交
451
    TRACE_CLOSURE (this);
452
    unsigned int count = alternateSet.len;
453
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
454 455
    {
      if (unlikely (iter.get_coverage () >= count))
456
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
B
Behdad Esfahbod 已提交
457 458 459 460
      if (c->glyphs->has (iter.get_glyph ())) {
	const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
	unsigned int count = alt_set.len;
	for (unsigned int i = 0; i < count; i++)
461
	  c->out->add (alt_set[i]);
B
Behdad Esfahbod 已提交
462 463
      }
    }
464 465
  }

466 467
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
468
    TRACE_COLLECT_GLYPHS (this);
469
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
470
    unsigned int count = alternateSet.len;
471
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
472 473
    {
      if (unlikely (iter.get_coverage () >= count))
474
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
475
      const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
476
      c->output->add_array (alt_set.arrayZ, alt_set.len);
477 478 479
    }
  }

480 481 482 483 484
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

485 486
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
487
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
488
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
489 490
  }

491
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
492
  {
B
Behdad Esfahbod 已提交
493
    TRACE_APPLY (this);
494
    hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
495

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

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

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

503
    hb_mask_t glyph_mask = c->buffer->cur().mask;
B
Behdad Esfahbod 已提交
504 505
    hb_mask_t lookup_mask = c->lookup_mask;

B
Behdad Esfahbod 已提交
506
    /* Note: This breaks badly if two features enabled this lookup together. */
507
    unsigned int shift = hb_ctz (lookup_mask);
B
Behdad Esfahbod 已提交
508
    unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift);
509

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

B
Behdad Esfahbod 已提交
512
    glyph_id = alt_set[alt_index - 1];
513

514
    c->replace_glyph (glyph_id);
515

B
Behdad Esfahbod 已提交
516
    return_trace (true);
517
  }
B
Behdad Esfahbod 已提交
518

519
  inline bool serialize (hb_serialize_context_t *c,
520 521
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &alternate_len_list,
522
			 unsigned int num_glyphs,
523
			 Supplier<GlyphID> &alternate_glyphs_list)
524
  {
B
Behdad Esfahbod 已提交
525
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
526 527
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    if (unlikely (!alternateSet.serialize (c, num_glyphs))) return_trace (false);
528 529 530
    for (unsigned int i = 0; i < num_glyphs; i++)
      if (unlikely (!alternateSet[i].serialize (c, this).serialize (c,
								    alternate_glyphs_list,
B
Behdad Esfahbod 已提交
531
								    alternate_len_list[i]))) return_trace (false);
532
    alternate_len_list += num_glyphs;
B
Behdad Esfahbod 已提交
533 534
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return_trace (false);
    return_trace (true);
535 536
  }

B
Behdad Esfahbod 已提交
537 538
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
539
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
540
    return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
541 542
  }

543
  protected:
B
Behdad Esfahbod 已提交
544
  HBUINT16	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
545 546
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
547
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
548 549 550
  OffsetArrayOf<AlternateSet>
		alternateSet;		/* Array of AlternateSet tables
					 * ordered by Coverage Index */
551
  public:
552
  DEFINE_SIZE_ARRAY (6, alternateSet);
B
Behdad Esfahbod 已提交
553
};
554

B
Behdad Esfahbod 已提交
555 556
struct AlternateSubst
{
557
  inline bool serialize (hb_serialize_context_t *c,
558 559
			 Supplier<GlyphID> &glyphs,
			 Supplier<unsigned int> &alternate_len_list,
560
			 unsigned int num_glyphs,
561
			 Supplier<GlyphID> &alternate_glyphs_list)
562
  {
B
Behdad Esfahbod 已提交
563
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
564
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
565 566 567
    unsigned int format = 1;
    u.format.set (format);
    switch (u.format) {
B
Behdad Esfahbod 已提交
568 569
    case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, num_glyphs, alternate_glyphs_list));
    default:return_trace (false);
570 571 572
    }
  }

B
Behdad Esfahbod 已提交
573 574 575
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
  {
576
    TRACE_DISPATCH (this, u.format);
577
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
578
    switch (u.format) {
B
Behdad Esfahbod 已提交
579 580
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
581 582 583
    }
  }

584
  protected:
585
  union {
B
Behdad Esfahbod 已提交
586
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
587
  AlternateSubstFormat1	format1;
588 589 590
  } u;
};

591

B
Behdad Esfahbod 已提交
592 593
struct Ligature
{
B
Behdad Esfahbod 已提交
594
  inline void closure (hb_closure_context_t *c) const
595
  {
B
Behdad Esfahbod 已提交
596
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
597 598 599
    unsigned int count = component.len;
    for (unsigned int i = 1; i < count; i++)
      if (!c->glyphs->has (component[i]))
B
Behdad Esfahbod 已提交
600
        return;
601
    c->out->add (ligGlyph);
602 603
  }

604 605
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
606
    TRACE_COLLECT_GLYPHS (this);
607
    c->input->add_array (component.arrayZ, component.len ? component.len - 1 : 0);
B
Minor  
Behdad Esfahbod 已提交
608
    c->output->add (ligGlyph);
609 610
  }

611
  inline bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
612
  {
B
Behdad Esfahbod 已提交
613
    TRACE_WOULD_APPLY (this);
614
    if (c->len != component.len)
B
Behdad Esfahbod 已提交
615
      return_trace (false);
616 617 618

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

B
Behdad Esfahbod 已提交
621
    return_trace (true);
B
Behdad Esfahbod 已提交
622 623
  }

624
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
625
  {
B
Behdad Esfahbod 已提交
626
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
627
    unsigned int count = component.len;
B
Behdad Esfahbod 已提交
628

B
Behdad Esfahbod 已提交
629
    if (unlikely (!count)) return_trace (false);
B
Behdad Esfahbod 已提交
630

631 632 633 634 635
    /* 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 已提交
636
      return_trace (true);
637 638
    }

B
Behdad Esfahbod 已提交
639 640
    bool is_mark_ligature = false;
    unsigned int total_component_count = 0;
641

642
    unsigned int match_length = 0;
643
    unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
644

645 646 647
    if (likely (!match_input (c, count,
			      &component[1],
			      match_glyph,
B
Behdad Esfahbod 已提交
648
			      nullptr,
649 650
			      &match_length,
			      match_positions,
651 652
			      &is_mark_ligature,
			      &total_component_count)))
B
Behdad Esfahbod 已提交
653
      return_trace (false);
654

655 656
    ligate_input (c,
		  count,
657 658
		  match_positions,
		  match_length,
659
		  ligGlyph,
660 661
		  is_mark_ligature,
		  total_component_count);
662

B
Behdad Esfahbod 已提交
663
    return_trace (true);
664
  }
665

666 667 668 669 670
  inline bool serialize (hb_serialize_context_t *c,
			 GlyphID ligature,
			 Supplier<GlyphID> &components, /* Starting from second */
			 unsigned int num_components /* Including first component */)
  {
B
Behdad Esfahbod 已提交
671
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
672
    if (unlikely (!c->extend_min (*this))) return_trace (false);
673
    ligGlyph = ligature;
B
Behdad Esfahbod 已提交
674 675
    if (unlikely (!component.serialize (c, components, num_components))) return_trace (false);
    return_trace (true);
676 677
  }

B
Behdad Esfahbod 已提交
678
  public:
B
Behdad Esfahbod 已提交
679 680
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
681
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
682
    return_trace (ligGlyph.sanitize (c) && component.sanitize (c));
B
Behdad Esfahbod 已提交
683 684
  }

685
  protected:
686
  GlyphID	ligGlyph;		/* GlyphID of ligature to substitute */
B
Behdad Esfahbod 已提交
687 688
  HeadlessArrayOf<GlyphID>
		component;		/* Array of component GlyphIDs--start
689 690
					 * with the second  component--ordered
					 * in writing direction */
691
  public:
692
  DEFINE_SIZE_ARRAY (4, component);
693
};
B
Behdad Esfahbod 已提交
694

B
Behdad Esfahbod 已提交
695 696
struct LigatureSet
{
B
Behdad Esfahbod 已提交
697
  inline void closure (hb_closure_context_t *c) const
698
  {
B
Behdad Esfahbod 已提交
699
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
700 701
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
B
Behdad Esfahbod 已提交
702
      (this+ligature[i]).closure (c);
703 704
  }

705 706
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
707
    TRACE_COLLECT_GLYPHS (this);
708 709 710 711 712
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
      (this+ligature[i]).collect_glyphs (c);
  }

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

726
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
727
  {
B
Behdad Esfahbod 已提交
728
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
729
    unsigned int num_ligs = ligature.len;
B
Behdad Esfahbod 已提交
730 731
    for (unsigned int i = 0; i < num_ligs; i++)
    {
B
Behdad Esfahbod 已提交
732
      const Ligature &lig = this+ligature[i];
B
Behdad Esfahbod 已提交
733
      if (lig.apply (c)) return_trace (true);
734 735
    }

B
Behdad Esfahbod 已提交
736
    return_trace (false);
737
  }
B
Behdad Esfahbod 已提交
738

739 740 741 742 743 744
  inline bool serialize (hb_serialize_context_t *c,
			 Supplier<GlyphID> &ligatures,
			 Supplier<unsigned int> &component_count_list,
			 unsigned int num_ligatures,
			 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
  {
B
Behdad Esfahbod 已提交
745
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
746 747
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    if (unlikely (!ligature.serialize (c, num_ligatures))) return_trace (false);
748 749 750 751
    for (unsigned int i = 0; i < num_ligatures; i++)
      if (unlikely (!ligature[i].serialize (c, this).serialize (c,
								ligatures[i],
								component_list,
B
Behdad Esfahbod 已提交
752
								component_count_list[i]))) return_trace (false);
753 754
    ligatures += num_ligatures;
    component_count_list += num_ligatures;
B
Behdad Esfahbod 已提交
755
    return_trace (true);
756 757
  }

B
Behdad Esfahbod 已提交
758 759
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
760
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
761
    return_trace (ligature.sanitize (c, this));
B
Behdad Esfahbod 已提交
762 763
  }

764
  protected:
B
Behdad Esfahbod 已提交
765 766 767
  OffsetArrayOf<Ligature>
		ligature;		/* Array LigatureSet tables
					 * ordered by preference */
768
  public:
769
  DEFINE_SIZE_ARRAY (2, ligature);
B
Behdad Esfahbod 已提交
770 771
};

B
Behdad Esfahbod 已提交
772 773
struct LigatureSubstFormat1
{
B
Behdad Esfahbod 已提交
774
  inline void closure (hb_closure_context_t *c) const
775
  {
B
Behdad Esfahbod 已提交
776
    TRACE_CLOSURE (this);
777
    unsigned int count = ligatureSet.len;
778
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
779 780
    {
      if (unlikely (iter.get_coverage () >= count))
781
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
B
Behdad Esfahbod 已提交
782
      if (c->glyphs->has (iter.get_glyph ()))
B
Behdad Esfahbod 已提交
783
	(this+ligatureSet[iter.get_coverage ()]).closure (c);
B
Behdad Esfahbod 已提交
784
    }
785 786
  }

787 788
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
789
    TRACE_COLLECT_GLYPHS (this);
790
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
791
    unsigned int count = ligatureSet.len;
792
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
793 794
    {
      if (unlikely (iter.get_coverage () >= count))
795
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
796 797 798 799
      (this+ligatureSet[iter.get_coverage ()]).collect_glyphs (c);
    }
  }

800 801 802 803 804
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

805
  inline bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
806
  {
B
Behdad Esfahbod 已提交
807
    TRACE_WOULD_APPLY (this);
808
    unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
B
Behdad Esfahbod 已提交
809
    if (likely (index == NOT_COVERED)) return_trace (false);
810 811

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

815
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
816
  {
B
Behdad Esfahbod 已提交
817
    TRACE_APPLY (this);
818
    hb_codepoint_t glyph_id = c->buffer->cur().codepoint;
819

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

B
Behdad Esfahbod 已提交
823
    const LigatureSet &lig_set = this+ligatureSet[index];
B
Behdad Esfahbod 已提交
824
    return_trace (lig_set.apply (c));
825
  }
B
Behdad Esfahbod 已提交
826

827 828 829 830 831 832 833 834
  inline bool serialize (hb_serialize_context_t *c,
			 Supplier<GlyphID> &first_glyphs,
			 Supplier<unsigned int> &ligature_per_first_glyph_count_list,
			 unsigned int num_first_glyphs,
			 Supplier<GlyphID> &ligatures_list,
			 Supplier<unsigned int> &component_count_list,
			 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
  {
B
Behdad Esfahbod 已提交
835
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
836 837
    if (unlikely (!c->extend_min (*this))) return_trace (false);
    if (unlikely (!ligatureSet.serialize (c, num_first_glyphs))) return_trace (false);
838 839 840 841 842
    for (unsigned int i = 0; i < num_first_glyphs; i++)
      if (unlikely (!ligatureSet[i].serialize (c, this).serialize (c,
								   ligatures_list,
								   component_count_list,
								   ligature_per_first_glyph_count_list[i],
B
Behdad Esfahbod 已提交
843
								   component_list))) return_trace (false);
844
    ligature_per_first_glyph_count_list += num_first_glyphs;
B
Behdad Esfahbod 已提交
845 846
    if (unlikely (!coverage.serialize (c, this).serialize (c, first_glyphs, num_first_glyphs))) return_trace (false);
    return_trace (true);
847 848
  }

B
Behdad Esfahbod 已提交
849 850
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
851
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
852
    return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
853 854
  }

855
  protected:
B
Behdad Esfahbod 已提交
856
  HBUINT16	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
857 858
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
859
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
860
  OffsetArrayOf<LigatureSet>
B
Behdad Esfahbod 已提交
861 862
		ligatureSet;		/* Array LigatureSet tables
					 * ordered by Coverage Index */
863
  public:
864
  DEFINE_SIZE_ARRAY (6, ligatureSet);
B
Behdad Esfahbod 已提交
865
};
866

B
Behdad Esfahbod 已提交
867 868
struct LigatureSubst
{
869 870 871 872 873 874 875 876
  inline bool serialize (hb_serialize_context_t *c,
			 Supplier<GlyphID> &first_glyphs,
			 Supplier<unsigned int> &ligature_per_first_glyph_count_list,
			 unsigned int num_first_glyphs,
			 Supplier<GlyphID> &ligatures_list,
			 Supplier<unsigned int> &component_count_list,
			 Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
  {
B
Behdad Esfahbod 已提交
877
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
878
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
879 880 881
    unsigned int format = 1;
    u.format.set (format);
    switch (u.format) {
B
Behdad Esfahbod 已提交
882 883 884 885 886 887 888 889
    case 1: return_trace (u.format1.serialize (c,
					       first_glyphs,
					       ligature_per_first_glyph_count_list,
					       num_first_glyphs,
					       ligatures_list,
					       component_count_list,
					       component_list));
    default:return_trace (false);
890 891 892
    }
  }

B
Behdad Esfahbod 已提交
893 894 895
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
  {
896
    TRACE_DISPATCH (this, u.format);
897
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
898
    switch (u.format) {
B
Behdad Esfahbod 已提交
899 900
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
901 902 903
    }
  }

904
  protected:
905
  union {
B
Behdad Esfahbod 已提交
906
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
907
  LigatureSubstFormat1	format1;
908 909 910
  } u;
};

B
Behdad Esfahbod 已提交
911

B
Minor  
Behdad Esfahbod 已提交
912
struct ContextSubst : Context {};
B
Behdad Esfahbod 已提交
913

B
Minor  
Behdad Esfahbod 已提交
914
struct ChainContextSubst : ChainContext {};
915

B
Behdad Esfahbod 已提交
916
struct ExtensionSubst : Extension<ExtensionSubst>
B
Behdad Esfahbod 已提交
917
{
918
  typedef struct SubstLookupSubTable LookupSubTable;
B
Behdad Esfahbod 已提交
919

B
Behdad Esfahbod 已提交
920
  inline bool is_reverse (void) const;
921 922 923
};


B
Behdad Esfahbod 已提交
924 925
struct ReverseChainSingleSubstFormat1
{
B
Behdad Esfahbod 已提交
926
  inline void closure (hb_closure_context_t *c) const
927
  {
B
Behdad Esfahbod 已提交
928
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
929 930 931 932 933 934 935
    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 已提交
936
        return;
B
Behdad Esfahbod 已提交
937 938 939 940

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

    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
944
    count = substitute.len;
945
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
946 947
    {
      if (unlikely (iter.get_coverage () >= count))
948
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
B
Behdad Esfahbod 已提交
949
      if (c->glyphs->has (iter.get_glyph ()))
950
	c->out->add (substitute[iter.get_coverage ()]);
B
Behdad Esfahbod 已提交
951
    }
952 953
  }

954 955
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
B
Behdad Esfahbod 已提交
956
    TRACE_COLLECT_GLYPHS (this);
957
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
958 959 960 961 962

    unsigned int count;

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

965
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
966 967
    count = lookahead.len;
    for (unsigned int i = 0; i < count; i++)
968
      if (unlikely (!(this+lookahead[i]).add_coverage (c->after))) return;
969 970 971

    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
    count = substitute.len;
972
    c->output->add_array (substitute.arrayZ, substitute.len);
973 974
  }

975 976 977 978 979
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

980 981
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
982
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
983
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
984 985
  }

986
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
987
  {
B
Behdad Esfahbod 已提交
988
    TRACE_APPLY (this);
989
    if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
B
Behdad Esfahbod 已提交
990
      return_trace (false); /* No chaining to this type */
991

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

995 996
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
997

998
  unsigned int start_index = 0, end_index = 0;
B
Behdad Esfahbod 已提交
999
    if (match_backtrack (c,
1000
			 backtrack.len, (HBUINT16 *) backtrack.arrayZ,
1001 1002
			 match_coverage, this,
			 &start_index) &&
B
Behdad Esfahbod 已提交
1003
        match_lookahead (c,
1004
			 lookahead.len, (HBUINT16 *) lookahead.arrayZ,
B
Behdad Esfahbod 已提交
1005
			 match_coverage, this,
1006
			 1, &end_index))
1007
    {
1008
      c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index);
B
Behdad Esfahbod 已提交
1009
      c->replace_glyph_inplace (substitute[index]);
1010 1011 1012
      /* 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 已提交
1013
      return_trace (true);
1014 1015
    }

B
Behdad Esfahbod 已提交
1016
    return_trace (false);
1017
  }
B
Behdad Esfahbod 已提交
1018

B
Behdad Esfahbod 已提交
1019 1020
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1021
    TRACE_SANITIZE (this);
1022
    if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
B
Behdad Esfahbod 已提交
1023
      return_trace (false);
B
Behdad Esfahbod 已提交
1024
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
B
Behdad Esfahbod 已提交
1025
    if (!lookahead.sanitize (c, this))
B
Behdad Esfahbod 已提交
1026
      return_trace (false);
B
Behdad Esfahbod 已提交
1027
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
B
Behdad Esfahbod 已提交
1028
    return_trace (substitute.sanitize (c));
B
Behdad Esfahbod 已提交
1029 1030
  }

1031
  protected:
B
Behdad Esfahbod 已提交
1032
  HBUINT16	format;			/* Format identifier--format = 1 */
1033 1034 1035 1036 1037
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of table */
  OffsetArrayOf<Coverage>
		backtrack;		/* Array of coverage tables
B
Behdad Esfahbod 已提交
1038 1039
					 * in backtracking sequence, in  glyph
					 * sequence order */
1040 1041 1042
  OffsetArrayOf<Coverage>
		lookaheadX;		/* Array of coverage tables
					 * in lookahead sequence, in glyph
B
Behdad Esfahbod 已提交
1043
					 * sequence order */
1044 1045 1046
  ArrayOf<GlyphID>
		substituteX;		/* Array of substitute
					 * GlyphIDs--ordered by Coverage Index */
1047
  public:
B
Behdad Esfahbod 已提交
1048
  DEFINE_SIZE_MIN (10);
B
Behdad Esfahbod 已提交
1049 1050
};

B
Behdad Esfahbod 已提交
1051 1052
struct ReverseChainSingleSubst
{
1053
  template <typename context_t>
1054
  inline typename context_t::return_t dispatch (context_t *c) const
1055
  {
1056
    TRACE_DISPATCH (this, u.format);
1057
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1058
    switch (u.format) {
B
Behdad Esfahbod 已提交
1059 1060
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
1061 1062 1063
    }
  }

1064
  protected:
1065
  union {
B
Behdad Esfahbod 已提交
1066
  HBUINT16				format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1067
  ReverseChainSingleSubstFormat1	format1;
1068 1069 1070 1071 1072
  } u;
};



B
Behdad Esfahbod 已提交
1073 1074 1075 1076
/*
 * SubstLookup
 */

B
Behdad Esfahbod 已提交
1077 1078
struct SubstLookupSubTable
{
B
Behdad Esfahbod 已提交
1079 1080
  friend struct SubstLookup;

B
Behdad Esfahbod 已提交
1081
  enum Type {
1082 1083 1084 1085 1086 1087 1088
    Single		= 1,
    Multiple		= 2,
    Alternate		= 3,
    Ligature		= 4,
    Context		= 5,
    ChainContext	= 6,
    Extension		= 7,
1089
    ReverseChainSingle	= 8
1090 1091
  };

1092
  template <typename context_t>
1093
  inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
1094
  {
1095
    TRACE_DISPATCH (this, lookup_type);
1096
    if (unlikely (!c->may_dispatch (this, &u.sub_format))) return_trace (c->no_dispatch_return_value ());
1097
    switch (lookup_type) {
B
Behdad Esfahbod 已提交
1098 1099 1100 1101 1102 1103 1104 1105 1106
    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 ());
1107 1108 1109
    }
  }

1110
  protected:
B
Behdad Esfahbod 已提交
1111
  union {
B
Behdad Esfahbod 已提交
1112
  HBUINT16			sub_format;
B
Behdad Esfahbod 已提交
1113 1114 1115 1116
  SingleSubst			single;
  MultipleSubst			multiple;
  AlternateSubst		alternate;
  LigatureSubst			ligature;
1117
  ContextSubst			context;
B
Behdad Esfahbod 已提交
1118 1119 1120
  ChainContextSubst		chainContext;
  ExtensionSubst		extension;
  ReverseChainSingleSubst	reverseChainContextSingle;
B
Behdad Esfahbod 已提交
1121
  } u;
B
Behdad Esfahbod 已提交
1122
  public:
B
Minor  
Behdad Esfahbod 已提交
1123
  DEFINE_SIZE_UNION (2, sub_format);
B
Behdad Esfahbod 已提交
1124 1125
};

1126

B
Behdad Esfahbod 已提交
1127 1128
struct SubstLookup : Lookup
{
1129
  inline const SubstLookupSubTable& get_subtable (unsigned int i) const
1130
  { return Lookup::get_subtable<SubstLookupSubTable> (i); }
B
Behdad Esfahbod 已提交
1131

B
Behdad Esfahbod 已提交
1132
  inline static bool lookup_type_is_reverse (unsigned int lookup_type)
1133
  { return lookup_type == SubstLookupSubTable::ReverseChainSingle; }
B
Behdad Esfahbod 已提交
1134 1135

  inline bool is_reverse (void) const
B
Behdad Esfahbod 已提交
1136
  {
B
Behdad Esfahbod 已提交
1137
    unsigned int type = get_type ();
1138
    if (unlikely (type == SubstLookupSubTable::Extension))
1139
      return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
B
Behdad Esfahbod 已提交
1140
    return lookup_type_is_reverse (type);
B
Behdad Esfahbod 已提交
1141
  }
1142

1143
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1144 1145
  {
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
1146
    return_trace (dispatch (c));
B
Behdad Esfahbod 已提交
1147 1148
  }

1149
  inline hb_closure_context_t::return_t closure (hb_closure_context_t *c, unsigned int this_index) const
1150
  {
B
Behdad Esfahbod 已提交
1151
    TRACE_CLOSURE (this);
1152
    if (!c->should_visit_lookup (this_index))
1153 1154 1155
      return_trace (HB_VOID);

    c->set_recurse_func (dispatch_closure_recurse_func);
1156 1157 1158 1159 1160 1161

    hb_closure_context_t::return_t ret = dispatch (c);

    c->flush ();

    return_trace (ret);
B
Behdad Esfahbod 已提交
1162 1163
  }

B
Behdad Esfahbod 已提交
1164
  inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
B
Behdad Esfahbod 已提交
1165 1166
  {
    TRACE_COLLECT_GLYPHS (this);
1167
    c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
B
Behdad Esfahbod 已提交
1168
    return_trace (dispatch (c));
1169 1170
  }

B
Behdad Esfahbod 已提交
1171 1172 1173
  template <typename set_t>
  inline void add_coverage (set_t *glyphs) const
  {
1174 1175
    hb_add_coverage_context_t<set_t> c (glyphs);
    dispatch (&c);
B
Behdad Esfahbod 已提交
1176 1177
  }

1178 1179
  inline bool would_apply (hb_would_apply_context_t *c,
			   const hb_ot_layout_lookup_accelerator_t *accel) const
B
Behdad Esfahbod 已提交
1180
  {
B
Behdad Esfahbod 已提交
1181
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
1182 1183 1184
    if (unlikely (!c->len))  return_trace (false);
    if (!accel->may_have (c->glyphs[0]))  return_trace (false);
      return_trace (dispatch (c));
B
Behdad Esfahbod 已提交
1185 1186
  }

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

1189 1190
  inline SubstLookupSubTable& serialize_subtable (hb_serialize_context_t *c,
						  unsigned int i)
1191
  { return get_subtables<SubstLookupSubTable> ()[i].serialize (c, this); }
1192 1193 1194 1195 1196 1197 1198

  inline bool serialize_single (hb_serialize_context_t *c,
				uint32_t lookup_props,
			        Supplier<GlyphID> &glyphs,
			        Supplier<GlyphID> &substitutes,
			        unsigned int num_glyphs)
  {
B
Behdad Esfahbod 已提交
1199
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1200 1201
    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Single, lookup_props, 1))) return_trace (false);
    return_trace (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes, num_glyphs));
1202 1203 1204 1205 1206 1207 1208 1209 1210
  }

  inline bool serialize_multiple (hb_serialize_context_t *c,
				  uint32_t lookup_props,
				  Supplier<GlyphID> &glyphs,
				  Supplier<unsigned int> &substitute_len_list,
				  unsigned int num_glyphs,
				  Supplier<GlyphID> &substitute_glyphs_list)
  {
B
Behdad Esfahbod 已提交
1211
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1212 1213 1214 1215 1216 1217
    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Multiple, lookup_props, 1))) return_trace (false);
    return_trace (serialize_subtable (c, 0).u.multiple.serialize (c,
								  glyphs,
								  substitute_len_list,
								  num_glyphs,
								  substitute_glyphs_list));
1218 1219 1220 1221 1222 1223 1224 1225 1226
  }

  inline bool serialize_alternate (hb_serialize_context_t *c,
				   uint32_t lookup_props,
				   Supplier<GlyphID> &glyphs,
				   Supplier<unsigned int> &alternate_len_list,
				   unsigned int num_glyphs,
				   Supplier<GlyphID> &alternate_glyphs_list)
  {
B
Behdad Esfahbod 已提交
1227
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1228 1229 1230 1231 1232 1233
    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Alternate, lookup_props, 1))) return_trace (false);
    return_trace (serialize_subtable (c, 0).u.alternate.serialize (c,
								   glyphs,
								   alternate_len_list,
								   num_glyphs,
								   alternate_glyphs_list));
1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244
  }

  inline bool serialize_ligature (hb_serialize_context_t *c,
				  uint32_t lookup_props,
				  Supplier<GlyphID> &first_glyphs,
				  Supplier<unsigned int> &ligature_per_first_glyph_count_list,
				  unsigned int num_first_glyphs,
				  Supplier<GlyphID> &ligatures_list,
				  Supplier<unsigned int> &component_count_list,
				  Supplier<GlyphID> &component_list /* Starting from second for each ligature */)
  {
B
Behdad Esfahbod 已提交
1245
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1246 1247 1248 1249 1250 1251 1252 1253
    if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Ligature, lookup_props, 1))) return_trace (false);
    return_trace (serialize_subtable (c, 0).u.ligature.serialize (c,
								  first_glyphs,
								  ligature_per_first_glyph_count_list,
								  num_first_glyphs,
								  ligatures_list,
								  component_count_list,
								  component_list));
1254 1255
  }

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

B
Behdad Esfahbod 已提交
1259
  static inline hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned int lookup_index)
1260
  {
1261
    if (!c->should_visit_lookup (lookup_index))
1262
      return HB_VOID;
1263 1264 1265 1266 1267 1268

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

    c->flush ();

    return ret;
1269 1270
  }

B
Behdad Esfahbod 已提交
1271 1272
  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
1273
  { return Lookup::dispatch<SubstLookupSubTable> (c); }
B
Behdad Esfahbod 已提交
1274

B
Behdad Esfahbod 已提交
1275
  inline bool sanitize (hb_sanitize_context_t *c) const
1276
  {
B
Behdad Esfahbod 已提交
1277
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1278 1279
    if (unlikely (!Lookup::sanitize (c))) return_trace (false);
    if (unlikely (!dispatch (c))) return_trace (false);
B
Behdad Esfahbod 已提交
1280 1281 1282 1283

    if (unlikely (get_type () == SubstLookupSubTable::Extension))
    {
      /* The spec says all subtables of an Extension lookup should
1284
       * have the same type, which shall not be the Extension type
1285 1286
       * itself (but we already checked for that).
       * This is specially important if one has a reverse type! */
B
Behdad Esfahbod 已提交
1287 1288 1289 1290
      unsigned int type = get_subtable (0).u.extension.get_type ();
      unsigned int count = get_subtable_count ();
      for (unsigned int i = 1; i < count; i++)
        if (get_subtable (i).u.extension.get_type () != type)
B
Behdad Esfahbod 已提交
1291
	  return_trace (false);
B
Behdad Esfahbod 已提交
1292
    }
B
Behdad Esfahbod 已提交
1293
    return_trace (true);
B
Behdad Esfahbod 已提交
1294
  }
B
Behdad Esfahbod 已提交
1295 1296
};

B
Behdad Esfahbod 已提交
1297
typedef OffsetListOf<SubstLookup> SubstLookupList;
1298

B
Minor  
Behdad Esfahbod 已提交
1299
/*
1300 1301
 * GSUB -- Glyph Substitution
 * https://docs.microsoft.com/en-us/typography/opentype/spec/gsub
B
Minor  
Behdad Esfahbod 已提交
1302 1303
 */

B
Behdad Esfahbod 已提交
1304 1305
struct GSUB : GSUBGPOS
{
1306
  static const hb_tag_t tableTag	= HB_OT_TAG_GSUB;
B
Minor  
Behdad Esfahbod 已提交
1307

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

1311
  inline bool subset (hb_subset_context_t *c)
1312 1313
  {
    TRACE_SUBSET (this);
1314
    struct GSUB *out = c->serializer->start_embed<GSUB> ();
1315 1316 1317 1318 1319
    //XXX if (unlikely (!GSUBGPOS::subset (c))) return_trace (false);
    return_trace (true);
  }


B
Behdad Esfahbod 已提交
1320 1321
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1322
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1323
    if (unlikely (!GSUBGPOS::sanitize (c))) return_trace (false);
B
Behdad Esfahbod 已提交
1324
    const OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
B
Behdad Esfahbod 已提交
1325
    return_trace (list.sanitize (c, this));
B
Behdad Esfahbod 已提交
1326
  }
B
WIP  
Behdad Esfahbod 已提交
1327 1328

  typedef GSUBGPOS::accelerator_t<GSUB> accelerator_t;
B
Minor  
Behdad Esfahbod 已提交
1329
};
1330 1331


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

1334
/*static*/ inline bool ExtensionSubst::is_reverse (void) const
B
Behdad Esfahbod 已提交
1335 1336
{
  unsigned int type = get_type ();
1337
  if (unlikely (type == SubstLookupSubTable::Extension))
1338
    return CastR<ExtensionSubst> (get_subtable<LookupSubTable>()).is_reverse ();
B
Behdad Esfahbod 已提交
1339 1340 1341
  return SubstLookup::lookup_type_is_reverse (type);
}

1342
template <typename context_t>
1343
/*static*/ inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
1344
{
1345
  const SubstLookup &l = _get_gsub_relaxed (c->face).get_lookup (lookup_index);
1346
  return l.dispatch (c);
1347 1348
}

1349
/*static*/ inline bool SubstLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index)
B
Behdad Esfahbod 已提交
1350
{
1351
  const SubstLookup &l = _get_gsub_relaxed (c->face).get_lookup (lookup_index);
1352
  unsigned int saved_lookup_props = c->lookup_props;
1353 1354 1355
  unsigned int saved_lookup_index = c->lookup_index;
  c->set_lookup_index (lookup_index);
  c->set_lookup_props (l.get_props ());
1356
  bool ret = l.dispatch (c);
1357
  c->set_lookup_index (saved_lookup_index);
1358
  c->set_lookup_props (saved_lookup_props);
1359
  return ret;
1360 1361
}

1362
struct GSUB_accelerator_t : GSUB::accelerator_t {};
1363

B
Behdad Esfahbod 已提交
1364
} /* namespace OT */
1365

B
Behdad Esfahbod 已提交
1366

1367
#endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */