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

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

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

B
Behdad Esfahbod 已提交
34

35 36
namespace OT {

37

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

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

47
  void closure (hb_closure_context_t *c) const
48
  {
B
Behdad Esfahbod 已提交
49 50 51
    for (auto it = (this+coverage).iter (); it; ++it)
      if (c->glyphs->has (*it))
        c->out->add ((*it + deltaGlyphID) & 0xFFFFu);
52 53
  }

54
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
55
  {
56
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
B
Behdad Esfahbod 已提交
57 58
    for (auto it = (this+coverage).iter (); it; ++it)
      c->output->add ((*it + deltaGlyphID) & 0xFFFFu);
59 60
  }

61
  const Coverage &get_coverage () const { return this+coverage; }
62

63
  bool would_apply (hb_would_apply_context_t *c) const
64
  {
B
Behdad Esfahbod 已提交
65
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
66
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
67 68
  }

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

76 77
    /* According to the Adobe Annotated OpenType Suite, result is always
     * limited to 16bit. */
78
    glyph_id = (glyph_id + deltaGlyphID) & 0xFFFFu;
79
    c->replace_glyph (glyph_id);
B
Behdad Esfahbod 已提交
80

B
Behdad Esfahbod 已提交
81
    return_trace (true);
82
  }
B
Behdad Esfahbod 已提交
83

84
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
85
		  hb_sorted_array_t<const GlyphID> glyphs,
86
		  int delta)
87
  {
B
Behdad Esfahbod 已提交
88
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
89
    if (unlikely (!c->extend_min (*this))) return_trace (false);
B
Behdad Esfahbod 已提交
90
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs))) return_trace (false);
B
Bruce Mitchener 已提交
91
    deltaGlyphID.set (delta); /* TODO(serialize) overflow? */
B
Behdad Esfahbod 已提交
92
    return_trace (true);
93 94
  }

95
  bool subset (hb_subset_context_t *c) const
96 97
  {
    TRACE_SUBSET (this);
B
Behdad Esfahbod 已提交
98
    const hb_set_t &glyphset = *c->plan->glyphset;
99
    const hb_map_t &glyph_map = *c->plan->glyph_map;
B
Behdad Esfahbod 已提交
100
    hb_sorted_vector_t<GlyphID> from;
101
    hb_vector_t<GlyphID> to;
102
    hb_codepoint_t delta = deltaGlyphID;
B
Behdad Esfahbod 已提交
103 104 105 106 107 108
    for (auto it = (this+coverage).iter (); it; ++it)
      if (glyphset.has (*it))
      {
	from.push ()->set (glyph_map[*it]);
	to.push ()->set (glyph_map[(*it + delta) & 0xFFFF]);
      }
109
    c->serializer->propagate_error (from, to);
B
Behdad Esfahbod 已提交
110
    SingleSubst_serialize (c->serializer, from, to);
111
    return_trace (from.length);
112 113
  }

114
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
115
  {
B
Behdad Esfahbod 已提交
116
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
117
    return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
B
Behdad Esfahbod 已提交
118 119
  }

120
  protected:
B
Behdad Esfahbod 已提交
121
  HBUINT16	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
122 123
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
124
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
125
  HBINT16	deltaGlyphID;		/* Add to original GlyphID to get
B
Behdad Esfahbod 已提交
126
					 * substitute GlyphID */
127 128
  public:
  DEFINE_SIZE_STATIC (6);
B
Behdad Esfahbod 已提交
129 130
};

B
Behdad Esfahbod 已提交
131 132
struct SingleSubstFormat2
{
133
  bool intersects (const hb_set_t *glyphs) const
134 135
  { return (this+coverage).intersects (glyphs); }

136
  void closure (hb_closure_context_t *c) const
137
  {
B
Behdad Esfahbod 已提交
138 139 140
    for (auto it = hb_zip (this+coverage, substitute); it; ++it)
      if (c->glyphs->has (it->first))
        c->out->add (it->second);
141 142
  }

143
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
144
  {
145
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
B
Behdad Esfahbod 已提交
146 147
    for (auto it = hb_zip (this+coverage, substitute); it; ++it)
      c->output->add (it->second);
148 149
  }

150
  const Coverage &get_coverage () const { return this+coverage; }
151

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

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

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

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

B
Behdad Esfahbod 已提交
168
    return_trace (true);
169
  }
B
Behdad Esfahbod 已提交
170

171
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
172
		  hb_sorted_array_t<const GlyphID> glyphs,
B
Behdad Esfahbod 已提交
173
		  hb_array_t<const GlyphID> substitutes)
B
Behdad Esfahbod 已提交
174
  {
B
Behdad Esfahbod 已提交
175
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
176
    if (unlikely (!c->extend_min (*this))) return_trace (false);
B
Behdad Esfahbod 已提交
177 178
    if (unlikely (!substitute.serialize (c, substitutes))) return_trace (false);
    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs))) return_trace (false);
B
Behdad Esfahbod 已提交
179
    return_trace (true);
B
Behdad Esfahbod 已提交
180 181
  }

182
  bool subset (hb_subset_context_t *c) const
183 184
  {
    TRACE_SUBSET (this);
B
Behdad Esfahbod 已提交
185
    const hb_set_t &glyphset = *c->plan->glyphset;
186
    const hb_map_t &glyph_map = *c->plan->glyph_map;
B
Behdad Esfahbod 已提交
187
    hb_sorted_vector_t<GlyphID> from;
188
    hb_vector_t<GlyphID> to;
B
Behdad Esfahbod 已提交
189 190 191 192 193 194
    for (auto it = hb_zip (this+coverage, substitute); it; ++it)
      if (glyphset.has (it->first))
      {
	from.push ()->set (glyph_map[it->first]);
	to.push ()->set (glyph_map[it->second]);
      }
195
    c->serializer->propagate_error (from, to);
B
Behdad Esfahbod 已提交
196
    SingleSubst_serialize (c->serializer, from, to);
197
    return_trace (from.length);
198 199
  }

200
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
201
  {
B
Behdad Esfahbod 已提交
202
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
203
    return_trace (coverage.sanitize (c, this) && substitute.sanitize (c));
B
Behdad Esfahbod 已提交
204 205
  }

206
  protected:
B
Behdad Esfahbod 已提交
207
  HBUINT16	format;			/* Format identifier--format = 2 */
B
Behdad Esfahbod 已提交
208 209
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
210
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
211 212 213
  ArrayOf<GlyphID>
		substitute;		/* Array of substitute
					 * GlyphIDs--ordered by Coverage Index */
214
  public:
215
  DEFINE_SIZE_ARRAY (6, substitute);
B
Behdad Esfahbod 已提交
216 217
};

B
Behdad Esfahbod 已提交
218 219
struct SingleSubst
{
220
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
221
		  hb_sorted_array_t<const GlyphID> glyphs,
B
Behdad Esfahbod 已提交
222
		  hb_array_t<const GlyphID> substitutes)
B
Behdad Esfahbod 已提交
223
  {
B
Behdad Esfahbod 已提交
224
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
225
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
B
Behdad Esfahbod 已提交
226
    unsigned int format = 2;
B
Behdad Esfahbod 已提交
227
    int delta = 0;
228
    if (glyphs.length)
B
Behdad Esfahbod 已提交
229
    {
B
Behdad Esfahbod 已提交
230
      format = 1;
B
Minor  
Behdad Esfahbod 已提交
231
      /* TODO(serialize) check for wrap-around */
B
Behdad Esfahbod 已提交
232
      delta = substitutes[0] - glyphs[0];
233
      for (unsigned int i = 1; i < glyphs.length; i++)
B
Minor  
Behdad Esfahbod 已提交
234
	if (delta != (int) (substitutes[i] - glyphs[i])) {
B
Behdad Esfahbod 已提交
235 236 237 238 239 240
	  format = 2;
	  break;
	}
    }
    u.format.set (format);
    switch (u.format) {
B
Behdad Esfahbod 已提交
241 242
    case 1: return_trace (u.format1.serialize (c, glyphs, delta));
    case 2: return_trace (u.format2.serialize (c, glyphs, substitutes));
B
Behdad Esfahbod 已提交
243
    default:return_trace (false);
B
Behdad Esfahbod 已提交
244 245 246
    }
  }

B
Behdad Esfahbod 已提交
247
  template <typename context_t>
248
  typename context_t::return_t dispatch (context_t *c) const
B
Behdad Esfahbod 已提交
249
  {
250
    TRACE_DISPATCH (this, u.format);
251
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
252
    switch (u.format) {
B
Behdad Esfahbod 已提交
253 254 255
    case 1: return_trace (c->dispatch (u.format1));
    case 2: return_trace (c->dispatch (u.format2));
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
256 257 258
    }
  }

259
  protected:
260
  union {
B
Behdad Esfahbod 已提交
261
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
262 263
  SingleSubstFormat1	format1;
  SingleSubstFormat2	format2;
264
  } u;
B
Behdad Esfahbod 已提交
265
};
266

267 268
static inline void
SingleSubst_serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
269
		       hb_sorted_array_t<const GlyphID> glyphs,
B
Behdad Esfahbod 已提交
270 271
		       hb_array_t<const GlyphID> substitutes)
{ c->start_embed<SingleSubst> ()->serialize (c, glyphs, substitutes); }
B
Behdad Esfahbod 已提交
272

B
Behdad Esfahbod 已提交
273 274
struct Sequence
{
275
  void closure (hb_closure_context_t *c) const
276
  {
B
Behdad Esfahbod 已提交
277 278
    unsigned int count = substitute.len;
    for (unsigned int i = 0; i < count; i++)
279
      c->out->add (substitute[i]);
280 281
  }

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

285
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
286
  {
B
Behdad Esfahbod 已提交
287
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
288
    unsigned int count = substitute.len;
289

B
Behdad Esfahbod 已提交
290 291 292
    /* Special-case to make it in-place and not consider this
     * as a "multiplied" substitution. */
    if (unlikely (count == 1))
293
    {
294
      c->replace_glyph (substitute.arrayZ[0]);
B
Behdad Esfahbod 已提交
295
      return_trace (true);
296
    }
297
    /* Spec disallows this, but Uniscribe allows it.
298
     * https://github.com/harfbuzz/harfbuzz/issues/253 */
299 300 301 302 303
    else if (unlikely (count == 0))
    {
      c->buffer->delete_glyph ();
      return_trace (true);
    }
B
Behdad Esfahbod 已提交
304 305 306 307 308 309

    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);
310
      c->output_glyph_for_component (substitute.arrayZ[i], klass);
311
    }
B
Behdad Esfahbod 已提交
312
    c->buffer->skip_glyph ();
B
Behdad Esfahbod 已提交
313

B
Behdad Esfahbod 已提交
314
    return_trace (true);
B
Behdad Esfahbod 已提交
315 316
  }

317
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
318
		  hb_array_t<const GlyphID> subst)
319
  {
B
Behdad Esfahbod 已提交
320
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
321
    return_trace (substitute.serialize (c, subst));
322 323
  }

324
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
325
  {
B
Behdad Esfahbod 已提交
326
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
327
    return_trace (substitute.sanitize (c));
B
Behdad Esfahbod 已提交
328 329
  }

330
  protected:
B
Behdad Esfahbod 已提交
331 332
  ArrayOf<GlyphID>
		substitute;		/* String of GlyphIDs to substitute */
333
  public:
334
  DEFINE_SIZE_ARRAY (2, substitute);
B
Behdad Esfahbod 已提交
335 336
};

B
Behdad Esfahbod 已提交
337 338
struct MultipleSubstFormat1
{
339
  bool intersects (const hb_set_t *glyphs) const
340 341
  { return (this+coverage).intersects (glyphs); }

342
  void closure (hb_closure_context_t *c) const
343
  {
B
Behdad Esfahbod 已提交
344 345 346
    for (auto it = hb_zip (this+coverage, sequence); it; ++it)
      if (c->glyphs->has (it->first))
        (this+it->second).closure (c);
347 348
  }

349
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
350
  {
351
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
B
Behdad Esfahbod 已提交
352 353
    for (auto it = hb_zip (this+coverage, sequence); it; ++it)
      (this+it->second).collect_glyphs (c);
354 355
  }

356
  const Coverage &get_coverage () const { return this+coverage; }
357

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

364
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
365
  {
B
Behdad Esfahbod 已提交
366
    TRACE_APPLY (this);
367

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

B
Behdad Esfahbod 已提交
371
    return_trace ((this+sequence[index]).apply (c));
372
  }
B
Behdad Esfahbod 已提交
373

374
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
375
		  hb_sorted_array_t<const GlyphID> glyphs,
B
Behdad Esfahbod 已提交
376 377
		  hb_array_t<const unsigned int> substitute_len_list,
		  hb_array_t<const GlyphID> substitute_glyphs_list)
378
  {
B
Behdad Esfahbod 已提交
379
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
380
    if (unlikely (!c->extend_min (*this))) return_trace (false);
381 382
    if (unlikely (!sequence.serialize (c, glyphs.length))) return_trace (false);
    for (unsigned int i = 0; i < glyphs.length; i++)
B
Behdad Esfahbod 已提交
383 384 385 386 387 388 389 390
    {
      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));
391 392
  }

393
  bool subset (hb_subset_context_t *c) const
394 395 396 397 398 399
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

400
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
401
  {
B
Behdad Esfahbod 已提交
402
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
403
    return_trace (coverage.sanitize (c, this) && sequence.sanitize (c, this));
B
Behdad Esfahbod 已提交
404 405
  }

406
  protected:
B
Behdad Esfahbod 已提交
407
  HBUINT16	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
408 409
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
410
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
411 412 413
  OffsetArrayOf<Sequence>
		sequence;		/* Array of Sequence tables
					 * ordered by Coverage Index */
414
  public:
415
  DEFINE_SIZE_ARRAY (6, sequence);
B
Behdad Esfahbod 已提交
416
};
417

B
Behdad Esfahbod 已提交
418 419
struct MultipleSubst
{
420
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
421
		  hb_sorted_array_t<const GlyphID> glyphs,
B
Behdad Esfahbod 已提交
422 423
		  hb_array_t<const unsigned int> substitute_len_list,
		  hb_array_t<const GlyphID> substitute_glyphs_list)
424
  {
B
Behdad Esfahbod 已提交
425
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
426
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
427 428 429
    unsigned int format = 1;
    u.format.set (format);
    switch (u.format) {
B
Behdad Esfahbod 已提交
430
    case 1: return_trace (u.format1.serialize (c, glyphs, substitute_len_list, substitute_glyphs_list));
B
Behdad Esfahbod 已提交
431
    default:return_trace (false);
432 433 434
    }
  }

B
Behdad Esfahbod 已提交
435
  template <typename context_t>
436
  typename context_t::return_t dispatch (context_t *c) const
B
Behdad Esfahbod 已提交
437
  {
438
    TRACE_DISPATCH (this, u.format);
439
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
440
    switch (u.format) {
B
Behdad Esfahbod 已提交
441 442
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
443 444 445
    }
  }

446
  protected:
447
  union {
B
Behdad Esfahbod 已提交
448
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
449
  MultipleSubstFormat1	format1;
450 451 452
  } u;
};

453 454
struct AlternateSet
{
455
  void closure (hb_closure_context_t *c) const
456 457 458 459 460 461
  {
    unsigned int count = alternates.len;
    for (unsigned int i = 0; i < count; i++)
      c->out->add (alternates[i]);
  }

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

465
  bool apply (hb_ot_apply_context_t *c) const
466 467 468 469 470 471
  {
    TRACE_APPLY (this);
    unsigned int count = alternates.len;

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

472 473
    hb_mask_t glyph_mask = c->buffer->cur().mask;
    hb_mask_t lookup_mask = c->lookup_mask;
474

475 476 477
    /* 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);
478

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

483 484
    if (unlikely (alt_index > count || alt_index == 0)) return_trace (false);

485 486
    c->replace_glyph (alternates[alt_index - 1]);

487 488 489
    return_trace (true);
  }

490
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
491
		  hb_array_t<const GlyphID> alts)
492 493
  {
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
494
    return_trace (alternates.serialize (c, alts));
495 496
  }

497
  bool sanitize (hb_sanitize_context_t *c) const
498 499 500 501 502 503 504 505
  {
    TRACE_SANITIZE (this);
    return_trace (alternates.sanitize (c));
  }

  protected:
  ArrayOf<GlyphID>
		alternates;		/* Array of alternate GlyphIDs--in
B
Behdad Esfahbod 已提交
506
					 * arbitrary order */
507 508 509
  public:
  DEFINE_SIZE_ARRAY (2, alternates);
};
B
Behdad Esfahbod 已提交
510

B
Behdad Esfahbod 已提交
511 512
struct AlternateSubstFormat1
{
513
  bool intersects (const hb_set_t *glyphs) const
514 515
  { return (this+coverage).intersects (glyphs); }

516
  void closure (hb_closure_context_t *c) const
517
  {
B
Behdad Esfahbod 已提交
518 519 520
    for (auto it = hb_zip (this+coverage, alternateSet); it; ++it)
      if (c->glyphs->has (it->first))
        (this+it->second).closure (c);
521 522
  }

523
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
524
  {
525
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
B
Behdad Esfahbod 已提交
526 527
    for (auto it = hb_zip (this+coverage, alternateSet); it; ++it)
      (this+it->second).collect_glyphs (c);
528 529
  }

530
  const Coverage &get_coverage () const { return this+coverage; }
531

532
  bool would_apply (hb_would_apply_context_t *c) const
533
  {
B
Behdad Esfahbod 已提交
534
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
535
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
536 537
  }

538
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
539
  {
B
Behdad Esfahbod 已提交
540
    TRACE_APPLY (this);
541

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

545
    return_trace ((this+alternateSet[index]).apply (c));
546
  }
B
Behdad Esfahbod 已提交
547

548
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
549
		  hb_sorted_array_t<const GlyphID> glyphs,
B
Behdad Esfahbod 已提交
550 551
		  hb_array_t<const unsigned int> alternate_len_list,
		  hb_array_t<const GlyphID> alternate_glyphs_list)
552
  {
B
Behdad Esfahbod 已提交
553
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
554
    if (unlikely (!c->extend_min (*this))) return_trace (false);
555 556
    if (unlikely (!alternateSet.serialize (c, glyphs.length))) return_trace (false);
    for (unsigned int i = 0; i < glyphs.length; i++)
B
Behdad Esfahbod 已提交
557 558 559 560 561 562 563 564
    {
      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));
565 566
  }

567
  bool subset (hb_subset_context_t *c) const
568 569 570 571 572 573
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

574
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
575
  {
B
Behdad Esfahbod 已提交
576
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
577
    return_trace (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
578 579
  }

580
  protected:
B
Behdad Esfahbod 已提交
581
  HBUINT16	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
582 583
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
B
Behdad Esfahbod 已提交
584
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
585 586 587
  OffsetArrayOf<AlternateSet>
		alternateSet;		/* Array of AlternateSet tables
					 * ordered by Coverage Index */
588
  public:
589
  DEFINE_SIZE_ARRAY (6, alternateSet);
B
Behdad Esfahbod 已提交
590
};
591

B
Behdad Esfahbod 已提交
592 593
struct AlternateSubst
{
594
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
595
		  hb_sorted_array_t<const GlyphID> glyphs,
B
Behdad Esfahbod 已提交
596 597
		  hb_array_t<const unsigned int> alternate_len_list,
		  hb_array_t<const GlyphID> alternate_glyphs_list)
598
  {
B
Behdad Esfahbod 已提交
599
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
600
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
601 602 603
    unsigned int format = 1;
    u.format.set (format);
    switch (u.format) {
B
Behdad Esfahbod 已提交
604
    case 1: return_trace (u.format1.serialize (c, glyphs, alternate_len_list, alternate_glyphs_list));
B
Behdad Esfahbod 已提交
605
    default:return_trace (false);
606 607 608
    }
  }

B
Behdad Esfahbod 已提交
609
  template <typename context_t>
610
  typename context_t::return_t dispatch (context_t *c) const
B
Behdad Esfahbod 已提交
611
  {
612
    TRACE_DISPATCH (this, u.format);
613
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
614
    switch (u.format) {
B
Behdad Esfahbod 已提交
615 616
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
617 618 619
    }
  }

620
  protected:
621
  union {
B
Behdad Esfahbod 已提交
622
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
623
  AlternateSubstFormat1	format1;
624 625 626
  } u;
};

627

B
Behdad Esfahbod 已提交
628 629
struct Ligature
{
630
  bool intersects (const hb_set_t *glyphs) const
631
  {
632
    unsigned int count = component.lenP1;
633 634 635 636 637 638
    for (unsigned int i = 1; i < count; i++)
      if (!glyphs->has (component[i]))
        return false;
    return true;
  }

639
  void closure (hb_closure_context_t *c) const
640
  {
641
    unsigned int count = component.lenP1;
B
Behdad Esfahbod 已提交
642 643
    for (unsigned int i = 1; i < count; i++)
      if (!c->glyphs->has (component[i]))
B
Behdad Esfahbod 已提交
644
        return;
645
    c->out->add (ligGlyph);
646 647
  }

648
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
649
  {
650
    c->input->add_array (component.arrayZ, component.lenP1 ? component.lenP1 - 1 : 0);
B
Minor  
Behdad Esfahbod 已提交
651
    c->output->add (ligGlyph);
652 653
  }

654
  bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
655
  {
B
Behdad Esfahbod 已提交
656
    TRACE_WOULD_APPLY (this);
657
    if (c->len != component.lenP1)
B
Behdad Esfahbod 已提交
658
      return_trace (false);
659 660 661

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

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

667
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
668
  {
B
Behdad Esfahbod 已提交
669
    TRACE_APPLY (this);
670
    unsigned int count = component.lenP1;
B
Behdad Esfahbod 已提交
671

B
Behdad Esfahbod 已提交
672
    if (unlikely (!count)) return_trace (false);
B
Behdad Esfahbod 已提交
673

674 675 676 677 678
    /* 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 已提交
679
      return_trace (true);
680 681
    }

B
Behdad Esfahbod 已提交
682
    unsigned int total_component_count = 0;
683

684
    unsigned int match_length = 0;
685
    unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
686

687 688 689
    if (likely (!match_input (c, count,
			      &component[1],
			      match_glyph,
B
Behdad Esfahbod 已提交
690
			      nullptr,
691 692
			      &match_length,
			      match_positions,
693
			      &total_component_count)))
B
Behdad Esfahbod 已提交
694
      return_trace (false);
695

696 697
    ligate_input (c,
		  count,
698 699
		  match_positions,
		  match_length,
700
		  ligGlyph,
701
		  total_component_count);
702

B
Behdad Esfahbod 已提交
703
    return_trace (true);
704
  }
705

706 707
  bool serialize (hb_serialize_context_t *c,
		  GlyphID ligature,
B
Behdad Esfahbod 已提交
708
		  hb_array_t<const GlyphID> components /* Starting from second */)
709
  {
B
Behdad Esfahbod 已提交
710
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
711
    if (unlikely (!c->extend_min (*this))) return_trace (false);
712
    ligGlyph = ligature;
B
Behdad Esfahbod 已提交
713
    if (unlikely (!component.serialize (c, components))) return_trace (false);
B
Behdad Esfahbod 已提交
714
    return_trace (true);
715 716
  }

B
Behdad Esfahbod 已提交
717
  public:
718
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
719
  {
B
Behdad Esfahbod 已提交
720
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
721
    return_trace (ligGlyph.sanitize (c) && component.sanitize (c));
B
Behdad Esfahbod 已提交
722 723
  }

724
  protected:
725
  GlyphID	ligGlyph;		/* GlyphID of ligature to substitute */
B
Behdad Esfahbod 已提交
726 727
  HeadlessArrayOf<GlyphID>
		component;		/* Array of component GlyphIDs--start
728 729
					 * with the second  component--ordered
					 * in writing direction */
730
  public:
731
  DEFINE_SIZE_ARRAY (4, component);
732
};
B
Behdad Esfahbod 已提交
733

B
Behdad Esfahbod 已提交
734 735
struct LigatureSet
{
736
  bool intersects (const hb_set_t *glyphs) const
737 738 739 740 741 742 743 744
  {
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
      if ((this+ligature[i]).intersects (glyphs))
        return true;
    return false;
  }

745
  void closure (hb_closure_context_t *c) const
746
  {
B
Behdad Esfahbod 已提交
747 748
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
B
Behdad Esfahbod 已提交
749
      (this+ligature[i]).closure (c);
750 751
  }

752
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
753 754 755 756 757 758
  {
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
      (this+ligature[i]).collect_glyphs (c);
  }

759
  bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
760
  {
B
Behdad Esfahbod 已提交
761
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
762 763 764 765
    unsigned int num_ligs = ligature.len;
    for (unsigned int i = 0; i < num_ligs; i++)
    {
      const Ligature &lig = this+ligature[i];
766
      if (lig.would_apply (c))
B
Behdad Esfahbod 已提交
767
        return_trace (true);
B
Behdad Esfahbod 已提交
768
    }
B
Behdad Esfahbod 已提交
769
    return_trace (false);
B
Behdad Esfahbod 已提交
770 771
  }

772
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
773
  {
B
Behdad Esfahbod 已提交
774
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
775
    unsigned int num_ligs = ligature.len;
B
Behdad Esfahbod 已提交
776 777
    for (unsigned int i = 0; i < num_ligs; i++)
    {
B
Behdad Esfahbod 已提交
778
      const Ligature &lig = this+ligature[i];
B
Behdad Esfahbod 已提交
779
      if (lig.apply (c)) return_trace (true);
780 781
    }

B
Behdad Esfahbod 已提交
782
    return_trace (false);
783
  }
B
Behdad Esfahbod 已提交
784

785
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
786 787
		  hb_array_t<const GlyphID> ligatures,
		  hb_array_t<const unsigned int> component_count_list,
788
		  hb_array_t<const GlyphID> &component_list /* Starting from second for each ligature */)
789
  {
B
Behdad Esfahbod 已提交
790
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
791
    if (unlikely (!c->extend_min (*this))) return_trace (false);
792 793
    if (unlikely (!ligature.serialize (c, ligatures.length))) return_trace (false);
    for (unsigned int i = 0; i < ligatures.length; i++)
B
Behdad Esfahbod 已提交
794 795 796 797 798 799 800 801 802
    {
      unsigned int component_count = MAX<int> (component_count_list[i] - 1, 0);
      if (unlikely (!ligature[i].serialize (c, this)
				.serialize (c,
					    ligatures[i],
					    component_list.sub_array (0, component_count))))
	return_trace (false);
      component_list += component_count;
    }
B
Behdad Esfahbod 已提交
803
    return_trace (true);
804 805
  }

806
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
807
  {
B
Behdad Esfahbod 已提交
808
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
809
    return_trace (ligature.sanitize (c, this));
B
Behdad Esfahbod 已提交
810 811
  }

812
  protected:
B
Behdad Esfahbod 已提交
813 814 815
  OffsetArrayOf<Ligature>
		ligature;		/* Array LigatureSet tables
					 * ordered by preference */
816
  public:
817
  DEFINE_SIZE_ARRAY (2, ligature);
B
Behdad Esfahbod 已提交
818 819
};

B
Behdad Esfahbod 已提交
820 821
struct LigatureSubstFormat1
{
822
  bool intersects (const hb_set_t *glyphs) const
823
  {
B
Behdad Esfahbod 已提交
824 825 826 827
    for (auto it = hb_zip (this+coverage, ligatureSet); it; ++it)
      if (glyphs->has (it->first))
        if ((this+it->second).intersects (glyphs))
	  return true;
828 829 830
    return false;
  }

831
  void closure (hb_closure_context_t *c) const
832
  {
B
Behdad Esfahbod 已提交
833 834 835
    for (auto it = hb_zip (this+coverage, ligatureSet); it; ++it)
      if (c->glyphs->has (it->first))
        (this+it->second).closure (c);
836 837
  }

838
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
839
  {
840
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
B
Behdad Esfahbod 已提交
841 842
    for (auto it = hb_zip (this+coverage, ligatureSet); it; ++it)
      (this+it->second).collect_glyphs (c);
843 844
  }

845
  const Coverage &get_coverage () const { return this+coverage; }
846

847
  bool would_apply (hb_would_apply_context_t *c) const
B
Behdad Esfahbod 已提交
848
  {
B
Behdad Esfahbod 已提交
849
    TRACE_WOULD_APPLY (this);
850
    unsigned int index = (this+coverage).get_coverage (c->glyphs[0]);
B
Behdad Esfahbod 已提交
851
    if (likely (index == NOT_COVERED)) return_trace (false);
852 853

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

857
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
858
  {
B
Behdad Esfahbod 已提交
859
    TRACE_APPLY (this);
860

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

B
Behdad Esfahbod 已提交
864
    const LigatureSet &lig_set = this+ligatureSet[index];
B
Behdad Esfahbod 已提交
865
    return_trace (lig_set.apply (c));
866
  }
B
Behdad Esfahbod 已提交
867

868
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
869
		  hb_sorted_array_t<const GlyphID> first_glyphs,
B
Behdad Esfahbod 已提交
870 871 872 873
		  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 */)
874
  {
B
Behdad Esfahbod 已提交
875
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
876
    if (unlikely (!c->extend_min (*this))) return_trace (false);
877 878
    if (unlikely (!ligatureSet.serialize (c, first_glyphs.length))) return_trace (false);
    for (unsigned int i = 0; i < first_glyphs.length; i++)
B
Behdad Esfahbod 已提交
879 880 881 882 883 884 885 886 887 888 889
    {
      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));
890 891
  }

892
  bool subset (hb_subset_context_t *c) const
893 894 895 896 897 898
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

899
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
900
  {
B
Behdad Esfahbod 已提交
901
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
902
    return_trace (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
903 904
  }

905
  protected:
B
Behdad Esfahbod 已提交
906
  HBUINT16	format;			/* Format identifier--format = 1 */
B
Behdad Esfahbod 已提交
907 908
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
909
					 * beginning of Substitution table */
B
Behdad Esfahbod 已提交
910
  OffsetArrayOf<LigatureSet>
B
Behdad Esfahbod 已提交
911 912
		ligatureSet;		/* Array LigatureSet tables
					 * ordered by Coverage Index */
913
  public:
914
  DEFINE_SIZE_ARRAY (6, ligatureSet);
B
Behdad Esfahbod 已提交
915
};
916

B
Behdad Esfahbod 已提交
917 918
struct LigatureSubst
{
919
  bool serialize (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
920
		  hb_sorted_array_t<const GlyphID> first_glyphs,
B
Behdad Esfahbod 已提交
921 922 923 924
		  hb_array_t<const unsigned int> ligature_per_first_glyph_count_list,
		  hb_array_t<const GlyphID> ligatures_list,
		  hb_array_t<const unsigned int> component_count_list,
		  hb_array_t<const GlyphID> component_list /* Starting from second for each ligature */)
925
  {
B
Behdad Esfahbod 已提交
926
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
927
    if (unlikely (!c->extend_min (u.format))) return_trace (false);
928 929 930
    unsigned int format = 1;
    u.format.set (format);
    switch (u.format) {
B
Behdad Esfahbod 已提交
931 932 933 934 935 936 937
    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);
938 939 940
    }
  }

B
Behdad Esfahbod 已提交
941
  template <typename context_t>
942
  typename context_t::return_t dispatch (context_t *c) const
B
Behdad Esfahbod 已提交
943
  {
944
    TRACE_DISPATCH (this, u.format);
945
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
946
    switch (u.format) {
B
Behdad Esfahbod 已提交
947 948
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
949 950 951
    }
  }

952
  protected:
953
  union {
B
Behdad Esfahbod 已提交
954
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
955
  LigatureSubstFormat1	format1;
956 957 958
  } u;
};

B
Behdad Esfahbod 已提交
959

B
Minor  
Behdad Esfahbod 已提交
960
struct ContextSubst : Context {};
B
Behdad Esfahbod 已提交
961

B
Minor  
Behdad Esfahbod 已提交
962
struct ChainContextSubst : ChainContext {};
963

B
Behdad Esfahbod 已提交
964
struct ExtensionSubst : Extension<ExtensionSubst>
B
Behdad Esfahbod 已提交
965
{
B
Behdad Esfahbod 已提交
966
  typedef struct SubstLookupSubTable SubTable;
B
Behdad Esfahbod 已提交
967

968
  bool is_reverse () const;
969 970 971
};


B
Behdad Esfahbod 已提交
972 973
struct ReverseChainSingleSubstFormat1
{
974
  bool intersects (const hb_set_t *glyphs) const
975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995
  {
    if (!(this+coverage).intersects (glyphs))
      return false;

    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);

    unsigned int count;

    count = backtrack.len;
    for (unsigned int i = 0; i < count; i++)
      if (!(this+backtrack[i]).intersects (glyphs))
        return false;

    count = lookahead.len;
    for (unsigned int i = 0; i < count; i++)
      if (!(this+lookahead[i]).intersects (glyphs))
        return false;

    return true;
  }

996
  void closure (hb_closure_context_t *c) const
997
  {
B
Behdad Esfahbod 已提交
998 999 1000 1001 1002 1003 1004
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);

    unsigned int count;

    count = backtrack.len;
    for (unsigned int i = 0; i < count; i++)
      if (!(this+backtrack[i]).intersects (c->glyphs))
B
Behdad Esfahbod 已提交
1005
        return;
B
Behdad Esfahbod 已提交
1006 1007 1008 1009

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

    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
B
Behdad Esfahbod 已提交
1013 1014 1015
    for (auto it = hb_zip (this+coverage, substitute); it; ++it)
      if (c->glyphs->has (it->first))
        c->out->add (it->second);
1016 1017
  }

1018
  void collect_glyphs (hb_collect_glyphs_context_t *c) const
1019
  {
1020
    if (unlikely (!(this+coverage).add_coverage (c->input))) return;
1021 1022 1023 1024 1025

    unsigned int count;

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

1028
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1029 1030
    count = lookahead.len;
    for (unsigned int i = 0; i < count; i++)
1031
      if (unlikely (!(this+lookahead[i]).add_coverage (c->after))) return;
1032 1033 1034

    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
    count = substitute.len;
1035
    c->output->add_array (substitute.arrayZ, substitute.len);
1036 1037
  }

1038
  const Coverage &get_coverage () const { return this+coverage; }
1039

1040
  bool would_apply (hb_would_apply_context_t *c) const
1041
  {
B
Behdad Esfahbod 已提交
1042
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
1043
    return_trace (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED);
1044 1045
  }

1046
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1047
  {
B
Behdad Esfahbod 已提交
1048
    TRACE_APPLY (this);
1049
    if (unlikely (c->nesting_level_left != HB_MAX_NESTING_LEVEL))
B
Behdad Esfahbod 已提交
1050
      return_trace (false); /* No chaining to this type */
1051

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

1055 1056
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
1057

1058
  unsigned int start_index = 0, end_index = 0;
B
Behdad Esfahbod 已提交
1059
    if (match_backtrack (c,
1060
			 backtrack.len, (HBUINT16 *) backtrack.arrayZ,
1061 1062
			 match_coverage, this,
			 &start_index) &&
B
Behdad Esfahbod 已提交
1063
        match_lookahead (c,
1064
			 lookahead.len, (HBUINT16 *) lookahead.arrayZ,
B
Behdad Esfahbod 已提交
1065
			 match_coverage, this,
1066
			 1, &end_index))
1067
    {
1068
      c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index);
B
Behdad Esfahbod 已提交
1069
      c->replace_glyph_inplace (substitute[index]);
1070 1071 1072
      /* 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 已提交
1073
      return_trace (true);
1074 1075
    }

B
Behdad Esfahbod 已提交
1076
    return_trace (false);
1077
  }
B
Behdad Esfahbod 已提交
1078

1079
  bool subset (hb_subset_context_t *c) const
1080 1081 1082 1083 1084 1085
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

1086
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
1087
  {
B
Behdad Esfahbod 已提交
1088
    TRACE_SANITIZE (this);
1089
    if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
B
Behdad Esfahbod 已提交
1090
      return_trace (false);
B
Behdad Esfahbod 已提交
1091
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
B
Behdad Esfahbod 已提交
1092
    if (!lookahead.sanitize (c, this))
B
Behdad Esfahbod 已提交
1093
      return_trace (false);
B
Behdad Esfahbod 已提交
1094
    const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
B
Behdad Esfahbod 已提交
1095
    return_trace (substitute.sanitize (c));
B
Behdad Esfahbod 已提交
1096 1097
  }

1098
  protected:
B
Behdad Esfahbod 已提交
1099
  HBUINT16	format;			/* Format identifier--format = 1 */
1100 1101 1102 1103 1104
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of table */
  OffsetArrayOf<Coverage>
		backtrack;		/* Array of coverage tables
1105
					 * in backtracking sequence, in glyph
B
Behdad Esfahbod 已提交
1106
					 * sequence order */
1107 1108 1109
  OffsetArrayOf<Coverage>
		lookaheadX;		/* Array of coverage tables
					 * in lookahead sequence, in glyph
B
Behdad Esfahbod 已提交
1110
					 * sequence order */
1111 1112 1113
  ArrayOf<GlyphID>
		substituteX;		/* Array of substitute
					 * GlyphIDs--ordered by Coverage Index */
1114
  public:
B
Behdad Esfahbod 已提交
1115
  DEFINE_SIZE_MIN (10);
B
Behdad Esfahbod 已提交
1116 1117
};

B
Behdad Esfahbod 已提交
1118 1119
struct ReverseChainSingleSubst
{
1120
  template <typename context_t>
1121
  typename context_t::return_t dispatch (context_t *c) const
1122
  {
1123
    TRACE_DISPATCH (this, u.format);
1124
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1125
    switch (u.format) {
B
Behdad Esfahbod 已提交
1126 1127
    case 1: return_trace (c->dispatch (u.format1));
    default:return_trace (c->default_return_value ());
1128 1129 1130
    }
  }

1131
  protected:
1132
  union {
B
Behdad Esfahbod 已提交
1133
  HBUINT16				format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1134
  ReverseChainSingleSubstFormat1	format1;
1135 1136 1137 1138 1139
  } u;
};



B
Behdad Esfahbod 已提交
1140 1141 1142 1143
/*
 * SubstLookup
 */

B
Behdad Esfahbod 已提交
1144 1145
struct SubstLookupSubTable
{
B
Behdad Esfahbod 已提交
1146
  friend struct Lookup;
B
Behdad Esfahbod 已提交
1147 1148
  friend struct SubstLookup;

B
Behdad Esfahbod 已提交
1149
  enum Type {
1150 1151 1152 1153 1154 1155 1156
    Single		= 1,
    Multiple		= 2,
    Alternate		= 3,
    Ligature		= 4,
    Context		= 5,
    ChainContext	= 6,
    Extension		= 7,
1157
    ReverseChainSingle	= 8
1158 1159
  };

1160
  template <typename context_t>
1161
  typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
1162
  {
1163
    TRACE_DISPATCH (this, lookup_type);
1164
    switch (lookup_type) {
B
Behdad Esfahbod 已提交
1165 1166 1167 1168 1169 1170 1171 1172 1173
    case Single:		return_trace (u.single.dispatch (c));
    case Multiple:		return_trace (u.multiple.dispatch (c));
    case Alternate:		return_trace (u.alternate.dispatch (c));
    case Ligature:		return_trace (u.ligature.dispatch (c));
    case Context:		return_trace (u.context.dispatch (c));
    case ChainContext:		return_trace (u.chainContext.dispatch (c));
    case Extension:		return_trace (u.extension.dispatch (c));
    case ReverseChainSingle:	return_trace (u.reverseChainContextSingle.dispatch (c));
    default:			return_trace (c->default_return_value ());
1174 1175 1176
    }
  }

1177
  protected:
B
Behdad Esfahbod 已提交
1178
  union {
B
Behdad Esfahbod 已提交
1179 1180 1181 1182
  SingleSubst			single;
  MultipleSubst			multiple;
  AlternateSubst		alternate;
  LigatureSubst			ligature;
1183
  ContextSubst			context;
B
Behdad Esfahbod 已提交
1184 1185 1186
  ChainContextSubst		chainContext;
  ExtensionSubst		extension;
  ReverseChainSingleSubst	reverseChainContextSingle;
B
Behdad Esfahbod 已提交
1187
  } u;
B
Behdad Esfahbod 已提交
1188
  public:
B
Behdad Esfahbod 已提交
1189
  DEFINE_SIZE_MIN (0);
B
Behdad Esfahbod 已提交
1190 1191
};

1192

B
Behdad Esfahbod 已提交
1193 1194
struct SubstLookup : Lookup
{
B
Behdad Esfahbod 已提交
1195 1196
  typedef SubstLookupSubTable SubTable;

1197
  const SubTable& get_subtable (unsigned int i) const
B
Behdad Esfahbod 已提交
1198
  { return Lookup::get_subtable<SubTable> (i); }
B
Behdad Esfahbod 已提交
1199

1200
  static bool lookup_type_is_reverse (unsigned int lookup_type)
B
Behdad Esfahbod 已提交
1201
  { return lookup_type == SubTable::ReverseChainSingle; }
B
Behdad Esfahbod 已提交
1202

1203
  bool is_reverse () const
B
Behdad Esfahbod 已提交
1204
  {
B
Behdad Esfahbod 已提交
1205
    unsigned int type = get_type ();
B
Behdad Esfahbod 已提交
1206
    if (unlikely (type == SubTable::Extension))
1207
      return CastR<ExtensionSubst> (get_subtable(0)).is_reverse ();
B
Behdad Esfahbod 已提交
1208
    return lookup_type_is_reverse (type);
B
Behdad Esfahbod 已提交
1209
  }
1210

1211
  bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1212 1213
  {
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
1214
    return_trace (dispatch (c));
B
Behdad Esfahbod 已提交
1215 1216
  }

1217
  bool intersects (const hb_set_t *glyphs) const
1218 1219 1220 1221 1222
  {
    hb_intersects_context_t c (glyphs);
    return dispatch (&c);
  }

1223
  hb_closure_context_t::return_t closure (hb_closure_context_t *c, unsigned int this_index) const
1224
  {
1225
    if (!c->should_visit_lookup (this_index))
B
Behdad Esfahbod 已提交
1226
      return hb_closure_context_t::default_return_value ();
1227 1228

    c->set_recurse_func (dispatch_closure_recurse_func);
1229 1230 1231 1232 1233

    hb_closure_context_t::return_t ret = dispatch (c);

    c->flush ();

B
Behdad Esfahbod 已提交
1234
    return ret;
B
Behdad Esfahbod 已提交
1235 1236
  }

1237
  hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
B
Behdad Esfahbod 已提交
1238
  {
1239
    c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>);
B
Behdad Esfahbod 已提交
1240
    return dispatch (c);
1241 1242
  }

B
Behdad Esfahbod 已提交
1243
  template <typename set_t>
1244
  void add_coverage (set_t *glyphs) const
B
Behdad Esfahbod 已提交
1245
  {
1246 1247
    hb_add_coverage_context_t<set_t> c (glyphs);
    dispatch (&c);
B
Behdad Esfahbod 已提交
1248 1249
  }

1250 1251
  bool would_apply (hb_would_apply_context_t *c,
		    const hb_ot_layout_lookup_accelerator_t *accel) const
B
Behdad Esfahbod 已提交
1252
  {
B
Behdad Esfahbod 已提交
1253
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
1254 1255 1256
    if (unlikely (!c->len))  return_trace (false);
    if (!accel->may_have (c->glyphs[0]))  return_trace (false);
      return_trace (dispatch (c));
B
Behdad Esfahbod 已提交
1257 1258
  }

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

1261
  SubTable& serialize_subtable (hb_serialize_context_t *c,
B
Behdad Esfahbod 已提交
1262 1263
				       unsigned int i)
  { return get_subtables<SubTable> ()[i].serialize (c, this); }
1264

1265 1266
  bool serialize_single (hb_serialize_context_t *c,
			 uint32_t lookup_props,
B
Behdad Esfahbod 已提交
1267
		         hb_sorted_array_t<const GlyphID> glyphs,
B
Behdad Esfahbod 已提交
1268
		         hb_array_t<const GlyphID> substitutes)
1269
  {
B
Behdad Esfahbod 已提交
1270
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1271
    if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1272
    return_trace (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes));
1273 1274
  }

1275 1276
  bool serialize_multiple (hb_serialize_context_t *c,
			   uint32_t lookup_props,
B
Behdad Esfahbod 已提交
1277
			   hb_sorted_array_t<const GlyphID> glyphs,
B
Behdad Esfahbod 已提交
1278 1279
			   hb_array_t<const unsigned int> substitute_len_list,
			   hb_array_t<const GlyphID> substitute_glyphs_list)
1280
  {
B
Behdad Esfahbod 已提交
1281
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1282
    if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1283 1284 1285 1286
    return_trace (serialize_subtable (c, 0).u.multiple.serialize (c,
								  glyphs,
								  substitute_len_list,
								  substitute_glyphs_list));
1287 1288
  }

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

1303 1304
  bool serialize_ligature (hb_serialize_context_t *c,
			   uint32_t lookup_props,
B
Behdad Esfahbod 已提交
1305
			   hb_sorted_array_t<const GlyphID> first_glyphs,
B
Behdad Esfahbod 已提交
1306 1307 1308 1309
			   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 */)
1310
  {
B
Behdad Esfahbod 已提交
1311
    TRACE_SERIALIZE (this);
B
Behdad Esfahbod 已提交
1312
    if (unlikely (!Lookup::serialize (c, SubTable::Ligature, lookup_props, 1))) return_trace (false);
B
Behdad Esfahbod 已提交
1313 1314 1315 1316 1317 1318
    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));
1319 1320
  }

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

1324
  static hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned int lookup_index)
1325
  {
1326
    if (!c->should_visit_lookup (lookup_index))
1327
      return hb_void_t ();
1328 1329 1330

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

1331 1332 1333 1334
    /* 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 ();
1335 1336

    return ret;
1337 1338
  }

B
Behdad Esfahbod 已提交
1339
  template <typename context_t>
1340
  typename context_t::return_t dispatch (context_t *c) const
B
Behdad Esfahbod 已提交
1341 1342
  { return Lookup::dispatch<SubTable> (c); }

1343
  bool subset (hb_subset_context_t *c) const
1344
  { return Lookup::subset<SubTable> (c); }
B
Behdad Esfahbod 已提交
1345

1346
  bool sanitize (hb_sanitize_context_t *c) const
B
Behdad Esfahbod 已提交
1347
  { return Lookup::sanitize<SubTable> (c); }
B
Behdad Esfahbod 已提交
1348 1349
};

B
Minor  
Behdad Esfahbod 已提交
1350
/*
1351 1352
 * GSUB -- Glyph Substitution
 * https://docs.microsoft.com/en-us/typography/opentype/spec/gsub
B
Minor  
Behdad Esfahbod 已提交
1353 1354
 */

B
Behdad Esfahbod 已提交
1355 1356
struct GSUB : GSUBGPOS
{
1357
  enum { tableTag = HB_OT_TAG_GSUB };
B
Minor  
Behdad Esfahbod 已提交
1358

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

1362
  bool subset (hb_subset_context_t *c) const
1363
  { return GSUBGPOS::subset<SubstLookup> (c); }
1364

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

1368 1369 1370
  HB_INTERNAL bool is_blacklisted (hb_blob_t *blob,
				   hb_face_t *face) const;

B
WIP  
Behdad Esfahbod 已提交
1371
  typedef GSUBGPOS::accelerator_t<GSUB> accelerator_t;
B
Minor  
Behdad Esfahbod 已提交
1372
};
1373 1374


B
Behdad Esfahbod 已提交
1375 1376 1377
struct GSUB_accelerator_t : GSUB::accelerator_t {};


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

1380
/*static*/ inline bool ExtensionSubst::is_reverse () const
B
Behdad Esfahbod 已提交
1381 1382
{
  unsigned int type = get_type ();
B
Behdad Esfahbod 已提交
1383 1384
  if (unlikely (type == SubTable::Extension))
    return CastR<ExtensionSubst> (get_subtable<SubTable>()).is_reverse ();
B
Behdad Esfahbod 已提交
1385 1386 1387
  return SubstLookup::lookup_type_is_reverse (type);
}

1388
template <typename context_t>
1389
/*static*/ inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
1390
{
B
Behdad Esfahbod 已提交
1391
  const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index);
1392
  return l.dispatch (c);
1393 1394
}

1395
/*static*/ inline bool SubstLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index)
B
Behdad Esfahbod 已提交
1396
{
B
Behdad Esfahbod 已提交
1397
  const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index);
1398
  unsigned int saved_lookup_props = c->lookup_props;
1399 1400 1401
  unsigned int saved_lookup_index = c->lookup_index;
  c->set_lookup_index (lookup_index);
  c->set_lookup_props (l.get_props ());
1402
  bool ret = l.dispatch (c);
1403
  c->set_lookup_index (saved_lookup_index);
1404
  c->set_lookup_props (saved_lookup_props);
1405
  return ret;
1406 1407
}

B
Behdad Esfahbod 已提交
1408
} /* namespace OT */
1409

B
Behdad Esfahbod 已提交
1410

1411
#endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */