hb-ot-layout-gsub-table.hh 42.1 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 120
    SingleSubst_serialize (c->serializer, it);
    return_trace (it.len ());
121 122
  }

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

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

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

145
  void closure (hb_closure_context_t *c) const
146
  {
B
Behdad Esfahbod 已提交
147 148 149
    + hb_zip (this+coverage, substitute)
    | hb_filter (*c->glyphs, hb_first)
    | hb_map (hb_second)
150
    | hb_sink (c->output)
151
    ;
152 153
  }

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

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

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

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

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

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

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

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

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

208
    auto it =
209 210
    + hb_zip (this+coverage, substitute)
    | hb_filter (glyphset, hb_first)
211 212 213
    | 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]); })
    ;
214

215 216
    SingleSubst_serialize (c->serializer, it);
    return_trace (it.len ());
217 218
  }

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

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

B
Behdad Esfahbod 已提交
237 238
struct SingleSubst
{
239 240

  template<typename Iterator,
B
Behdad Esfahbod 已提交
241 242
	   hb_requires (hb_is_sorted_source_of (Iterator,
						const hb_codepoint_pair_t))>
243
  bool serialize (hb_serialize_context_t *c,
244
		  Iterator glyphs)
B
Behdad Esfahbod 已提交
245
  {
B
Behdad Esfahbod 已提交
246
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
247
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
B
Behdad Esfahbod 已提交
248 249
    unsigned format = 2;
    unsigned delta = 0;
250
    if (glyphs.len ())
B
Behdad Esfahbod 已提交
251
    {
B
Behdad Esfahbod 已提交
252
      format = 1;
253 254 255 256 257
      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 已提交
258
    }
259
    u.format = format;
B
Behdad Esfahbod 已提交
260
    switch (u.format) {
261 262 263 264 265
    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 已提交
266
    default:return_trace (false);
B
Behdad Esfahbod 已提交
267 268 269
    }
  }

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

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

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

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

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

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

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

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

B
Behdad Esfahbod 已提交
337
    return_trace (true);
B
Behdad Esfahbod 已提交
338 339
  }

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

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

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

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

365
  void closure (hb_closure_context_t *c) const
366
  {
367 368 369
    + hb_zip (this+coverage, sequence)
    | hb_filter (*c->glyphs, hb_first)
    | hb_map (hb_second)
B
Behdad Esfahbod 已提交
370
    | hb_apply ([c, this] (const OffsetTo<Sequence> &_) { (this+_).closure (c); })
371
    ;
372 373
  }

374
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
375
  {
376
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
377 378
    + hb_zip (this+coverage, sequence)
    | hb_map (hb_second)
B
Behdad Esfahbod 已提交
379
    | hb_apply ([c, this] (const OffsetTo<Sequence> &_) { (this+_).collect_glyphs (c); })
380
    ;
381 382
  }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

499 500 501
    /* 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);
502

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

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

509 510
    c->replace_glyph (alternates[alt_index - 1]);

511 512 513
    return_trace (true);
  }

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

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

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

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

540
  void closure (hb_closure_context_t *c) const
541
  {
542 543
    + hb_zip (this+coverage, alternateSet)
    | hb_map (hb_second)
B
Behdad Esfahbod 已提交
544
    | hb_apply ([c, this] (const OffsetTo<AlternateSet> &_) { (this+_).closure (c); })
545
    ;
546 547
  }

548
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
549
  {
550
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
551 552
    + hb_zip (this+coverage, alternateSet)
    | hb_map (hb_second)
B
Behdad Esfahbod 已提交
553
    | hb_apply ([c, this] (const OffsetTo<AlternateSet> &_) { (this+_).collect_glyphs (c); })
554
    ;
555 556
  }

557
  const Coverage &get_coverage () const { return this+coverage; }
558

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

562
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
563
  {
B
Behdad Esfahbod 已提交
564
    TRACE_APPLY (this);
565

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

569
    return_trace ((this+alternateSet[index]).apply (c));
570
  }
B
Behdad Esfahbod 已提交
571

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

591
  bool subset (hb_subset_context_t *c) const
592 593 594 595 596 597
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

598
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
599
  {
B
Behdad Esfahbod 已提交
600
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
601
    return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
602 603
  }

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

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

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

644
  protected:
645
  union {
B
Behdad Esfahbod 已提交
646
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
647
  AlternateSubstFormat1	format1;
648 649 650
  } u;
};

651

B
Behdad Esfahbod 已提交
652 653
struct Ligature
{
654
  bool intersects (const hb_set_t *glyphs) const
655
  {
656
    unsigned int count = component.lenP1;
657 658 659 660 661 662
    for (unsigned int i = 1; i < count; i++)
      if (!glyphs->has (component[i]))
        return false;
    return true;
  }

663
  void closure (hb_closure_context_t *c) const
664
  {
B
Behdad Esfahbod 已提交
665
    if (!intersects (c->glyphs)) return;
B
Behdad Esfahbod 已提交
666
    c->output->add (ligGlyph);
667 668
  }

669
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
670
  {
671
    c->input->add_array (component.arrayZ, component.lenP1 ? component.lenP1 - 1 : 0);
B
Minor  
Behdad Esfahbod 已提交
672
    c->output->add (ligGlyph);
673 674
  }

675
  bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
676
  {
677
    if (c->len != component.lenP1)
B
Behdad Esfahbod 已提交
678
      return false;
679 680 681

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

B
Behdad Esfahbod 已提交
684
    return true;
B
Behdad Esfahbod 已提交
685 686
  }

687
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
688
  {
B
Behdad Esfahbod 已提交
689
    TRACE_APPLY (this);
690
    unsigned int count = component.lenP1;
B
Behdad Esfahbod 已提交
691

B
Behdad Esfahbod 已提交
692
    if (unlikely (!count)) return_trace (false);
B
Behdad Esfahbod 已提交
693

694 695 696 697 698
    /* 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 已提交
699
      return_trace (true);
700 701
    }

B
Behdad Esfahbod 已提交
702
    unsigned int total_component_count = 0;
703

704
    unsigned int match_length = 0;
705
    unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
706

707 708 709
    if (likely (!match_input (c, count,
			      &component[1],
			      match_glyph,
B
Behdad Esfahbod 已提交
710
			      nullptr,
711 712
			      &match_length,
			      match_positions,
713
			      &total_component_count)))
B
Behdad Esfahbod 已提交
714
      return_trace (false);
715

716 717
    ligate_input (c,
		  count,
718 719
		  match_positions,
		  match_length,
720
		  ligGlyph,
721
		  total_component_count);
722

B
Behdad Esfahbod 已提交
723
    return_trace (true);
724
  }
725

726 727
  bool serialize (hb_serialize_context_t *c,
		  GlyphID ligature,
B
Behdad Esfahbod 已提交
728
		  hb_array_t<const GlyphID> components /* Starting from second */)
729
  {
B
Behdad Esfahbod 已提交
730
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
731
    if (unlikely (!c->extend_min (*this))) return_trace (false);
732
    ligGlyph = ligature;
B
Behdad Esfahbod 已提交
733
    if (unlikely (!component.serialize (c, components))) return_trace (false);
B
Behdad Esfahbod 已提交
734
    return_trace (true);
735 736
  }

B
Behdad Esfahbod 已提交
737
  public:
738
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
739
  {
B
Behdad Esfahbod 已提交
740
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
741
    return_trace (ligGlyph.sanitize (c) && component.sanitize (c));
B
Behdad Esfahbod 已提交
742 743
  }

744
  protected:
745
  GlyphID	ligGlyph;		/* GlyphID of ligature to substitute */
B
Behdad Esfahbod 已提交
746 747
  HeadlessArrayOf<GlyphID>
		component;		/* Array of component GlyphIDs--start
748 749
					 * with the second  component--ordered
					 * in writing direction */
750
  public:
751
  DEFINE_SIZE_ARRAY (4, component);
752
};
B
Behdad Esfahbod 已提交
753

B
Behdad Esfahbod 已提交
754 755
struct LigatureSet
{
756
  bool intersects (const hb_set_t *glyphs) const
757
  {
B
Behdad Esfahbod 已提交
758 759
    return
    + hb_iter (ligature)
B
Behdad Esfahbod 已提交
760
    | hb_map ([this, glyphs] (const OffsetTo<Ligature> &_) { return (this+_).intersects (glyphs); })
B
Behdad Esfahbod 已提交
761 762
    | hb_any
    ;
763 764
  }

765
  void closure (hb_closure_context_t *c) const
766
  {
B
Behdad Esfahbod 已提交
767
    + hb_iter (ligature)
B
Behdad Esfahbod 已提交
768
    | hb_apply ([this, c] (const OffsetTo<Ligature> &_) { (this+_).closure (c); })
B
Behdad Esfahbod 已提交
769
    ;
770 771
  }

772
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
773
  {
B
Behdad Esfahbod 已提交
774
    + hb_iter (ligature)
B
Behdad Esfahbod 已提交
775
    | hb_apply ([this, c] (const OffsetTo<Ligature> &_) { (this+_).collect_glyphs (c); })
B
Behdad Esfahbod 已提交
776
    ;
777 778
  }

779
  bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
780
  {
B
Behdad Esfahbod 已提交
781 782
    return
    + hb_iter (ligature)
B
Behdad Esfahbod 已提交
783
    | hb_map ([this, c] (const OffsetTo<Ligature> &_) { return (this+_).would_apply (c); })
B
Behdad Esfahbod 已提交
784 785
    | hb_any
    ;
B
Behdad Esfahbod 已提交
786 787
  }

788
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
789
  {
B
Behdad Esfahbod 已提交
790
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
791
    unsigned int num_ligs = ligature.len;
B
Behdad Esfahbod 已提交
792 793
    for (unsigned int i = 0; i < num_ligs; i++)
    {
B
Behdad Esfahbod 已提交
794
      const Ligature &lig = this+ligature[i];
B
Behdad Esfahbod 已提交
795
      if (lig.apply (c)) return_trace (true);
796 797
    }

B
Behdad Esfahbod 已提交
798
    return_trace (false);
799
  }
B
Behdad Esfahbod 已提交
800

801
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
802 803
		  hb_array_t<const GlyphID> ligatures,
		  hb_array_t<const unsigned int> component_count_list,
804
		  hb_array_t<const GlyphID> &component_list /* Starting from second for each ligature */)
805
  {
B
Behdad Esfahbod 已提交
806
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
807
    if (unlikely (!c->extend_min (*this))) return_trace (false);
808 809
    if (unlikely (!ligature.serialize (c, ligatures.length))) return_trace (false);
    for (unsigned int i = 0; i < ligatures.length; i++)
B
Behdad Esfahbod 已提交
810
    {
811
      unsigned int component_count = (unsigned) hb_max ((int) component_count_list[i] - 1, 0);
B
Behdad Esfahbod 已提交
812 813 814 815 816 817 818
      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 已提交
819
    return_trace (true);
820 821
  }

822
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
823
  {
B
Behdad Esfahbod 已提交
824
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
825
    return_trace (ligature.sanitize (c, this));
B
Behdad Esfahbod 已提交
826 827
  }

828
  protected:
B
Behdad Esfahbod 已提交
829 830 831
  OffsetArrayOf<Ligature>
		ligature;		/* Array LigatureSet tables
					 * ordered by preference */
832
  public:
833
  DEFINE_SIZE_ARRAY (2, ligature);
B
Behdad Esfahbod 已提交
834 835
};

B
Behdad Esfahbod 已提交
836 837
struct LigatureSubstFormat1
{
838
  bool intersects (const hb_set_t *glyphs) const
839
  {
840 841 842 843
    return
    + hb_zip (this+coverage, ligatureSet)
    | hb_filter (*glyphs, hb_first)
    | hb_map (hb_second)
B
Behdad Esfahbod 已提交
844
    | hb_map ([this, glyphs] (const OffsetTo<LigatureSet> &_)
845 846 847
	      { return (this+_).intersects (glyphs); })
    | hb_any
    ;
848 849
  }

850
  void closure (hb_closure_context_t *c) const
851
  {
852 853 854
    + hb_zip (this+coverage, ligatureSet)
    | hb_filter (*c->glyphs, hb_first)
    | hb_map (hb_second)
B
Behdad Esfahbod 已提交
855
    | hb_apply ([this, c] (const OffsetTo<LigatureSet> &_) { (this+_).closure (c); })
856
    ;
857 858
  }

859
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
860
  {
861
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
B
Behdad Esfahbod 已提交
862

863 864
    + hb_zip (this+coverage, ligatureSet)
    | hb_map (hb_second)
B
Behdad Esfahbod 已提交
865
    | hb_apply ([this, c] (const OffsetTo<LigatureSet> &_) { (this+_).collect_glyphs (c); })
866
    ;
867 868
  }

869
  const Coverage &get_coverage () const { return this+coverage; }
870

871
  bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
872
  {
873
    unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
B
Behdad Esfahbod 已提交
874
    if (likely (index == NOT_COVERED)) return false;
875 876

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

880
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
881
  {
B
Behdad Esfahbod 已提交
882
    TRACE_APPLY (this);
883

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

B
Behdad Esfahbod 已提交
887
    const LigatureSet &lig_set = this+ligatureSet[index];
B
Behdad Esfahbod 已提交
888
    return_trace (lig_set.apply (c));
889
  }
B
Behdad Esfahbod 已提交
890

891
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
892
		  hb_sorted_array_t<const GlyphID> first_glyphs,
B
Behdad Esfahbod 已提交
893 894 895 896
		  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 */)
897
  {
B
Behdad Esfahbod 已提交
898
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
899
    if (unlikely (!c->extend_min (*this))) return_trace (false);
900 901
    if (unlikely (!ligatureSet.serialize (c, first_glyphs.length))) return_trace (false);
    for (unsigned int i = 0; i < first_glyphs.length; i++)
B
Behdad Esfahbod 已提交
902 903 904 905 906 907 908 909 910 911 912
    {
      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));
913 914
  }

915
  bool subset (hb_subset_context_t *c) const
916 917 918 919 920 921
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

922
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
923
  {
B
Behdad Esfahbod 已提交
924
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
925
    return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
926 927
  }

928
  protected:
B
Behdad Esfahbod 已提交
929
  HBUINT16	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
930 931
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
932
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
933
  OffsetArrayOf<LigatureSet>
B
Behdad Esfahbod 已提交
934 935
		ligatureSet;		/* Array LigatureSet tables
					 * ordered by Coverage Index */
936
  public:
937
  DEFINE_SIZE_ARRAY (6, ligatureSet);
B
Behdad Esfahbod 已提交
938
};
939

B
Behdad Esfahbod 已提交
940 941
struct LigatureSubst
{
942
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
943
		  hb_sorted_array_t<const GlyphID> first_glyphs,
B
Behdad Esfahbod 已提交
944 945 946 947
		  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 */)
948
  {
B
Behdad Esfahbod 已提交
949
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
950
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
951
    unsigned int format = 1;
952
    u.format = format;
953
    switch (u.format) {
B
Behdad Esfahbod 已提交
954 955 956 957 958 959 960
    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);
961 962 963
    }
  }

964
  template <typename context_t, typename ...Ts>
B
Behdad Esfahbod 已提交
965
  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
B
Behdad Esfahbod 已提交
966
  {
967
    TRACE_DISPATCH (this, u.format);
968
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
969
    switch (u.format) {
970
    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
B
Behdad Esfahbod 已提交
971
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
972 973 974
    }
  }

975
  protected:
976
  union {
B
Behdad Esfahbod 已提交
977
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
978
  LigatureSubstFormat1	format1;
979 980 981
  } u;
};

B
Behdad Esfahbod 已提交
982

B
Minor  
Behdad Esfahbod 已提交
983
struct ContextSubst : Context {};
B
Behdad Esfahbod 已提交
984

B
Minor  
Behdad Esfahbod 已提交
985
struct ChainContextSubst : ChainContext {};
986

B
Behdad Esfahbod 已提交
987
struct ExtensionSubst : Extension<ExtensionSubst>
B
Behdad Esfahbod 已提交
988
{
B
Behdad Esfahbod 已提交
989
  typedef struct SubstLookupSubTable SubTable;
B
Behdad Esfahbod 已提交
990

991
  bool is_reverse () const;
992 993 994
};


B
Behdad Esfahbod 已提交
995 996
struct ReverseChainSingleSubstFormat1
{
997
  bool intersects (const hb_set_t *glyphs) const
998 999 1000 1001
  {
    if (!(this+coverage).intersects (glyphs))
      return false;

1002
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018

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

1019
  void closure (hb_closure_context_t *c) const
1020
  {
B
Behdad Esfahbod 已提交
1021
    if (!intersects (c->glyphs)) return;
B
Behdad Esfahbod 已提交
1022

1023 1024
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID>> (lookahead);
B
Behdad Esfahbod 已提交
1025

B
Behdad Esfahbod 已提交
1026 1027 1028
    + hb_zip (this+coverage, substitute)
    | hb_filter (*c->glyphs, hb_first)
    | hb_map (hb_second)
1029
    | hb_sink (c->output)
1030
    ;
1031 1032
  }

1033
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
1034
  {
1035
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
1036 1037 1038 1039 1040

    unsigned int count;

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

1043
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
1044 1045
    count = lookahead.len;
    for (unsigned int i = 0; i < count; i++)
1046
      if (unlikely (!(this+lookahead[i]).add_coverage (c->after))) return;
1047

1048
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID>> (lookahead);
1049
    count = substitute.len;
1050
    c->output->add_array (substitute.arrayZ, substitute.len);
1051 1052
  }

1053
  const Coverage &get_coverage () const { return this+coverage; }
1054

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

1058
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1059
  {
B
Behdad Esfahbod 已提交
1060
    TRACE_APPLY (this);
1061
    if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
B
Behdad Esfahbod 已提交
1062
      return_trace (false); /* No chaining to this type */
1063

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

1067 1068
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID>> (lookahead);
1069

1070
  unsigned int start_index = 0, end_index = 0;
B
Behdad Esfahbod 已提交
1071
    if (match_backtrack (c,
1072
			 backtrack.len, (HBUINT16 *) backtrack.arrayZ,
1073 1074
			 match_coverage, this,
			 &start_index) &&
B
Behdad Esfahbod 已提交
1075
        match_lookahead (c,
1076
			 lookahead.len, (HBUINT16 *) lookahead.arrayZ,
B
Behdad Esfahbod 已提交
1077
			 match_coverage, this,
1078
			 1, &end_index))
1079
    {
1080
      c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index);
B
Behdad Esfahbod 已提交
1081
      c->replace_glyph_inplace (substitute[index]);
1082 1083 1084
      /* 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 已提交
1085
      return_trace (true);
1086 1087
    }

B
Behdad Esfahbod 已提交
1088
    return_trace (false);
1089
  }
B
Behdad Esfahbod 已提交
1090

1091
  bool subset (hb_subset_context_t *c) const
1092 1093 1094 1095 1096 1097
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

1098
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
1099
  {
B
Behdad Esfahbod 已提交
1100
    TRACE_SANITIZE (this);
1101
    if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
B
Behdad Esfahbod 已提交
1102
      return_trace (false);
1103
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
B
Behdad Esfahbod 已提交
1104
    if (!lookahead.sanitize (c, this))
B
Behdad Esfahbod 已提交
1105
      return_trace (false);
1106
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID>> (lookahead);
B
Behdad Esfahbod 已提交
1107
    return_trace (substitute.sanitize (c));
B
Behdad Esfahbod 已提交
1108 1109
  }

1110
  protected:
B
Behdad Esfahbod 已提交
1111
  HBUINT16	format;			/* Format identifier--format = 1 */
1112 1113 1114 1115 1116
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of table */
  OffsetArrayOf<Coverage>
		backtrack;		/* Array of coverage tables
1117
					 * in backtracking sequence, in glyph
B
Behdad Esfahbod 已提交
1118
					 * sequence order */
1119 1120 1121
  OffsetArrayOf<Coverage>
		lookaheadX;		/* Array of coverage tables
					 * in lookahead sequence, in glyph
B
Behdad Esfahbod 已提交
1122
					 * sequence order */
1123 1124 1125
  ArrayOf<GlyphID>
		substituteX;		/* Array of substitute
					 * GlyphIDs--ordered by Coverage Index */
1126
  public:
B
Behdad Esfahbod 已提交
1127
  DEFINE_SIZE_MIN (10);
B
Behdad Esfahbod 已提交
1128 1129
};

B
Behdad Esfahbod 已提交
1130 1131
struct ReverseChainSingleSubst
{
1132
  template <typename context_t, typename ...Ts>
B
Behdad Esfahbod 已提交
1133
  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
1134
  {
1135
    TRACE_DISPATCH (this, u.format);
1136
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1137
    switch (u.format) {
1138
    case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
B
Behdad Esfahbod 已提交
1139
    default:return_trace (c->default_return_value ());
1140 1141 1142
    }
  }

1143
  protected:
1144
  union {
B
Behdad Esfahbod 已提交
1145
  HBUINT16				format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1146
  ReverseChainSingleSubstFormat1	format1;
1147 1148 1149 1150 1151
  } u;
};



B
Behdad Esfahbod 已提交
1152 1153 1154 1155
/*
 * SubstLookup
 */

B
Behdad Esfahbod 已提交
1156 1157
struct SubstLookupSubTable
{
B
Behdad Esfahbod 已提交
1158
  friend struct Lookup;
B
Behdad Esfahbod 已提交
1159 1160
  friend struct SubstLookup;

B
Behdad Esfahbod 已提交
1161
  enum Type {
1162 1163 1164 1165 1166 1167 1168
    Single		= 1,
    Multiple		= 2,
    Alternate		= 3,
    Ligature		= 4,
    Context		= 5,
    ChainContext	= 6,
    Extension		= 7,
1169
    ReverseChainSingle	= 8
1170 1171
  };

1172
  template <typename context_t, typename ...Ts>
B
Behdad Esfahbod 已提交
1173
  typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type, Ts&&... ds) const
1174
  {
1175
    TRACE_DISPATCH (this, lookup_type);
1176
    switch (lookup_type) {
1177 1178 1179 1180 1181 1182 1183 1184
    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 已提交
1185
    default:			return_trace (c->default_return_value ());
1186 1187 1188
    }
  }

1189
  protected:
B
Behdad Esfahbod 已提交
1190
  union {
B
Behdad Esfahbod 已提交
1191 1192 1193 1194
  SingleSubst			single;
  MultipleSubst			multiple;
  AlternateSubst		alternate;
  LigatureSubst			ligature;
1195
  ContextSubst			context;
B
Behdad Esfahbod 已提交
1196 1197 1198
  ChainContextSubst		chainContext;
  ExtensionSubst		extension;
  ReverseChainSingleSubst	reverseChainContextSingle;
B
Behdad Esfahbod 已提交
1199
  } u;
B
Behdad Esfahbod 已提交
1200
  public:
B
Behdad Esfahbod 已提交
1201
  DEFINE_SIZE_MIN (0);
B
Behdad Esfahbod 已提交
1202 1203
};

1204

B
Behdad Esfahbod 已提交
1205 1206
struct SubstLookup : Lookup
{
B
Behdad Esfahbod 已提交
1207 1208
  typedef SubstLookupSubTable SubTable;

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

B
Behdad Esfahbod 已提交
1212
  HB_INTERNAL static bool lookup_type_is_reverse (unsigned int lookup_type)
B
Behdad Esfahbod 已提交
1213
  { return lookup_type == SubTable::ReverseChainSingle; }
B
Behdad Esfahbod 已提交
1214

1215
  bool is_reverse () const
B
Behdad Esfahbod 已提交
1216
  {
B
Behdad Esfahbod 已提交
1217
    unsigned int type = get_type ();
B
Behdad Esfahbod 已提交
1218
    if (unlikely (type == SubTable::Extension))
1219
      return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
B
Behdad Esfahbod 已提交
1220
    return lookup_type_is_reverse (type);
B
Behdad Esfahbod 已提交
1221
  }
1222

1223
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1224 1225
  {
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
1226
    return_trace (dispatch (c));
B
Behdad Esfahbod 已提交
1227 1228
  }

1229
  bool intersects (const hb_set_t *glyphs) const
1230 1231 1232 1233 1234
  {
    hb_intersects_context_t c (glyphs);
    return dispatch (&c);
  }

1235
  hb_closure_context_t::return_t closure (hb_closure_context_t *c, unsigned int this_index) const
1236
  {
1237
    if (!c->should_visit_lookup (this_index))
B
Behdad Esfahbod 已提交
1238
      return hb_closure_context_t::default_return_value ();
1239 1240

    c->set_recurse_func (dispatch_closure_recurse_func);
1241 1242 1243 1244 1245

    hb_closure_context_t::return_t ret = dispatch (c);

    c->flush ();

B
Behdad Esfahbod 已提交
1246
    return ret;
B
Behdad Esfahbod 已提交
1247 1248
  }

1249
  hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
B
Behdad Esfahbod 已提交
1250
  {
1251
    c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
B
Behdad Esfahbod 已提交
1252
    return dispatch (c);
1253 1254
  }

B
Behdad Esfahbod 已提交
1255
  template <typename set_t>
1256
  void add_coverage (set_t *glyphs) const
B
Behdad Esfahbod 已提交
1257
  {
1258 1259
    hb_add_coverage_context_t<set_t> c (glyphs);
    dispatch (&c);
B
Behdad Esfahbod 已提交
1260 1261
  }

1262 1263
  bool would_apply (hb_would_apply_context_t *c,
		    const hb_ot_layout_lookup_accelerator_t *accel) const
B
Behdad Esfahbod 已提交
1264
  {
B
Behdad Esfahbod 已提交
1265 1266 1267
    if (unlikely (!c->len)) return false;
    if (!accel->may_have (c->glyphs[0])) return false;
      return dispatch (c);
B
Behdad Esfahbod 已提交
1268 1269
  }

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

1272
  SubTable& serialize_subtable (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
1273 1274
				       unsigned int i)
  { return get_subtables<SubTable> ()[i].serialize (c, this); }
1275

1276 1277
  bool serialize_single (hb_serialize_context_t *c,
			 uint32_t lookup_props,
B
Behdad Esfahbod 已提交
1278
		         hb_sorted_array_t<const GlyphID> glyphs,
B
Behdad Esfahbod 已提交
1279
		         hb_array_t<const GlyphID> substitutes)
1280
  {
B
Behdad Esfahbod 已提交
1281
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1282
    if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false);
1283 1284 1285

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

1288 1289
  bool serialize_multiple (hb_serialize_context_t *c,
			   uint32_t lookup_props,
B
Behdad Esfahbod 已提交
1290
			   hb_sorted_array_t<const GlyphID> glyphs,
B
Behdad Esfahbod 已提交
1291 1292
			   hb_array_t<const unsigned int> substitute_len_list,
			   hb_array_t<const GlyphID> substitute_glyphs_list)
1293
  {
B
Behdad Esfahbod 已提交
1294
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1295
    if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1296 1297 1298 1299
    return_trace (serialize_subtable (c, 0).u.multiple.serialize (c,
								  glyphs,
								  substitute_len_list,
								  substitute_glyphs_list));
1300 1301
  }

1302 1303
  bool serialize_alternate (hb_serialize_context_t *c,
			    uint32_t lookup_props,
B
Behdad Esfahbod 已提交
1304
			    hb_sorted_array_t<const GlyphID> glyphs,
B
Behdad Esfahbod 已提交
1305 1306
			    hb_array_t<const unsigned int> alternate_len_list,
			    hb_array_t<const GlyphID> alternate_glyphs_list)
1307
  {
B
Behdad Esfahbod 已提交
1308
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1309
    if (unlikely (!Lookup::serialize (c, SubTable::Alternate, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1310 1311 1312 1313
    return_trace (serialize_subtable (c, 0).u.alternate.serialize (c,
								   glyphs,
								   alternate_len_list,
								   alternate_glyphs_list));
1314 1315
  }

1316 1317
  bool serialize_ligature (hb_serialize_context_t *c,
			   uint32_t lookup_props,
B
Behdad Esfahbod 已提交
1318
			   hb_sorted_array_t<const GlyphID> first_glyphs,
B
Behdad Esfahbod 已提交
1319 1320 1321 1322
			   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 */)
1323
  {
B
Behdad Esfahbod 已提交
1324
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1325
    if (unlikely (!Lookup::serialize (c, SubTable::Ligature, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1326 1327 1328 1329 1330 1331
    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));
1332 1333
  }

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

B
Behdad Esfahbod 已提交
1337
  HB_INTERNAL static hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned int lookup_index)
1338
  {
1339
    if (!c->should_visit_lookup (lookup_index))
B
Behdad Esfahbod 已提交
1340
      return hb_empty_t ();
1341 1342 1343

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

1344 1345 1346 1347
    /* 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 ();
1348 1349

    return ret;
1350 1351
  }

1352
  template <typename context_t, typename ...Ts>
B
Behdad Esfahbod 已提交
1353
  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
1354
  { return Lookup::dispatch<SubTable> (c, hb_forward<Ts> (ds)...); }
B
Behdad Esfahbod 已提交
1355

1356
  bool subset (hb_subset_context_t *c) const
1357
  { return Lookup::subset<SubTable> (c); }
B
Behdad Esfahbod 已提交
1358

1359
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
1360
  { return Lookup::sanitize<SubTable> (c); }
B
Behdad Esfahbod 已提交
1361 1362
};

B
Minor  
Behdad Esfahbod 已提交
1363
/*
1364 1365
 * GSUB -- Glyph Substitution
 * https://docs.microsoft.com/en-us/typography/opentype/spec/gsub
B
Minor  
Behdad Esfahbod 已提交
1366 1367
 */

B
Behdad Esfahbod 已提交
1368 1369
struct GSUB : GSUBGPOS
{
1370
  static constexpr hb_tag_t tableTag = HB_OT_TAG_GSUB;
B
Minor  
Behdad Esfahbod 已提交
1371

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

1375
  bool subset (hb_subset_context_t *c) const
1376
  { return GSUBGPOS::subset<SubstLookup> (c); }
1377

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

1381 1382 1383
  HB_INTERNAL bool is_blacklisted (hb_blob_t *blob,
				   hb_face_t *face) const;

B
WIP  
Behdad Esfahbod 已提交
1384
  typedef GSUBGPOS::accelerator_t<GSUB> accelerator_t;
B
Minor  
Behdad Esfahbod 已提交
1385
};
1386 1387


B
Behdad Esfahbod 已提交
1388 1389 1390
struct GSUB_accelerator_t : GSUB::accelerator_t {};


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

1393
/*static*/ inline bool ExtensionSubst::is_reverse () const
B
Behdad Esfahbod 已提交
1394 1395
{
  unsigned int type = get_type ();
B
Behdad Esfahbod 已提交
1396 1397
  if (unlikely (type == SubTable::Extension))
    return CastR<ExtensionSubst> (get_subtable<SubTable>()).is_reverse ();
B
Behdad Esfahbod 已提交
1398 1399 1400
  return SubstLookup::lookup_type_is_reverse (type);
}

1401
template <typename context_t>
1402
/*static*/ inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
1403
{
B
Behdad Esfahbod 已提交
1404
  const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index);
1405
  return l.dispatch (c);
1406 1407
}

1408
/*static*/ inline bool SubstLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index)
B
Behdad Esfahbod 已提交
1409
{
B
Behdad Esfahbod 已提交
1410
  const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index);
1411
  unsigned int saved_lookup_props = c->lookup_props;
1412 1413 1414
  unsigned int saved_lookup_index = c->lookup_index;
  c->set_lookup_index (lookup_index);
  c->set_lookup_props (l.get_props ());
1415
  bool ret = l.dispatch (c);
1416
  c->set_lookup_index (saved_lookup_index);
1417
  c->set_lookup_props (saved_lookup_props);
1418
  return ret;
1419 1420
}

B
Behdad Esfahbod 已提交
1421
} /* namespace OT */
1422

B
Behdad Esfahbod 已提交
1423

1424
#endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */