hb-ot-layout-gsub-table.hh 42.2 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
typedef hb_pair_t<hb_codepoint_t, hb_codepoint_t> hb_codepoint_pair_t;
38

B
Behdad Esfahbod 已提交
39
template<typename Iterator>
40
static inline void SingleSubst_serialize (hb_serialize_context_t *c,
41 42
					  Iterator it);

43

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

49
  void closure (hb_closure_context_t *c) const
50
  {
B
Behdad Esfahbod 已提交
51
    unsigned d = deltaGlyphID;
52 53
    + hb_iter (this+coverage)
    | hb_filter (*c->glyphs)
B
Behdad Esfahbod 已提交
54
    | hb_map ([d] (hb_codepoint_t g) { return (g + d) & 0xFFFFu; })
55 56
    | hb_sink (c->output)
    ;
57 58
  }

59
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
60
  {
61
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
B
Behdad Esfahbod 已提交
62
    unsigned d = deltaGlyphID;
63
    + hb_iter (this+coverage)
B
Behdad Esfahbod 已提交
64
    | hb_map ([d] (hb_codepoint_t g) { return (g + d) & 0xFFFFu; })
65 66
    | hb_sink (c->output)
    ;
67 68
  }

69
  const Coverage &get_coverage () const { return this+coverage; }
70

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

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

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

B
Behdad Esfahbod 已提交
86
    return_trace (true);
87
  }
B
Behdad Esfahbod 已提交
88

89
  template<typename Iterator,
B
Behdad Esfahbod 已提交
90 91
	   hb_requires (hb_is_sorted_source_of (Iterator,
						hb_codepoint_t))>
92
  bool serialize (hb_serialize_context_t *c,
93
		  Iterator glyphs,
94
		  unsigned delta)
95
  {
B
Behdad Esfahbod 已提交
96
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
97
    if (unlikely (!c->extend_min (*this))) return_trace (false);
B
Behdad Esfahbod 已提交
98
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs))) return_trace (false);
99
    c->check_assign (deltaGlyphID, delta);
B
Behdad Esfahbod 已提交
100
    return_trace (true);
101 102
  }

103
  bool subset (hb_subset_context_t *c) const
104 105
  {
    TRACE_SUBSET (this);
106
    const hb_set_t &glyphset = *c->plan->glyphset ();
107
    const hb_map_t &glyph_map = *c->plan->glyph_map;
108

109
    hb_codepoint_t delta = deltaGlyphID;
110

111
    auto it =
112 113
    + hb_iter (this+coverage)
    | hb_filter (glyphset)
114 115 116 117
    | hb_map_retains_sorting ([&] (hb_codepoint_t g) {
                                return hb_codepoint_pair_t (glyph_map[g],
                                                            glyph_map[(g + delta) & 0xFFFF]); })
    ;
118

119
    bool ret = bool (it);
120
    SingleSubst_serialize (c->serializer, it);
121
    return_trace (ret);
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 */
135 136
  HBUINT16	deltaGlyphID;		/* Add to original GlyphID to get
					 * substitute GlyphID, modulo 0x10000 */
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
  {
B
Behdad Esfahbod 已提交
148 149 150
    + hb_zip (this+coverage, substitute)
    | hb_filter (*c->glyphs, hb_first)
    | hb_map (hb_second)
151
    | hb_sink (c->output)
152
    ;
153 154
  }

155
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
156
  {
157
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
B
Behdad Esfahbod 已提交
158 159
    + hb_zip (this+coverage, substitute)
    | hb_map (hb_second)
160
    | hb_sink (c->output)
161
    ;
162 163
  }

164
  const Coverage &get_coverage () const { return this+coverage; }
165

166
  bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
167
  { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
168

169
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
170
  {
B
Behdad Esfahbod 已提交
171
    TRACE_APPLY (this);
172
    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
B
Behdad Esfahbod 已提交
173
    if (likely (index == NOT_COVERED)) return_trace (false);
174

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

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

B
Behdad Esfahbod 已提交
179
    return_trace (true);
180
  }
B
Behdad Esfahbod 已提交
181

182
  template<typename Iterator,
B
Behdad Esfahbod 已提交
183 184
	   hb_requires (hb_is_sorted_source_of (Iterator,
						const hb_codepoint_pair_t))>
185
  bool serialize (hb_serialize_context_t *c,
186
		  Iterator it)
B
Behdad Esfahbod 已提交
187
  {
B
Behdad Esfahbod 已提交
188
    TRACE_SERIALIZE (this);
189 190 191 192 193 194 195 196
    auto substitutes =
      + it
      | hb_map (hb_second)
      ;
    auto glyphs =
      + it
      | hb_map_retains_sorting (hb_first)
      ;
B
Behdad Esfahbod 已提交
197
    if (unlikely (!c->extend_min (*this))) return_trace (false);
B
Behdad Esfahbod 已提交
198 199
    if (unlikely (!substitute.serialize (c, substitutes))) return_trace (false);
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs))) return_trace (false);
B
Behdad Esfahbod 已提交
200
    return_trace (true);
B
Behdad Esfahbod 已提交
201 202
  }

203
  bool subset (hb_subset_context_t *c) const
204 205
  {
    TRACE_SUBSET (this);
206
    const hb_set_t &glyphset = *c->plan->glyphset ();
207
    const hb_map_t &glyph_map = *c->plan->glyph_map;
208

209
    auto it =
210 211
    + hb_zip (this+coverage, substitute)
    | hb_filter (glyphset, hb_first)
212 213 214
    | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const GlyphID &> p) -> hb_codepoint_pair_t
                              { return hb_pair (glyph_map[p.first], glyph_map[p.second]); })
    ;
215

216
    bool ret = bool (it);
217
    SingleSubst_serialize (c->serializer, it);
218
    return_trace (ret);
219 220
  }

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

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

B
Behdad Esfahbod 已提交
239 240
struct SingleSubst
{
241 242

  template<typename Iterator,
B
Behdad Esfahbod 已提交
243 244
	   hb_requires (hb_is_sorted_source_of (Iterator,
						const hb_codepoint_pair_t))>
245
  bool serialize (hb_serialize_context_t *c,
246
		  Iterator glyphs)
B
Behdad Esfahbod 已提交
247
  {
B
Behdad Esfahbod 已提交
248
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
249
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
B
Behdad Esfahbod 已提交
250 251
    unsigned format = 2;
    unsigned delta = 0;
252
    if (glyphs.len ())
B
Behdad Esfahbod 已提交
253
    {
B
Behdad Esfahbod 已提交
254
      format = 1;
255 256 257 258 259
      auto get_delta = [=] (hb_codepoint_pair_t _) {
			 return (unsigned) (_.second - _.first) & 0xFFFF;
		       };
      delta = get_delta (*glyphs);
      if (!hb_all (++(+glyphs), delta, get_delta)) format = 2;
B
Behdad Esfahbod 已提交
260
    }
261
    u.format = format;
B
Behdad Esfahbod 已提交
262
    switch (u.format) {
263 264 265 266 267
    case 1: return_trace (u.format1.serialize (c,
                                               + glyphs
                                               | hb_map_retains_sorting (hb_first),
                                               delta));
    case 2: return_trace (u.format2.serialize (c, glyphs));
B
Behdad Esfahbod 已提交
268
    default:return_trace (false);
B
Behdad Esfahbod 已提交
269 270 271
    }
  }

272
  template <typename context_t, typename ...Ts>
B
Behdad Esfahbod 已提交
273
  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
B
Behdad Esfahbod 已提交
274
  {
275
    TRACE_DISPATCH (this, u.format);
276
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
277
    switch (u.format) {
278 279
    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
    case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
B
Behdad Esfahbod 已提交
280
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
281 282 283
    }
  }

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

B
Behdad Esfahbod 已提交
292
template<typename Iterator>
293 294
static inline void
SingleSubst_serialize (hb_serialize_context_t *c,
295 296
		       Iterator it)
{ c->start_embed<SingleSubst> ()->serialize (c, it); }
B
Behdad Esfahbod 已提交
297

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

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

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

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

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

B
Behdad Esfahbod 已提交
339
    return_trace (true);
B
Behdad Esfahbod 已提交
340 341
  }

342
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
343
		  hb_array_t<const GlyphID> subst)
344
  {
B
Behdad Esfahbod 已提交
345
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
346
    return_trace (substitute.serialize (c, subst));
347 348
  }

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

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

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

367
  void closure (hb_closure_context_t *c) const
368
  {
369 370 371
    + hb_zip (this+coverage, sequence)
    | hb_filter (*c->glyphs, hb_first)
    | hb_map (hb_second)
372 373
    | hb_map (hb_add (this))
    | hb_apply ([c] (const Sequence &_) { _.closure (c); })
374
    ;
375 376
  }

377
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
378
  {
379
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
380 381
    + hb_zip (this+coverage, sequence)
    | hb_map (hb_second)
382 383
    | hb_map (hb_add (this))
    | hb_apply ([c] (const Sequence &_) { _.collect_glyphs (c); })
384
    ;
385 386
  }

387
  const Coverage &get_coverage () const { return this+coverage; }
388

389
  bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
390
  { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
391

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

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

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

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

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

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

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

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

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

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

481 482
struct AlternateSet
{
483
  void closure (hb_closure_context_t *c) const
484 485 486
  {
    unsigned int count = alternates.len;
    for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
487
      c->output->add (alternates[i]);
488 489
  }

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

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

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

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

503 504 505
    /* 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);
506

507
    /* If alt_index is MAX_VALUE, randomize feature if it is the rand feature. */
508
    if (alt_index == HB_OT_MAP_MAX_VALUE && c->random)
B
Behdad Esfahbod 已提交
509
      alt_index = c->random_number () % count + 1;
B
Behdad Esfahbod 已提交
510

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

513 514
    c->replace_glyph (alternates[alt_index - 1]);

515 516 517
    return_trace (true);
  }

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

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

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

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

544
  void closure (hb_closure_context_t *c) const
545
  {
546 547
    + hb_zip (this+coverage, alternateSet)
    | hb_map (hb_second)
548 549
    | hb_map (hb_add (this))
    | hb_apply ([c] (const AlternateSet &_) { _.closure (c); })
550
    ;
551 552
  }

553
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
554
  {
555
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
556 557
    + hb_zip (this+coverage, alternateSet)
    | hb_map (hb_second)
558 559
    | hb_map (hb_add (this))
    | hb_apply ([c] (const AlternateSet &_) { _.collect_glyphs (c); })
560
    ;
561 562
  }

563
  const Coverage &get_coverage () const { return this+coverage; }
564

565
  bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
566
  { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
567

568
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
569
  {
B
Behdad Esfahbod 已提交
570
    TRACE_APPLY (this);
571

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

575
    return_trace ((this+alternateSet[index]).apply (c));
576
  }
B
Behdad Esfahbod 已提交
577

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

597
  bool subset (hb_subset_context_t *c) const
598 599 600 601 602 603
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

604
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
605
  {
B
Behdad Esfahbod 已提交
606
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
607
    return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
608 609
  }

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

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

639
  template <typename context_t, typename ...Ts>
B
Behdad Esfahbod 已提交
640
  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
B
Behdad Esfahbod 已提交
641
  {
642
    TRACE_DISPATCH (this, u.format);
643
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
644
    switch (u.format) {
645
    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
B
Behdad Esfahbod 已提交
646
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
647 648 649
    }
  }

650
  protected:
651
  union {
B
Behdad Esfahbod 已提交
652
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
653
  AlternateSubstFormat1	format1;
654 655 656
  } u;
};

657

B
Behdad Esfahbod 已提交
658 659
struct Ligature
{
660
  bool intersects (const hb_set_t *glyphs) const
661
  {
662
    unsigned int count = component.lenP1;
663 664 665 666 667 668
    for (unsigned int i = 1; i < count; i++)
      if (!glyphs->has (component[i]))
        return false;
    return true;
  }

669
  void closure (hb_closure_context_t *c) const
670
  {
B
Behdad Esfahbod 已提交
671
    if (!intersects (c->glyphs)) return;
B
Behdad Esfahbod 已提交
672
    c->output->add (ligGlyph);
673 674
  }

675
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
676
  {
677
    c->input->add_array (component.arrayZ, component.lenP1 ? component.lenP1 - 1 : 0);
B
Minor  
Behdad Esfahbod 已提交
678
    c->output->add (ligGlyph);
679 680
  }

681
  bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
682
  {
683
    if (c->len != component.lenP1)
B
Behdad Esfahbod 已提交
684
      return false;
685 686 687

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

B
Behdad Esfahbod 已提交
690
    return true;
B
Behdad Esfahbod 已提交
691 692
  }

693
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
694
  {
B
Behdad Esfahbod 已提交
695
    TRACE_APPLY (this);
696
    unsigned int count = component.lenP1;
B
Behdad Esfahbod 已提交
697

B
Behdad Esfahbod 已提交
698
    if (unlikely (!count)) return_trace (false);
B
Behdad Esfahbod 已提交
699

700 701 702 703 704
    /* 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 已提交
705
      return_trace (true);
706 707
    }

B
Behdad Esfahbod 已提交
708
    unsigned int total_component_count = 0;
709

710
    unsigned int match_length = 0;
711
    unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
712

713 714 715
    if (likely (!match_input (c, count,
			      &component[1],
			      match_glyph,
B
Behdad Esfahbod 已提交
716
			      nullptr,
717 718
			      &match_length,
			      match_positions,
719
			      &total_component_count)))
B
Behdad Esfahbod 已提交
720
      return_trace (false);
721

722 723
    ligate_input (c,
		  count,
724 725
		  match_positions,
		  match_length,
726
		  ligGlyph,
727
		  total_component_count);
728

B
Behdad Esfahbod 已提交
729
    return_trace (true);
730
  }
731

732 733
  bool serialize (hb_serialize_context_t *c,
		  GlyphID ligature,
B
Behdad Esfahbod 已提交
734
		  hb_array_t<const GlyphID> components /* Starting from second */)
735
  {
B
Behdad Esfahbod 已提交
736
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
737
    if (unlikely (!c->extend_min (*this))) return_trace (false);
738
    ligGlyph = ligature;
B
Behdad Esfahbod 已提交
739
    if (unlikely (!component.serialize (c, components))) return_trace (false);
B
Behdad Esfahbod 已提交
740
    return_trace (true);
741 742
  }

B
Behdad Esfahbod 已提交
743
  public:
744
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
745
  {
B
Behdad Esfahbod 已提交
746
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
747
    return_trace (ligGlyph.sanitize (c) && component.sanitize (c));
B
Behdad Esfahbod 已提交
748 749
  }

750
  protected:
751
  GlyphID	ligGlyph;		/* GlyphID of ligature to substitute */
B
Behdad Esfahbod 已提交
752 753
  HeadlessArrayOf<GlyphID>
		component;		/* Array of component GlyphIDs--start
754 755
					 * with the second  component--ordered
					 * in writing direction */
756
  public:
757
  DEFINE_SIZE_ARRAY (4, component);
758
};
B
Behdad Esfahbod 已提交
759

B
Behdad Esfahbod 已提交
760 761
struct LigatureSet
{
762
  bool intersects (const hb_set_t *glyphs) const
763
  {
B
Behdad Esfahbod 已提交
764 765
    return
    + hb_iter (ligature)
766 767
    | hb_map (hb_add (this))
    | hb_map ([glyphs] (const Ligature &_) { return _.intersects (glyphs); })
B
Behdad Esfahbod 已提交
768 769
    | hb_any
    ;
770 771
  }

772
  void closure (hb_closure_context_t *c) const
773
  {
B
Behdad Esfahbod 已提交
774
    + hb_iter (ligature)
775 776
    | hb_map (hb_add (this))
    | hb_apply ([c] (const Ligature &_) { _.closure (c); })
B
Behdad Esfahbod 已提交
777
    ;
778 779
  }

780
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
781
  {
B
Behdad Esfahbod 已提交
782
    + hb_iter (ligature)
783 784
    | hb_map (hb_add (this))
    | hb_apply ([c] (const Ligature &_) { _.collect_glyphs (c); })
B
Behdad Esfahbod 已提交
785
    ;
786 787
  }

788
  bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
789
  {
B
Behdad Esfahbod 已提交
790 791
    return
    + hb_iter (ligature)
792 793
    | hb_map (hb_add (this))
    | hb_map ([c] (const Ligature &_) { return _.would_apply (c); })
B
Behdad Esfahbod 已提交
794 795
    | hb_any
    ;
B
Behdad Esfahbod 已提交
796 797
  }

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

B
Behdad Esfahbod 已提交
808
    return_trace (false);
809
  }
B
Behdad Esfahbod 已提交
810

811
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
812 813
		  hb_array_t<const GlyphID> ligatures,
		  hb_array_t<const unsigned int> component_count_list,
814
		  hb_array_t<const GlyphID> &component_list /* Starting from second for each ligature */)
815
  {
B
Behdad Esfahbod 已提交
816
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
817
    if (unlikely (!c->extend_min (*this))) return_trace (false);
818 819
    if (unlikely (!ligature.serialize (c, ligatures.length))) return_trace (false);
    for (unsigned int i = 0; i < ligatures.length; i++)
B
Behdad Esfahbod 已提交
820
    {
821
      unsigned int component_count = (unsigned) hb_max ((int) component_count_list[i] - 1, 0);
B
Behdad Esfahbod 已提交
822 823 824 825 826 827 828
      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 已提交
829
    return_trace (true);
830 831
  }

832
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
833
  {
B
Behdad Esfahbod 已提交
834
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
835
    return_trace (ligature.sanitize (c, this));
B
Behdad Esfahbod 已提交
836 837
  }

838
  protected:
B
Behdad Esfahbod 已提交
839 840 841
  OffsetArrayOf<Ligature>
		ligature;		/* Array LigatureSet tables
					 * ordered by preference */
842
  public:
843
  DEFINE_SIZE_ARRAY (2, ligature);
B
Behdad Esfahbod 已提交
844 845
};

B
Behdad Esfahbod 已提交
846 847
struct LigatureSubstFormat1
{
848
  bool intersects (const hb_set_t *glyphs) const
849
  {
850 851 852 853
    return
    + hb_zip (this+coverage, ligatureSet)
    | hb_filter (*glyphs, hb_first)
    | hb_map (hb_second)
B
Behdad Esfahbod 已提交
854
    | hb_map ([this, glyphs] (const OffsetTo<LigatureSet> &_)
855 856 857
	      { return (this+_).intersects (glyphs); })
    | hb_any
    ;
858 859
  }

860
  void closure (hb_closure_context_t *c) const
861
  {
862 863 864
    + hb_zip (this+coverage, ligatureSet)
    | hb_filter (*c->glyphs, hb_first)
    | hb_map (hb_second)
865 866
    | hb_map (hb_add (this))
    | hb_apply ([c] (const LigatureSet &_) { _.closure (c); })
867
    ;
868 869
  }

870
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
871
  {
872
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
B
Behdad Esfahbod 已提交
873

874 875
    + hb_zip (this+coverage, ligatureSet)
    | hb_map (hb_second)
876 877
    | hb_map (hb_add (this))
    | hb_apply ([c] (const LigatureSet &_) { _.collect_glyphs (c); })
878
    ;
879 880
  }

881
  const Coverage &get_coverage () const { return this+coverage; }
882

883
  bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
884
  {
885
    unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
B
Behdad Esfahbod 已提交
886
    if (likely (index == NOT_COVERED)) return false;
887 888

    const LigatureSet &lig_set = this+ligatureSet[index];
B
Behdad Esfahbod 已提交
889
    return lig_set.would_apply (c);
B
Behdad Esfahbod 已提交
890 891
  }

892
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
893
  {
B
Behdad Esfahbod 已提交
894
    TRACE_APPLY (this);
895

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

B
Behdad Esfahbod 已提交
899
    const LigatureSet &lig_set = this+ligatureSet[index];
B
Behdad Esfahbod 已提交
900
    return_trace (lig_set.apply (c));
901
  }
B
Behdad Esfahbod 已提交
902

903
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
904
		  hb_sorted_array_t<const GlyphID> first_glyphs,
B
Behdad Esfahbod 已提交
905 906 907 908
		  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 */)
909
  {
B
Behdad Esfahbod 已提交
910
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
911
    if (unlikely (!c->extend_min (*this))) return_trace (false);
912 913
    if (unlikely (!ligatureSet.serialize (c, first_glyphs.length))) return_trace (false);
    for (unsigned int i = 0; i < first_glyphs.length; i++)
B
Behdad Esfahbod 已提交
914 915 916 917 918 919 920 921 922 923 924
    {
      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));
925 926
  }

927
  bool subset (hb_subset_context_t *c) const
928 929 930 931 932 933
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

934
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
935
  {
B
Behdad Esfahbod 已提交
936
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
937
    return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
938 939
  }

940
  protected:
B
Behdad Esfahbod 已提交
941
  HBUINT16	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
942 943
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
944
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
945
  OffsetArrayOf<LigatureSet>
B
Behdad Esfahbod 已提交
946 947
		ligatureSet;		/* Array LigatureSet tables
					 * ordered by Coverage Index */
948
  public:
949
  DEFINE_SIZE_ARRAY (6, ligatureSet);
B
Behdad Esfahbod 已提交
950
};
951

B
Behdad Esfahbod 已提交
952 953
struct LigatureSubst
{
954
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
955
		  hb_sorted_array_t<const GlyphID> first_glyphs,
B
Behdad Esfahbod 已提交
956 957 958 959
		  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 */)
960
  {
B
Behdad Esfahbod 已提交
961
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
962
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
963
    unsigned int format = 1;
964
    u.format = format;
965
    switch (u.format) {
B
Behdad Esfahbod 已提交
966 967 968 969 970 971 972
    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);
973 974 975
    }
  }

976
  template <typename context_t, typename ...Ts>
B
Behdad Esfahbod 已提交
977
  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
B
Behdad Esfahbod 已提交
978
  {
979
    TRACE_DISPATCH (this, u.format);
980
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
981
    switch (u.format) {
982
    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
B
Behdad Esfahbod 已提交
983
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
984 985 986
    }
  }

987
  protected:
988
  union {
B
Behdad Esfahbod 已提交
989
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
990
  LigatureSubstFormat1	format1;
991 992 993
  } u;
};

B
Behdad Esfahbod 已提交
994

B
Minor  
Behdad Esfahbod 已提交
995
struct ContextSubst : Context {};
B
Behdad Esfahbod 已提交
996

B
Minor  
Behdad Esfahbod 已提交
997
struct ChainContextSubst : ChainContext {};
998

B
Behdad Esfahbod 已提交
999
struct ExtensionSubst : Extension<ExtensionSubst>
B
Behdad Esfahbod 已提交
1000
{
B
Behdad Esfahbod 已提交
1001
  typedef struct SubstLookupSubTable SubTable;
B
Behdad Esfahbod 已提交
1002

1003
  bool is_reverse () const;
1004 1005 1006
};


B
Behdad Esfahbod 已提交
1007 1008
struct ReverseChainSingleSubstFormat1
{
1009
  bool intersects (const hb_set_t *glyphs) const
1010 1011 1012 1013
  {
    if (!(this+coverage).intersects (glyphs))
      return false;

1014
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030

    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;
  }

1031
  void closure (hb_closure_context_t *c) const
1032
  {
B
Behdad Esfahbod 已提交
1033
    if (!intersects (c->glyphs)) return;
B
Behdad Esfahbod 已提交
1034

1035 1036
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID>> (lookahead);
B
Behdad Esfahbod 已提交
1037

B
Behdad Esfahbod 已提交
1038 1039 1040
    + hb_zip (this+coverage, substitute)
    | hb_filter (*c->glyphs, hb_first)
    | hb_map (hb_second)
1041
    | hb_sink (c->output)
1042
    ;
1043 1044
  }

1045
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
1046
  {
1047
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
1048 1049 1050 1051 1052

    unsigned int count;

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

1055
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
1056 1057
    count = lookahead.len;
    for (unsigned int i = 0; i < count; i++)
1058
      if (unlikely (!(this+lookahead[i]).add_coverage (c->after))) return;
1059

1060
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID>> (lookahead);
1061
    count = substitute.len;
1062
    c->output->add_array (substitute.arrayZ, substitute.len);
1063 1064
  }

1065
  const Coverage &get_coverage () const { return this+coverage; }
1066

1067
  bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1068
  { return c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED; }
1069

1070
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1071
  {
B
Behdad Esfahbod 已提交
1072
    TRACE_APPLY (this);
1073
    if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
B
Behdad Esfahbod 已提交
1074
      return_trace (false); /* No chaining to this type */
1075

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

1079 1080
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID>> (lookahead);
1081

1082
  unsigned int start_index = 0, end_index = 0;
B
Behdad Esfahbod 已提交
1083
    if (match_backtrack (c,
1084
			 backtrack.len, (HBUINT16 *) backtrack.arrayZ,
1085 1086
			 match_coverage, this,
			 &start_index) &&
B
Behdad Esfahbod 已提交
1087
        match_lookahead (c,
1088
			 lookahead.len, (HBUINT16 *) lookahead.arrayZ,
B
Behdad Esfahbod 已提交
1089
			 match_coverage, this,
1090
			 1, &end_index))
1091
    {
1092
      c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index);
B
Behdad Esfahbod 已提交
1093
      c->replace_glyph_inplace (substitute[index]);
1094 1095 1096
      /* 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 已提交
1097
      return_trace (true);
1098 1099
    }

B
Behdad Esfahbod 已提交
1100
    return_trace (false);
1101
  }
B
Behdad Esfahbod 已提交
1102

1103
  bool subset (hb_subset_context_t *c) const
1104 1105 1106 1107 1108 1109
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

1110
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
1111
  {
B
Behdad Esfahbod 已提交
1112
    TRACE_SANITIZE (this);
1113
    if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
B
Behdad Esfahbod 已提交
1114
      return_trace (false);
1115
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
B
Behdad Esfahbod 已提交
1116
    if (!lookahead.sanitize (c, this))
B
Behdad Esfahbod 已提交
1117
      return_trace (false);
1118
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID>> (lookahead);
B
Behdad Esfahbod 已提交
1119
    return_trace (substitute.sanitize (c));
B
Behdad Esfahbod 已提交
1120 1121
  }

1122
  protected:
B
Behdad Esfahbod 已提交
1123
  HBUINT16	format;			/* Format identifier--format = 1 */
1124 1125 1126 1127 1128
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of table */
  OffsetArrayOf<Coverage>
		backtrack;		/* Array of coverage tables
1129
					 * in backtracking sequence, in glyph
B
Behdad Esfahbod 已提交
1130
					 * sequence order */
1131 1132 1133
  OffsetArrayOf<Coverage>
		lookaheadX;		/* Array of coverage tables
					 * in lookahead sequence, in glyph
B
Behdad Esfahbod 已提交
1134
					 * sequence order */
1135 1136 1137
  ArrayOf<GlyphID>
		substituteX;		/* Array of substitute
					 * GlyphIDs--ordered by Coverage Index */
1138
  public:
B
Behdad Esfahbod 已提交
1139
  DEFINE_SIZE_MIN (10);
B
Behdad Esfahbod 已提交
1140 1141
};

B
Behdad Esfahbod 已提交
1142 1143
struct ReverseChainSingleSubst
{
1144
  template <typename context_t, typename ...Ts>
B
Behdad Esfahbod 已提交
1145
  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
1146
  {
1147
    TRACE_DISPATCH (this, u.format);
1148
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1149
    switch (u.format) {
1150
    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
B
Behdad Esfahbod 已提交
1151
    default:return_trace (c->default_return_value ());
1152 1153 1154
    }
  }

1155
  protected:
1156
  union {
B
Behdad Esfahbod 已提交
1157
  HBUINT16				format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1158
  ReverseChainSingleSubstFormat1	format1;
1159 1160 1161 1162 1163
  } u;
};



B
Behdad Esfahbod 已提交
1164 1165 1166 1167
/*
 * SubstLookup
 */

B
Behdad Esfahbod 已提交
1168 1169
struct SubstLookupSubTable
{
B
Behdad Esfahbod 已提交
1170
  friend struct Lookup;
B
Behdad Esfahbod 已提交
1171 1172
  friend struct SubstLookup;

B
Behdad Esfahbod 已提交
1173
  enum Type {
1174 1175 1176 1177 1178 1179 1180
    Single		= 1,
    Multiple		= 2,
    Alternate		= 3,
    Ligature		= 4,
    Context		= 5,
    ChainContext	= 6,
    Extension		= 7,
1181
    ReverseChainSingle	= 8
1182 1183
  };

1184
  template <typename context_t, typename ...Ts>
B
Behdad Esfahbod 已提交
1185
  typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type, Ts&&... ds) const
1186
  {
1187
    TRACE_DISPATCH (this, lookup_type);
1188
    switch (lookup_type) {
1189 1190 1191 1192 1193 1194 1195 1196
    case Single:		return_trace (u.single.dispatch (c, hb_forward<Ts> (ds)...));
    case Multiple:		return_trace (u.multiple.dispatch (c, hb_forward<Ts> (ds)...));
    case Alternate:		return_trace (u.alternate.dispatch (c, hb_forward<Ts> (ds)...));
    case Ligature:		return_trace (u.ligature.dispatch (c, hb_forward<Ts> (ds)...));
    case Context:		return_trace (u.context.dispatch (c, hb_forward<Ts> (ds)...));
    case ChainContext:		return_trace (u.chainContext.dispatch (c, hb_forward<Ts> (ds)...));
    case Extension:		return_trace (u.extension.dispatch (c, hb_forward<Ts> (ds)...));
    case ReverseChainSingle:	return_trace (u.reverseChainContextSingle.dispatch (c, hb_forward<Ts> (ds)...));
B
Behdad Esfahbod 已提交
1197
    default:			return_trace (c->default_return_value ());
1198 1199 1200
    }
  }

1201
  protected:
B
Behdad Esfahbod 已提交
1202
  union {
B
Behdad Esfahbod 已提交
1203 1204 1205 1206
  SingleSubst			single;
  MultipleSubst			multiple;
  AlternateSubst		alternate;
  LigatureSubst			ligature;
1207
  ContextSubst			context;
B
Behdad Esfahbod 已提交
1208 1209 1210
  ChainContextSubst		chainContext;
  ExtensionSubst		extension;
  ReverseChainSingleSubst	reverseChainContextSingle;
B
Behdad Esfahbod 已提交
1211
  } u;
B
Behdad Esfahbod 已提交
1212
  public:
B
Behdad Esfahbod 已提交
1213
  DEFINE_SIZE_MIN (0);
B
Behdad Esfahbod 已提交
1214 1215
};

1216

B
Behdad Esfahbod 已提交
1217 1218
struct SubstLookup : Lookup
{
B
Behdad Esfahbod 已提交
1219 1220
  typedef SubstLookupSubTable SubTable;

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

B
Behdad Esfahbod 已提交
1224
  HB_INTERNAL static bool lookup_type_is_reverse (unsigned int lookup_type)
B
Behdad Esfahbod 已提交
1225
  { return lookup_type == SubTable::ReverseChainSingle; }
B
Behdad Esfahbod 已提交
1226

1227
  bool is_reverse () const
B
Behdad Esfahbod 已提交
1228
  {
B
Behdad Esfahbod 已提交
1229
    unsigned int type = get_type ();
B
Behdad Esfahbod 已提交
1230
    if (unlikely (type == SubTable::Extension))
1231
      return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
B
Behdad Esfahbod 已提交
1232
    return lookup_type_is_reverse (type);
B
Behdad Esfahbod 已提交
1233
  }
1234

1235
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1236 1237
  {
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
1238
    return_trace (dispatch (c));
B
Behdad Esfahbod 已提交
1239 1240
  }

1241
  bool intersects (const hb_set_t *glyphs) const
1242 1243 1244 1245 1246
  {
    hb_intersects_context_t c (glyphs);
    return dispatch (&c);
  }

1247
  hb_closure_context_t::return_t closure (hb_closure_context_t *c, unsigned int this_index) const
1248
  {
1249
    if (!c->should_visit_lookup (this_index))
B
Behdad Esfahbod 已提交
1250
      return hb_closure_context_t::default_return_value ();
1251 1252

    c->set_recurse_func (dispatch_closure_recurse_func);
1253 1254 1255 1256 1257

    hb_closure_context_t::return_t ret = dispatch (c);

    c->flush ();

B
Behdad Esfahbod 已提交
1258
    return ret;
B
Behdad Esfahbod 已提交
1259 1260
  }

1261
  hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
B
Behdad Esfahbod 已提交
1262
  {
1263
    c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
B
Behdad Esfahbod 已提交
1264
    return dispatch (c);
1265 1266
  }

B
Behdad Esfahbod 已提交
1267
  template <typename set_t>
1268
  void add_coverage (set_t *glyphs) const
B
Behdad Esfahbod 已提交
1269
  {
1270 1271
    hb_add_coverage_context_t<set_t> c (glyphs);
    dispatch (&c);
B
Behdad Esfahbod 已提交
1272 1273
  }

1274 1275
  bool would_apply (hb_would_apply_context_t *c,
		    const hb_ot_layout_lookup_accelerator_t *accel) const
B
Behdad Esfahbod 已提交
1276
  {
B
Behdad Esfahbod 已提交
1277 1278 1279
    if (unlikely (!c->len)) return false;
    if (!accel->may_have (c->glyphs[0])) return false;
      return dispatch (c);
B
Behdad Esfahbod 已提交
1280 1281
  }

B
Behdad Esfahbod 已提交
1282
  HB_INTERNAL static bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index);
B
Behdad Esfahbod 已提交
1283

1284
  SubTable& serialize_subtable (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
1285 1286
				       unsigned int i)
  { return get_subtables<SubTable> ()[i].serialize (c, this); }
1287

1288 1289
  bool serialize_single (hb_serialize_context_t *c,
			 uint32_t lookup_props,
B
Behdad Esfahbod 已提交
1290
		         hb_sorted_array_t<const GlyphID> glyphs,
B
Behdad Esfahbod 已提交
1291
		         hb_array_t<const GlyphID> substitutes)
1292
  {
B
Behdad Esfahbod 已提交
1293
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1294
    if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false);
1295 1296 1297

    return_trace (serialize_subtable (c, 0).u.single
		  .serialize (c, hb_zip (glyphs, substitutes)));
1298 1299
  }

1300 1301
  bool serialize_multiple (hb_serialize_context_t *c,
			   uint32_t lookup_props,
B
Behdad Esfahbod 已提交
1302
			   hb_sorted_array_t<const GlyphID> glyphs,
B
Behdad Esfahbod 已提交
1303 1304
			   hb_array_t<const unsigned int> substitute_len_list,
			   hb_array_t<const GlyphID> substitute_glyphs_list)
1305
  {
B
Behdad Esfahbod 已提交
1306
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1307
    if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1308 1309 1310 1311
    return_trace (serialize_subtable (c, 0).u.multiple.serialize (c,
								  glyphs,
								  substitute_len_list,
								  substitute_glyphs_list));
1312 1313
  }

1314 1315
  bool serialize_alternate (hb_serialize_context_t *c,
			    uint32_t lookup_props,
B
Behdad Esfahbod 已提交
1316
			    hb_sorted_array_t<const GlyphID> glyphs,
B
Behdad Esfahbod 已提交
1317 1318
			    hb_array_t<const unsigned int> alternate_len_list,
			    hb_array_t<const GlyphID> alternate_glyphs_list)
1319
  {
B
Behdad Esfahbod 已提交
1320
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1321
    if (unlikely (!Lookup::serialize (c, SubTable::Alternate, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1322 1323 1324 1325
    return_trace (serialize_subtable (c, 0).u.alternate.serialize (c,
								   glyphs,
								   alternate_len_list,
								   alternate_glyphs_list));
1326 1327
  }

1328 1329
  bool serialize_ligature (hb_serialize_context_t *c,
			   uint32_t lookup_props,
B
Behdad Esfahbod 已提交
1330
			   hb_sorted_array_t<const GlyphID> first_glyphs,
B
Behdad Esfahbod 已提交
1331 1332 1333 1334
			   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 */)
1335
  {
B
Behdad Esfahbod 已提交
1336
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1337
    if (unlikely (!Lookup::serialize (c, SubTable::Ligature, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1338 1339 1340 1341 1342 1343
    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));
1344 1345
  }

B
Behdad Esfahbod 已提交
1346
  template <typename context_t>
B
Behdad Esfahbod 已提交
1347
  HB_INTERNAL static typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
B
Behdad Esfahbod 已提交
1348

B
Behdad Esfahbod 已提交
1349
  HB_INTERNAL static hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned int lookup_index)
1350
  {
1351
    if (!c->should_visit_lookup (lookup_index))
B
Behdad Esfahbod 已提交
1352
      return hb_empty_t ();
1353 1354 1355

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

1356 1357 1358 1359
    /* 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 ();
1360 1361

    return ret;
1362 1363
  }

1364
  template <typename context_t, typename ...Ts>
B
Behdad Esfahbod 已提交
1365
  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
1366
  { return Lookup::dispatch<SubTable> (c, hb_forward<Ts> (ds)...); }
B
Behdad Esfahbod 已提交
1367

1368
  bool subset (hb_subset_context_t *c) const
1369
  { return Lookup::subset<SubTable> (c); }
B
Behdad Esfahbod 已提交
1370

1371
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
1372
  { return Lookup::sanitize<SubTable> (c); }
B
Behdad Esfahbod 已提交
1373 1374
};

B
Minor  
Behdad Esfahbod 已提交
1375
/*
1376 1377
 * GSUB -- Glyph Substitution
 * https://docs.microsoft.com/en-us/typography/opentype/spec/gsub
B
Minor  
Behdad Esfahbod 已提交
1378 1379
 */

B
Behdad Esfahbod 已提交
1380 1381
struct GSUB : GSUBGPOS
{
1382
  static constexpr hb_tag_t tableTag = HB_OT_TAG_GSUB;
B
Minor  
Behdad Esfahbod 已提交
1383

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

1387
  bool subset (hb_subset_context_t *c) const
1388
  { return GSUBGPOS::subset<SubstLookup> (c); }
1389

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

1393 1394 1395
  HB_INTERNAL bool is_blacklisted (hb_blob_t *blob,
				   hb_face_t *face) const;

B
WIP  
Behdad Esfahbod 已提交
1396
  typedef GSUBGPOS::accelerator_t<GSUB> accelerator_t;
B
Minor  
Behdad Esfahbod 已提交
1397
};
1398 1399


B
Behdad Esfahbod 已提交
1400 1401 1402
struct GSUB_accelerator_t : GSUB::accelerator_t {};


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

1405
/*static*/ inline bool ExtensionSubst::is_reverse () const
B
Behdad Esfahbod 已提交
1406 1407
{
  unsigned int type = get_type ();
B
Behdad Esfahbod 已提交
1408 1409
  if (unlikely (type == SubTable::Extension))
    return CastR<ExtensionSubst> (get_subtable<SubTable>()).is_reverse ();
B
Behdad Esfahbod 已提交
1410 1411 1412
  return SubstLookup::lookup_type_is_reverse (type);
}

1413
template <typename context_t>
1414
/*static*/ inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
1415
{
B
Behdad Esfahbod 已提交
1416
  const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index);
1417
  return l.dispatch (c);
1418 1419
}

1420
/*static*/ inline bool SubstLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index)
B
Behdad Esfahbod 已提交
1421
{
B
Behdad Esfahbod 已提交
1422
  const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index);
1423
  unsigned int saved_lookup_props = c->lookup_props;
1424 1425 1426
  unsigned int saved_lookup_index = c->lookup_index;
  c->set_lookup_index (lookup_index);
  c->set_lookup_props (l.get_props ());
1427
  bool ret = l.dispatch (c);
1428
  c->set_lookup_index (saved_lookup_index);
1429
  c->set_lookup_props (saved_lookup_props);
1430
  return ret;
1431 1432
}

B
Behdad Esfahbod 已提交
1433
} /* namespace OT */
1434

B
Behdad Esfahbod 已提交
1435

1436
#endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */