hb-ot-layout-gsubgpos.hh 89.8 KB
Newer Older
1
/*
B
Behdad Esfahbod 已提交
2
 * Copyright © 2007,2008,2009,2010  Red Hat, Inc.
B
Behdad Esfahbod 已提交
3
 * Copyright © 2010,2012  Google, Inc.
4
 *
B
Behdad Esfahbod 已提交
5
 *  This is part of HarfBuzz, a text shaping library.
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
27 28
 */

29 30
#ifndef HB_OT_LAYOUT_GSUBGPOS_HH
#define HB_OT_LAYOUT_GSUBGPOS_HH
31

32 33 34 35
#include "hb.hh"
#include "hb-buffer.hh"
#include "hb-map.hh"
#include "hb-set.hh"
36
#include "hb-ot-map.hh"
37 38
#include "hb-ot-layout-common.hh"
#include "hb-ot-layout-gdef-table.hh"
39

40

41 42
namespace OT {

B
Behdad Esfahbod 已提交
43

44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
struct hb_intersects_context_t :
       hb_dispatch_context_t<hb_intersects_context_t, bool, 0>
{
  inline const char *get_name (void) { return "INTERSECTS"; }
  template <typename T>
  inline return_t dispatch (const T &obj) { return obj.intersects (this->glyphs); }
  static return_t default_return_value (void) { return false; }
  bool stop_sublookup_iteration (return_t r) const { return r; }

  const hb_set_t *glyphs;
  unsigned int debug_depth;

  hb_intersects_context_t (const hb_set_t *glyphs_) :
			     glyphs (glyphs_),
			     debug_depth (0) {}
};

B
Behdad Esfahbod 已提交
61 62
struct hb_closure_context_t :
       hb_dispatch_context_t<hb_closure_context_t, hb_void_t, HB_DEBUG_CLOSURE>
63
{
64
  inline const char *get_name (void) { return "CLOSURE"; }
65 66
  typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
  template <typename T>
67
  inline return_t dispatch (const T &obj) { obj.closure (this); return HB_VOID; }
68
  static return_t default_return_value (void) { return HB_VOID; }
69
  bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
70
  void recurse (unsigned int lookup_index)
71
  {
72
    if (unlikely (nesting_level_left == 0 || !recurse_func))
73
      return;
74 75 76 77 78 79

    nesting_level_left--;
    recurse_func (this, lookup_index);
    nesting_level_left++;
  }

80
  bool should_visit_lookup (unsigned int lookup_index)
81 82 83 84 85 86 87 88 89
  {
    if (is_lookup_done (lookup_index))
      return false;
    done_lookups->set (lookup_index, glyphs->get_population ());
    return true;
  }

  bool is_lookup_done (unsigned int lookup_index)
  {
90
    /* Have we visited this lookup with the current set of glyphs? */
91 92 93
    return done_lookups->get (lookup_index) == glyphs->get_population ();
  }

94
  hb_face_t *face;
95
  hb_set_t *glyphs;
96
  hb_set_t out[1];
97
  recurse_func_t recurse_func;
98 99 100 101
  unsigned int nesting_level_left;
  unsigned int debug_depth;

  hb_closure_context_t (hb_face_t *face_,
102
			hb_set_t *glyphs_,
E
Ebrahim Byagowi 已提交
103 104
			hb_map_t *done_lookups_,
			unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
105 106
			  face (face_),
			  glyphs (glyphs_),
B
Behdad Esfahbod 已提交
107
			  recurse_func (nullptr),
108
			  nesting_level_left (nesting_level_left_),
109
			  debug_depth (0),
E
Ebrahim Byagowi 已提交
110
			  done_lookups (done_lookups_) {}
111

112 113 114 115 116
  ~hb_closure_context_t (void)
  {
    flush ();
  }

117
  void set_recurse_func (recurse_func_t func) { recurse_func = func; }
118

119 120 121 122 123 124
  void flush (void)
  {
    hb_set_union (glyphs, out);
    hb_set_clear (out);
  }

125 126
  private:
  hb_map_t *done_lookups;
127 128 129
};


B
Behdad Esfahbod 已提交
130 131
struct hb_would_apply_context_t :
       hb_dispatch_context_t<hb_would_apply_context_t, bool, HB_DEBUG_WOULD_APPLY>
132
{
133
  inline const char *get_name (void) { return "WOULD_APPLY"; }
B
Behdad Esfahbod 已提交
134
  template <typename T>
135
  inline return_t dispatch (const T &obj) { return obj.would_apply (this); }
B
Behdad Esfahbod 已提交
136
  static return_t default_return_value (void) { return false; }
137
  bool stop_sublookup_iteration (return_t r) const { return r; }
B
Behdad Esfahbod 已提交
138

139
  hb_face_t *face;
140
  const hb_codepoint_t *glyphs;
141
  unsigned int len;
142
  bool zero_context;
143 144 145
  unsigned int debug_depth;

  hb_would_apply_context_t (hb_face_t *face_,
146 147
			    const hb_codepoint_t *glyphs_,
			    unsigned int len_,
B
Behdad Esfahbod 已提交
148
			    bool zero_context_) :
149
			      face (face_),
150 151
			      glyphs (glyphs_),
			      len (len_),
152
			      zero_context (zero_context_),
153
			      debug_depth (0) {}
154 155 156
};


B
Behdad Esfahbod 已提交
157 158
struct hb_collect_glyphs_context_t :
       hb_dispatch_context_t<hb_collect_glyphs_context_t, hb_void_t, HB_DEBUG_COLLECT_GLYPHS>
159
{
160
  inline const char *get_name (void) { return "COLLECT_GLYPHS"; }
B
Behdad Esfahbod 已提交
161
  typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index);
B
Behdad Esfahbod 已提交
162
  template <typename T>
163
  inline return_t dispatch (const T &obj) { obj.collect_glyphs (this); return HB_VOID; }
164
  static return_t default_return_value (void) { return HB_VOID; }
165
  bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
166
  void recurse (unsigned int lookup_index)
B
Behdad Esfahbod 已提交
167
  {
B
Behdad Esfahbod 已提交
168
    if (unlikely (nesting_level_left == 0 || !recurse_func))
169
      return;
B
Behdad Esfahbod 已提交
170

B
Behdad Esfahbod 已提交
171
    /* Note that GPOS sets recurse_func to nullptr already, so it doesn't get
172
     * past the previous check.  For GSUB, we only want to collect the output
173 174 175 176 177 178 179
     * glyphs in the recursion.  If output is not requested, we can go home now.
     *
     * Note further, that the above is not exactly correct.  A recursed lookup
     * is allowed to match input that is not matched in the context, but that's
     * not how most fonts are built.  It's possible to relax that and recurse
     * with all sets here if it proves to be an issue.
     */
180 181

    if (output == hb_set_get_empty ())
182
      return;
183

184
    /* Return if new lookup was recursed to before. */
B
Behdad Esfahbod 已提交
185
    if (recursed_lookups->has (lookup_index))
186
      return;
187

188 189 190 191
    hb_set_t *old_before = before;
    hb_set_t *old_input  = input;
    hb_set_t *old_after  = after;
    before = input = after = hb_set_get_empty ();
192

B
Behdad Esfahbod 已提交
193
    nesting_level_left--;
194
    recurse_func (this, lookup_index);
B
Behdad Esfahbod 已提交
195
    nesting_level_left++;
196 197 198 199 200

    before = old_before;
    input  = old_input;
    after  = old_after;

B
Behdad Esfahbod 已提交
201
    recursed_lookups->add (lookup_index);
B
Behdad Esfahbod 已提交
202 203
  }

204
  hb_face_t *face;
B
Minor  
Behdad Esfahbod 已提交
205 206 207 208
  hb_set_t *before;
  hb_set_t *input;
  hb_set_t *after;
  hb_set_t *output;
B
Behdad Esfahbod 已提交
209
  recurse_func_t recurse_func;
B
Behdad Esfahbod 已提交
210
  hb_set_t *recursed_lookups;
B
Behdad Esfahbod 已提交
211
  unsigned int nesting_level_left;
212 213 214
  unsigned int debug_depth;

  hb_collect_glyphs_context_t (hb_face_t *face_,
E
Ebrahim Byagowi 已提交
215 216 217 218
			       hb_set_t  *glyphs_before, /* OUT.  May be NULL */
			       hb_set_t  *glyphs_input,  /* OUT.  May be NULL */
			       hb_set_t  *glyphs_after,  /* OUT.  May be NULL */
			       hb_set_t  *glyphs_output, /* OUT.  May be NULL */
219
			       unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
220
			      face (face_),
B
Minor  
Behdad Esfahbod 已提交
221 222 223 224
			      before (glyphs_before ? glyphs_before : hb_set_get_empty ()),
			      input  (glyphs_input  ? glyphs_input  : hb_set_get_empty ()),
			      after  (glyphs_after  ? glyphs_after  : hb_set_get_empty ()),
			      output (glyphs_output ? glyphs_output : hb_set_get_empty ()),
B
Behdad Esfahbod 已提交
225
			      recurse_func (nullptr),
226
			      recursed_lookups (hb_set_create ()),
B
Behdad Esfahbod 已提交
227
			      nesting_level_left (nesting_level_left_),
228 229
			      debug_depth (0) {}
  ~hb_collect_glyphs_context_t (void) { hb_set_destroy (recursed_lookups); }
B
Behdad Esfahbod 已提交
230 231

  void set_recurse_func (recurse_func_t func) { recurse_func = func; }
232 233 234 235
};



236
template <typename set_t>
B
Behdad Esfahbod 已提交
237 238
struct hb_add_coverage_context_t :
       hb_dispatch_context_t<hb_add_coverage_context_t<set_t>, const Coverage &, HB_DEBUG_GET_COVERAGE>
239
{
240
  inline const char *get_name (void) { return "GET_COVERAGE"; }
241 242
  typedef const Coverage &return_t;
  template <typename T>
243
  inline return_t dispatch (const T &obj) { return obj.get_coverage (); }
244
  static return_t default_return_value (void) { return Null(Coverage); }
245 246 247 248 249
  bool stop_sublookup_iteration (return_t r) const
  {
    r.add_coverage (set);
    return false;
  }
B
Behdad Esfahbod 已提交
250

251 252
  hb_add_coverage_context_t (set_t *set_) :
			    set (set_),
253 254
			    debug_depth (0) {}

255
  set_t *set;
256
  unsigned int debug_depth;
257 258 259
};


260 261
struct hb_ot_apply_context_t :
       hb_dispatch_context_t<hb_ot_apply_context_t, bool, HB_DEBUG_APPLY>
262
{
263
  struct matcher_t
B
Behdad Esfahbod 已提交
264
  {
265 266
    inline matcher_t (void) :
	     lookup_props (0),
267 268
	     ignore_zwnj (false),
	     ignore_zwj (false),
269 270 271 272
	     mask (-1),
#define arg1(arg) (arg) /* Remove the macro to see why it's needed! */
	     syllable arg1(0),
#undef arg1
B
Behdad Esfahbod 已提交
273
	     match_func (nullptr),
274
	     match_data (nullptr) {}
275

B
Behdad Esfahbod 已提交
276
    typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data);
277 278

    inline void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; }
279
    inline void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
280 281 282 283 284 285 286
    inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
    inline void set_mask (hb_mask_t mask_) { mask = mask_; }
    inline void set_syllable (uint8_t syllable_)  { syllable = syllable_; }
    inline void set_match_func (match_func_t match_func_,
				const void *match_data_)
    { match_func = match_func_; match_data = match_data_; }

287 288 289 290 291 292 293
    enum may_match_t {
      MATCH_NO,
      MATCH_YES,
      MATCH_MAYBE
    };

    inline may_match_t may_match (const hb_glyph_info_t &info,
E
Ebrahim Byagowi 已提交
294
				  const HBUINT16        *glyph_data) const
B
Behdad Esfahbod 已提交
295
    {
296 297 298 299 300
      if (!(info.mask & mask) ||
	  (syllable && syllable != info.syllable ()))
	return MATCH_NO;

      if (match_func)
E
Ebrahim Byagowi 已提交
301
	return match_func (info.codepoint, *glyph_data, match_data) ? MATCH_YES : MATCH_NO;
302 303

      return MATCH_MAYBE;
B
Behdad Esfahbod 已提交
304
    }
305 306 307 308 309 310 311 312

    enum may_skip_t {
      SKIP_NO,
      SKIP_YES,
      SKIP_MAYBE
    };

    inline may_skip_t
313
    may_skip (const hb_ot_apply_context_t *c,
314
	      const hb_glyph_info_t    &info) const
B
Behdad Esfahbod 已提交
315
    {
B
Behdad Esfahbod 已提交
316
      if (!c->check_glyph_property (&info, lookup_props))
317 318
	return SKIP_YES;

319
      if (unlikely (_hb_glyph_info_is_default_ignorable_and_not_hidden (&info) &&
320
		    (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) &&
321
		    (ignore_zwj || !_hb_glyph_info_is_zwj (&info))))
322 323 324
	return SKIP_MAYBE;

      return SKIP_NO;
B
Behdad Esfahbod 已提交
325
    }
326 327 328 329

    protected:
    unsigned int lookup_props;
    bool ignore_zwnj;
330
    bool ignore_zwj;
331 332 333 334 335 336
    hb_mask_t mask;
    uint8_t syllable;
    match_func_t match_func;
    const void *match_data;
  };

337
  struct skipping_iterator_t
338
  {
339
    inline void init (hb_ot_apply_context_t *c_, bool context_match = false)
B
Behdad Esfahbod 已提交
340
    {
341
      c = c_;
B
Behdad Esfahbod 已提交
342 343
      match_glyph_data = nullptr;
      matcher.set_match_func (nullptr, nullptr);
344
      matcher.set_lookup_props (c->lookup_props);
B
Behdad Esfahbod 已提交
345
      /* Ignore ZWNJ if we are matching GPOS, or matching GSUB context and asked to. */
346
      matcher.set_ignore_zwnj (c->table_index == 1 || (context_match && c->auto_zwnj));
B
Behdad Esfahbod 已提交
347 348
      /* Ignore ZWJ if we are matching context, or asked to. */
      matcher.set_ignore_zwj  (context_match || c->auto_zwj);
349 350 351 352 353
      matcher.set_mask (context_match ? -1 : c->lookup_mask);
    }
    inline void set_lookup_props (unsigned int lookup_props)
    {
      matcher.set_lookup_props (lookup_props);
B
Behdad Esfahbod 已提交
354
    }
B
Behdad Esfahbod 已提交
355 356
    inline void set_match_func (matcher_t::match_func_t match_func_,
				const void *match_data_,
B
Behdad Esfahbod 已提交
357
				const HBUINT16 glyph_data[])
358
    {
B
Behdad Esfahbod 已提交
359
      matcher.set_match_func (match_func_, match_data_);
360
      match_glyph_data = glyph_data;
361
    }
362

363 364 365 366 367 368 369 370 371
    inline void reset (unsigned int start_index_,
		       unsigned int num_items_)
    {
      idx = start_index_;
      num_items = num_items_;
      end = c->buffer->len;
      matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
    }

372
    inline void reject (void) { num_items++; match_glyph_data--; }
373

374
    inline matcher_t::may_skip_t
B
Behdad Esfahbod 已提交
375
    may_skip (const hb_glyph_info_t    &info) const
376 377 378 379
    {
      return matcher.may_skip (c, info);
    }

B
Behdad Esfahbod 已提交
380
    inline bool next (void)
B
Behdad Esfahbod 已提交
381
    {
382
      assert (num_items > 0);
383
      while (idx + num_items < end)
B
Behdad Esfahbod 已提交
384
      {
B
Behdad Esfahbod 已提交
385
	idx++;
386 387
	const hb_glyph_info_t &info = c->buffer->info[idx];

B
Minor  
Behdad Esfahbod 已提交
388
	matcher_t::may_skip_t skip = matcher.may_skip (c, info);
389 390 391
	if (unlikely (skip == matcher_t::SKIP_YES))
	  continue;

392
	matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
B
Behdad Esfahbod 已提交
393 394 395
	if (match == matcher_t::MATCH_YES ||
	    (match == matcher_t::MATCH_MAYBE &&
	     skip == matcher_t::SKIP_NO))
396 397 398 399 400 401 402
	{
	  num_items--;
	  match_glyph_data++;
	  return true;
	}

	if (skip == matcher_t::SKIP_NO)
B
Behdad Esfahbod 已提交
403
	  return false;
404 405
      }
      return false;
B
Behdad Esfahbod 已提交
406
    }
B
Behdad Esfahbod 已提交
407
    inline bool prev (void)
B
Behdad Esfahbod 已提交
408
    {
409
      assert (num_items > 0);
B
Behdad Esfahbod 已提交
410
      while (idx > num_items - 1)
B
Behdad Esfahbod 已提交
411 412
      {
	idx--;
413 414
	const hb_glyph_info_t &info = c->buffer->out_info[idx];

B
Minor  
Behdad Esfahbod 已提交
415
	matcher_t::may_skip_t skip = matcher.may_skip (c, info);
416 417 418
	if (unlikely (skip == matcher_t::SKIP_YES))
	  continue;

419
	matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
B
Behdad Esfahbod 已提交
420 421 422
	if (match == matcher_t::MATCH_YES ||
	    (match == matcher_t::MATCH_MAYBE &&
	     skip == matcher_t::SKIP_NO))
423 424 425 426 427 428 429
	{
	  num_items--;
	  match_glyph_data++;
	  return true;
	}

	if (skip == matcher_t::SKIP_NO)
B
Behdad Esfahbod 已提交
430
	  return false;
431 432
      }
      return false;
B
Behdad Esfahbod 已提交
433 434 435
    }

    unsigned int idx;
436
    protected:
437
    hb_ot_apply_context_t *c;
438
    matcher_t matcher;
B
Behdad Esfahbod 已提交
439
    const HBUINT16 *match_glyph_data;
440

B
Behdad Esfahbod 已提交
441
    unsigned int num_items;
442
    unsigned int end;
B
Behdad Esfahbod 已提交
443 444
  };

B
Behdad Esfahbod 已提交
445 446

  inline const char *get_name (void) { return "APPLY"; }
447
  typedef return_t (*recurse_func_t) (hb_ot_apply_context_t *c, unsigned int lookup_index);
B
Behdad Esfahbod 已提交
448 449 450 451
  template <typename T>
  inline return_t dispatch (const T &obj) { return obj.apply (this); }
  static return_t default_return_value (void) { return false; }
  bool stop_sublookup_iteration (return_t r) const { return r; }
B
Behdad Esfahbod 已提交
452
  return_t recurse (unsigned int sub_lookup_index)
B
Behdad Esfahbod 已提交
453
  {
454
    if (unlikely (nesting_level_left == 0 || !recurse_func || buffer->max_ops-- <= 0))
B
Behdad Esfahbod 已提交
455 456 457
      return default_return_value ();

    nesting_level_left--;
B
Behdad Esfahbod 已提交
458
    bool ret = recurse_func (this, sub_lookup_index);
B
Behdad Esfahbod 已提交
459 460 461 462
    nesting_level_left++;
    return ret;
  }

463 464
  skipping_iterator_t iter_input, iter_context;

B
Behdad Esfahbod 已提交
465 466 467 468 469
  hb_font_t *font;
  hb_face_t *face;
  hb_buffer_t *buffer;
  recurse_func_t recurse_func;
  const GDEF &gdef;
470
  const VariationStore &var_store;
471 472 473 474

  hb_direction_t direction;
  hb_mask_t lookup_mask;
  unsigned int table_index; /* GSUB/GPOS */
475
  unsigned int lookup_index;
476 477
  unsigned int lookup_props;
  unsigned int nesting_level_left;
B
Behdad Esfahbod 已提交
478 479
  unsigned int debug_depth;

480
  bool has_glyph_classes;
481 482
  bool auto_zwnj;
  bool auto_zwj;
D
David Corbett 已提交
483
  bool random;
484

B
Behdad Esfahbod 已提交
485
  uint32_t random_state;
486

B
Behdad Esfahbod 已提交
487

488
  hb_ot_apply_context_t (unsigned int table_index_,
B
Behdad Esfahbod 已提交
489 490
		      hb_font_t *font_,
		      hb_buffer_t *buffer_) :
491
			iter_input (), iter_context (),
B
Behdad Esfahbod 已提交
492
			font (font_), face (font->face), buffer (buffer_),
B
Behdad Esfahbod 已提交
493
			recurse_func (nullptr),
B
Behdad Esfahbod 已提交
494
			gdef (*face->table.GDEF->table),
495
			var_store (gdef.get_var_store ()),
496 497 498
			direction (buffer_->props.direction),
			lookup_mask (1),
			table_index (table_index_),
499
			lookup_index ((unsigned int) -1),
500 501 502
			lookup_props (0),
			nesting_level_left (HB_MAX_NESTING_LEVEL),
			debug_depth (0),
503
			has_glyph_classes (gdef.has_glyph_classes ()),
504 505
			auto_zwnj (true),
			auto_zwj (true),
D
David Corbett 已提交
506
			random (false),
B
Behdad Esfahbod 已提交
507
			random_state (1) { init_iters (); }
B
Behdad Esfahbod 已提交
508

B
Behdad Esfahbod 已提交
509
  inline void init_iters (void)
510 511 512 513
  {
    iter_input.init (this, false);
    iter_context.init (this, true);
  }
B
Behdad Esfahbod 已提交
514

B
Behdad Esfahbod 已提交
515 516 517
  inline void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; init_iters (); }
  inline void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; init_iters (); }
  inline void set_auto_zwnj (bool auto_zwnj_) { auto_zwnj = auto_zwnj_; init_iters (); }
518 519 520
  inline void set_random (bool random_) { random = random_; }
  inline void set_recurse_func (recurse_func_t func) { recurse_func = func; }
  inline void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; }
B
Behdad Esfahbod 已提交
521
  inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; init_iters (); }
522

B
Behdad Esfahbod 已提交
523 524
  inline uint32_t random_number (void)
  {
B
Behdad Esfahbod 已提交
525 526 527
    /* http://www.cplusplus.com/reference/random/minstd_rand/ */
    random_state = random_state * 48271 % 2147483647;
    return random_state;
B
Behdad Esfahbod 已提交
528 529
  }

530 531 532
  inline bool
  match_properties_mark (hb_codepoint_t  glyph,
			 unsigned int    glyph_props,
B
Behdad Esfahbod 已提交
533
			 unsigned int    match_props) const
534 535
  {
    /* If using mark filtering sets, the high short of
B
Behdad Esfahbod 已提交
536
     * match_props has the set index.
537
     */
B
Behdad Esfahbod 已提交
538 539
    if (match_props & LookupFlag::UseMarkFilteringSet)
      return gdef.mark_set_covers (match_props >> 16, glyph);
540

B
Behdad Esfahbod 已提交
541
    /* The second byte of match_props has the meaning
542 543 544
     * "ignore marks of attachment type different than
     * the attachment type specified."
     */
B
Behdad Esfahbod 已提交
545 546
    if (match_props & LookupFlag::MarkAttachmentType)
      return (match_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);
547 548 549 550 551

    return true;
  }

  inline bool
B
Behdad Esfahbod 已提交
552
  check_glyph_property (const hb_glyph_info_t *info,
B
Behdad Esfahbod 已提交
553
			unsigned int  match_props) const
554
  {
B
Behdad Esfahbod 已提交
555 556 557
    hb_codepoint_t glyph = info->codepoint;
    unsigned int glyph_props = _hb_glyph_info_get_glyph_props (info);

558
    /* Not covered, if, for example, glyph class is ligature and
B
Behdad Esfahbod 已提交
559
     * match_props includes LookupFlags::IgnoreLigatures
560
     */
B
Behdad Esfahbod 已提交
561
    if (glyph_props & match_props & LookupFlag::IgnoreFlags)
562 563
      return false;

564
    if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK))
B
Behdad Esfahbod 已提交
565
      return match_properties_mark (glyph, glyph_props, match_props);
566 567 568 569

    return true;
  }

570
  inline void _set_glyph_props (hb_codepoint_t glyph_index,
571
			  unsigned int class_guess = 0,
572 573
			  bool ligature = false,
			  bool component = false) const
574
  {
575 576 577 578
    unsigned int add_in = _hb_glyph_info_get_glyph_props (&buffer->cur()) &
			  HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE;
    add_in |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED;
    if (ligature)
579
    {
580
      add_in |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED;
581 582
      /* In the only place that the MULTIPLIED bit is used, Uniscribe
       * seems to only care about the "last" transformation between
B
Bruce Mitchener 已提交
583
       * Ligature and Multiple substitutions.  Ie. if you ligate, expand,
584 585 586 587 588 589 590
       * and ligate again, it forgives the multiplication and acts as
       * if only ligation happened.  As such, clear MULTIPLIED bit.
       */
      add_in &= ~HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
    }
    if (component)
      add_in |= HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
591
    if (likely (has_glyph_classes))
592
      _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | gdef.get_glyph_props (glyph_index));
593
    else if (class_guess)
594
      _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | class_guess);
595
  }
B
Behdad Esfahbod 已提交
596

597
  inline void replace_glyph (hb_codepoint_t glyph_index) const
598
  {
599 600
    _set_glyph_props (glyph_index);
    buffer->replace_glyph (glyph_index);
601
  }
602
  inline void replace_glyph_inplace (hb_codepoint_t glyph_index) const
603
  {
604 605 606 607 608 609
    _set_glyph_props (glyph_index);
    buffer->cur().codepoint = glyph_index;
  }
  inline void replace_glyph_with_ligature (hb_codepoint_t glyph_index,
					   unsigned int class_guess) const
  {
610
    _set_glyph_props (glyph_index, class_guess, true);
611 612
    buffer->replace_glyph (glyph_index);
  }
613 614
  inline void output_glyph_for_component (hb_codepoint_t glyph_index,
					  unsigned int class_guess) const
B
Behdad Esfahbod 已提交
615
  {
616
    _set_glyph_props (glyph_index, class_guess, false, true);
617
    buffer->output_glyph (glyph_index);
B
Behdad Esfahbod 已提交
618
  }
619 620
};

621

B
Behdad Esfahbod 已提交
622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679
struct hb_get_subtables_context_t :
       hb_dispatch_context_t<hb_get_subtables_context_t, hb_void_t, HB_DEBUG_APPLY>
{
  template <typename Type>
  static inline bool apply_to (const void *obj, OT::hb_ot_apply_context_t *c)
  {
    const Type *typed_obj = (const Type *) obj;
    return typed_obj->apply (c);
  }

  typedef bool (*hb_apply_func_t) (const void *obj, OT::hb_ot_apply_context_t *c);

  struct hb_applicable_t
  {
    template <typename T>
    inline void init (const T &obj_, hb_apply_func_t apply_func_)
    {
      obj = &obj_;
      apply_func = apply_func_;
      digest.init ();
      obj_.get_coverage ().add_coverage (&digest);
    }

    inline bool apply (OT::hb_ot_apply_context_t *c) const
    {
      return digest.may_have (c->buffer->cur().codepoint) && apply_func (obj, c);
    }

    private:
    const void *obj;
    hb_apply_func_t apply_func;
    hb_set_digest_t digest;
  };

  typedef hb_vector_t<hb_applicable_t, 2> array_t;

  /* Dispatch interface. */
  inline const char *get_name (void) { return "GET_SUBTABLES"; }
  template <typename T>
  inline return_t dispatch (const T &obj)
  {
    hb_applicable_t *entry = array.push();
    entry->init (obj, apply_to<T>);
    return HB_VOID;
  }
  static return_t default_return_value (void) { return HB_VOID; }
  bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }

  hb_get_subtables_context_t (array_t &array_) :
			      array (array_),
			      debug_depth (0) {}

  array_t &array;
  unsigned int debug_depth;
};



B
Behdad Esfahbod 已提交
680

681
typedef bool (*intersects_func_t) (const hb_set_t *glyphs, const HBUINT16 &value, const void *data);
B
Behdad Esfahbod 已提交
682 683
typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const HBUINT16 &value, const void *data);
typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data);
684

685 686 687 688
struct ContextClosureFuncs
{
  intersects_func_t intersects;
};
689 690 691 692
struct ContextCollectGlyphsFuncs
{
  collect_glyphs_func_t collect;
};
693
struct ContextApplyFuncs
B
Behdad Esfahbod 已提交
694
{
695
  match_func_t match;
696 697
};

698

699
static inline bool intersects_glyph (const hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
700 701 702
{
  return glyphs->has (value);
}
703
static inline bool intersects_class (const hb_set_t *glyphs, const HBUINT16 &value, const void *data)
704 705 706 707
{
  const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
  return class_def.intersects_class (glyphs, value);
}
708
static inline bool intersects_coverage (const hb_set_t *glyphs, const HBUINT16 &value, const void *data)
709 710 711 712 713
{
  const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
  return (data+coverage).intersects (glyphs);
}

714
static inline bool intersects_array (const hb_set_t *glyphs,
715
				     unsigned int count,
B
Behdad Esfahbod 已提交
716
				     const HBUINT16 values[],
717 718 719 720
				     intersects_func_t intersects_func,
				     const void *intersects_data)
{
  for (unsigned int i = 0; i < count; i++)
721
    if (likely (!intersects_func (glyphs, values[i], intersects_data)))
722 723 724 725
      return false;
  return true;
}

726

B
Behdad Esfahbod 已提交
727
static inline void collect_glyph (hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
728 729 730
{
  glyphs->add (value);
}
B
Behdad Esfahbod 已提交
731
static inline void collect_class (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
732 733
{
  const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
734
  class_def.add_class (glyphs, value);
735
}
B
Behdad Esfahbod 已提交
736
static inline void collect_coverage (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
737 738 739 740
{
  const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
  (data+coverage).add_coverage (glyphs);
}
B
Behdad Esfahbod 已提交
741
static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
742
				  hb_set_t *glyphs,
743
				  unsigned int count,
B
Behdad Esfahbod 已提交
744
				  const HBUINT16 values[],
745 746 747 748
				  collect_glyphs_func_t collect_func,
				  const void *collect_data)
{
  for (unsigned int i = 0; i < count; i++)
749
    collect_func (glyphs, values[i], collect_data);
750 751 752
}


B
Behdad Esfahbod 已提交
753
static inline bool match_glyph (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data HB_UNUSED)
B
Behdad Esfahbod 已提交
754
{
755 756
  return glyph_id == value;
}
B
Behdad Esfahbod 已提交
757
static inline bool match_class (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data)
B
Behdad Esfahbod 已提交
758
{
B
Behdad Esfahbod 已提交
759
  const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
760 761
  return class_def.get_class (glyph_id) == value;
}
B
Behdad Esfahbod 已提交
762
static inline bool match_coverage (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data)
B
Behdad Esfahbod 已提交
763
{
764
  const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
765
  return (data+coverage).get_coverage (glyph_id) != NOT_COVERED;
766 767
}

768 769
static inline bool would_match_input (hb_would_apply_context_t *c,
				      unsigned int count, /* Including the first glyph (not matched) */
B
Behdad Esfahbod 已提交
770
				      const HBUINT16 input[], /* Array of input values--start with second glyph */
771 772 773 774 775 776 777
				      match_func_t match_func,
				      const void *match_data)
{
  if (count != c->len)
    return false;

  for (unsigned int i = 1; i < count; i++)
778
    if (likely (!match_func (c->glyphs[i], input[i - 1], match_data)))
779 780 781 782
      return false;

  return true;
}
783
static inline bool match_input (hb_ot_apply_context_t *c,
B
Behdad Esfahbod 已提交
784
				unsigned int count, /* Including the first glyph (not matched) */
B
Behdad Esfahbod 已提交
785
				const HBUINT16 input[], /* Array of input values--start with second glyph */
B
Behdad Esfahbod 已提交
786
				match_func_t match_func,
B
Behdad Esfahbod 已提交
787
				const void *match_data,
B
Behdad Esfahbod 已提交
788
				unsigned int *end_offset,
789
				unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],
B
Behdad Esfahbod 已提交
790
				unsigned int *p_total_component_count = nullptr)
B
Behdad Esfahbod 已提交
791
{
B
Behdad Esfahbod 已提交
792
  TRACE_APPLY (nullptr);
793

794
  if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return_trace (false);
795

B
Behdad Esfahbod 已提交
796 797
  hb_buffer_t *buffer = c->buffer;

798
  hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
799
  skippy_iter.reset (buffer->idx, count - 1);
800
  skippy_iter.set_match_func (match_func, match_data, input);
801

802 803 804 805 806 807 808 809 810 811 812
  /*
   * This is perhaps the trickiest part of OpenType...  Remarks:
   *
   * - If all components of the ligature were marks, we call this a mark ligature.
   *
   * - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize
   *   it as a ligature glyph.
   *
   * - Ligatures cannot be formed across glyphs attached to different components
   *   of previous ligatures.  Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and
   *   LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother.
813 814 815 816 817 818 819 820 821 822
   *   However, it would be wrong to ligate that SHADDA,FATHA sequence.
   *   There are a couple of exceptions to this:
   *
   *   o If a ligature tries ligating with marks that belong to it itself, go ahead,
   *     assuming that the font designer knows what they are doing (otherwise it can
   *     break Indic stuff when a matra wants to ligate with a conjunct,
   *
   *   o If two marks want to ligate and they belong to different components of the
   *     same ligature glyph, and said ligature glyph is to be ignored according to
   *     mark-filtering rules, then allow.
823
   *     https://github.com/harfbuzz/harfbuzz/issues/545
824 825
   */

826
  unsigned int total_component_count = 0;
B
Behdad Esfahbod 已提交
827
  total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur());
828

B
Behdad Esfahbod 已提交
829 830
  unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
  unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
B
Behdad Esfahbod 已提交
831

832 833 834 835 836 837
  enum {
    LIGBASE_NOT_CHECKED,
    LIGBASE_MAY_NOT_SKIP,
    LIGBASE_MAY_SKIP
  } ligbase = LIGBASE_NOT_CHECKED;

B
Behdad Esfahbod 已提交
838
  match_positions[0] = buffer->idx;
B
Minor  
Behdad Esfahbod 已提交
839
  for (unsigned int i = 1; i < count; i++)
B
Behdad Esfahbod 已提交
840
  {
B
Behdad Esfahbod 已提交
841
    if (!skippy_iter.next ()) return_trace (false);
B
Behdad Esfahbod 已提交
842 843

    match_positions[i] = skippy_iter.idx;
844

B
Behdad Esfahbod 已提交
845 846
    unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]);
    unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]);
847

848 849
    if (first_lig_id && first_lig_comp)
    {
850 851
      /* If first component was attached to a previous ligature component,
       * all subsequent components should be attached to the same ligature
852
       * component, otherwise we shouldn't ligate them... */
853
      if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
854
      {
E
Ebrahim Byagowi 已提交
855
	/* ...unless, we are attached to a base ligature and that base
856
	 * ligature is ignorable. */
E
Ebrahim Byagowi 已提交
857
	if (ligbase == LIGBASE_NOT_CHECKED)
858
	{
859 860 861 862
	  bool found = false;
	  const hb_glyph_info_t *out = buffer->out_info;
	  unsigned int j = buffer->out_len;
	  while (j && _hb_glyph_info_get_lig_id (&out[j - 1]) == first_lig_id)
863
	  {
864 865 866 867 868 869
	    if (_hb_glyph_info_get_lig_comp (&out[j - 1]) == 0)
	    {
	      j--;
	      found = true;
	      break;
	    }
870 871 872
	    j--;
	  }

B
Behdad Esfahbod 已提交
873
	  if (found && skippy_iter.may_skip (out[j]) == hb_ot_apply_context_t::matcher_t::SKIP_YES)
874 875 876 877
	    ligbase = LIGBASE_MAY_SKIP;
	  else
	    ligbase = LIGBASE_MAY_NOT_SKIP;
	}
878

E
Ebrahim Byagowi 已提交
879
	if (ligbase == LIGBASE_MAY_NOT_SKIP)
880 881 882 883
	  return_trace (false);
      }
    }
    else
884
    {
885 886 887 888
      /* If first component was NOT attached to a previous ligature component,
       * all subsequent components should also NOT be attached to any ligature
       * component, unless they are attached to the first component itself! */
      if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id))
B
Behdad Esfahbod 已提交
889
	return_trace (false);
890 891
    }

B
Behdad Esfahbod 已提交
892
    total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]);
B
Behdad Esfahbod 已提交
893 894
  }

B
Behdad Esfahbod 已提交
895
  *end_offset = skippy_iter.idx - buffer->idx + 1;
B
Behdad Esfahbod 已提交
896

897 898 899
  if (p_total_component_count)
    *p_total_component_count = total_component_count;

B
Behdad Esfahbod 已提交
900
  return_trace (true);
B
Behdad Esfahbod 已提交
901
}
902
static inline bool ligate_input (hb_ot_apply_context_t *c,
903
				 unsigned int count, /* Including the first glyph */
B
Bruce Mitchener 已提交
904
				 const unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
905
				 unsigned int match_length,
906 907 908
				 hb_codepoint_t lig_glyph,
				 unsigned int total_component_count)
{
B
Behdad Esfahbod 已提交
909
  TRACE_APPLY (nullptr);
910

B
Behdad Esfahbod 已提交
911 912 913
  hb_buffer_t *buffer = c->buffer;

  buffer->merge_clusters (buffer->idx, buffer->idx + match_length);
914

915 916 917 918 919
  /* - If a base and one or more marks ligate, consider that as a base, NOT
   *   ligature, such that all following marks can still attach to it.
   *   https://github.com/harfbuzz/harfbuzz/issues/1109
   *
   * - If all components of the ligature were marks, we call this a mark ligature.
B
Behdad Esfahbod 已提交
920
   *   If it *is* a mark ligature, we don't allocate a new ligature id, and leave
921 922
   *   the ligature to keep its old ligature id.  This will allow it to attach to
   *   a base ligature in GPOS.  Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH,
B
Behdad Esfahbod 已提交
923
   *   and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA with a
924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946
   *   ligature id and component value of 2.  Then if SHADDA,FATHA form a ligature
   *   later, we don't want them to lose their ligature id/component, otherwise
   *   GPOS will fail to correctly position the mark ligature on top of the
   *   LAM,LAM,HEH ligature.  See:
   *     https://bugzilla.gnome.org/show_bug.cgi?id=676343
   *
   * - If a ligature is formed of components that some of which are also ligatures
   *   themselves, and those ligature components had marks attached to *their*
   *   components, we have to attach the marks to the new ligature component
   *   positions!  Now *that*'s tricky!  And these marks may be following the
   *   last component of the whole sequence, so we should loop forward looking
   *   for them and update them.
   *
   *   Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a
   *   'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature
   *   id and component == 1.  Now, during 'liga', the LAM and the LAM-HEH ligature
   *   form a LAM-LAM-HEH ligature.  We need to reassign the SHADDA and FATHA to
   *   the new ligature with a component value of 2.
   *
   *   This in fact happened to a font...  See:
   *   https://bugzilla.gnome.org/show_bug.cgi?id=437633
   */

947 948 949
  bool is_base_ligature = _hb_glyph_info_is_base_glyph (&buffer->info[match_positions[0]]);
  bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->info[match_positions[0]]);
  for (unsigned int i = 1; i < count; i++)
B
Behdad Esfahbod 已提交
950 951
    if (!_hb_glyph_info_is_mark (&buffer->info[match_positions[i]]))
    {
952
      is_base_ligature = false;
B
Behdad Esfahbod 已提交
953 954 955
      is_mark_ligature = false;
      break;
    }
956
  bool is_ligature = !is_base_ligature && !is_mark_ligature;
B
Behdad Esfahbod 已提交
957

958 959
  unsigned int klass = is_ligature ? HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE : 0;
  unsigned int lig_id = is_ligature ? _hb_allocate_lig_id (buffer) : 0;
B
Behdad Esfahbod 已提交
960 961
  unsigned int last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
  unsigned int last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
962 963
  unsigned int components_so_far = last_num_components;

964
  if (is_ligature)
965
  {
B
Behdad Esfahbod 已提交
966
    _hb_glyph_info_set_lig_props_for_ligature (&buffer->cur(), lig_id, total_component_count);
B
Behdad Esfahbod 已提交
967
    if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
968
    {
B
Minor  
Behdad Esfahbod 已提交
969
      _hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER);
970
    }
971
  }
972
  c->replace_glyph_with_ligature (lig_glyph, klass);
973 974 975

  for (unsigned int i = 1; i < count; i++)
  {
B
Behdad Esfahbod 已提交
976
    while (buffer->idx < match_positions[i] && buffer->successful)
977
    {
978 979
      if (is_ligature)
      {
E
Ebrahim Byagowi 已提交
980
	unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
981
	if (this_comp == 0)
982
	  this_comp = last_num_components;
983
	unsigned int new_lig_comp = components_so_far - last_num_components +
984 985
				    MIN (this_comp, last_num_components);
	  _hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
986
      }
B
Behdad Esfahbod 已提交
987
      buffer->next_glyph ();
988 989
    }

B
Behdad Esfahbod 已提交
990 991
    last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
    last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
992 993 994
    components_so_far += last_num_components;

    /* Skip the base glyph */
B
Behdad Esfahbod 已提交
995
    buffer->idx++;
996 997 998 999
  }

  if (!is_mark_ligature && last_lig_id) {
    /* Re-adjust components for any marks following. */
B
Behdad Esfahbod 已提交
1000
    for (unsigned int i = buffer->idx; i < buffer->len; i++) {
B
Behdad Esfahbod 已提交
1001
      if (last_lig_id == _hb_glyph_info_get_lig_id (&buffer->info[i])) {
E
Ebrahim Byagowi 已提交
1002
	unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->info[i]);
1003 1004
	if (!this_comp)
	  break;
1005
	unsigned int new_lig_comp = components_so_far - last_num_components +
1006
				    MIN (this_comp, last_num_components);
B
Behdad Esfahbod 已提交
1007
	_hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
1008 1009 1010 1011
      } else
	break;
    }
  }
B
Behdad Esfahbod 已提交
1012
  return_trace (true);
1013
}
B
Behdad Esfahbod 已提交
1014

1015
static inline bool match_backtrack (hb_ot_apply_context_t *c,
1016
				    unsigned int count,
B
Behdad Esfahbod 已提交
1017
				    const HBUINT16 backtrack[],
1018
				    match_func_t match_func,
1019 1020
				    const void *match_data,
				    unsigned int *match_start)
1021
{
B
Behdad Esfahbod 已提交
1022
  TRACE_APPLY (nullptr);
1023

1024
  hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
1025
  skippy_iter.reset (c->buffer->backtrack_len (), count);
1026
  skippy_iter.set_match_func (match_func, match_data, backtrack);
1027

1028
  for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
1029
    if (!skippy_iter.prev ())
B
Behdad Esfahbod 已提交
1030
      return_trace (false);
1031

1032 1033
  *match_start = skippy_iter.idx;

B
Behdad Esfahbod 已提交
1034
  return_trace (true);
1035 1036
}

1037
static inline bool match_lookahead (hb_ot_apply_context_t *c,
B
Behdad Esfahbod 已提交
1038
				    unsigned int count,
B
Behdad Esfahbod 已提交
1039
				    const HBUINT16 lookahead[],
B
Behdad Esfahbod 已提交
1040
				    match_func_t match_func,
B
Behdad Esfahbod 已提交
1041
				    const void *match_data,
1042 1043
				    unsigned int offset,
				    unsigned int *end_index)
1044
{
B
Behdad Esfahbod 已提交
1045
  TRACE_APPLY (nullptr);
1046

1047
  hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
1048
  skippy_iter.reset (c->buffer->idx + offset - 1, count);
1049
  skippy_iter.set_match_func (match_func, match_data, lookahead);
1050

B
Minor  
Behdad Esfahbod 已提交
1051
  for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
1052
    if (!skippy_iter.next ())
B
Behdad Esfahbod 已提交
1053
      return_trace (false);
1054

1055 1056
  *end_index = skippy_iter.idx + 1;

B
Behdad Esfahbod 已提交
1057
  return_trace (true);
1058 1059
}

B
Behdad Esfahbod 已提交
1060

1061

B
Behdad Esfahbod 已提交
1062 1063
struct LookupRecord
{
B
Behdad Esfahbod 已提交
1064 1065
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1066
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1067
    return_trace (c->check_struct (this));
B
Behdad Esfahbod 已提交
1068 1069
  }

B
Behdad Esfahbod 已提交
1070
  HBUINT16	sequenceIndex;		/* Index into current glyph
1071
					 * sequence--first glyph = 0 */
B
Behdad Esfahbod 已提交
1072
  HBUINT16	lookupListIndex;	/* Lookup to apply to that
1073
					 * position--zero--based */
B
Behdad Esfahbod 已提交
1074 1075
  public:
  DEFINE_SIZE_STATIC (4);
1076 1077
};

1078 1079 1080 1081
template <typename context_t>
static inline void recurse_lookups (context_t *c,
				    unsigned int lookupCount,
				    const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
1082 1083
{
  for (unsigned int i = 0; i < lookupCount; i++)
B
Behdad Esfahbod 已提交
1084
    c->recurse (lookupRecord[i].lookupListIndex);
1085
}
B
Behdad Esfahbod 已提交
1086

1087
static inline bool apply_lookup (hb_ot_apply_context_t *c,
1088
				 unsigned int count, /* Including the first glyph */
1089
				 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
1090
				 unsigned int lookupCount,
1091 1092
				 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
				 unsigned int match_length)
1093
{
B
Behdad Esfahbod 已提交
1094
  TRACE_APPLY (nullptr);
1095

1096
  hb_buffer_t *buffer = c->buffer;
1097
  int end;
B
Behdad Esfahbod 已提交
1098

1099 1100 1101 1102 1103
  /* All positions are distance from beginning of *output* buffer.
   * Adjust. */
  {
    unsigned int bl = buffer->backtrack_len ();
    end = bl + match_length;
1104

1105 1106 1107 1108 1109
    int delta = bl - buffer->idx;
    /* Convert positions to new indexing. */
    for (unsigned int j = 0; j < count; j++)
      match_positions[j] += delta;
  }
1110

B
Behdad Esfahbod 已提交
1111
  for (unsigned int i = 0; i < lookupCount && buffer->successful; i++)
B
Behdad Esfahbod 已提交
1112
  {
1113 1114 1115
    unsigned int idx = lookupRecord[i].sequenceIndex;
    if (idx >= count)
      continue;
1116

1117 1118 1119 1120 1121
    /* Don't recurse to ourself at same position.
     * Note that this test is too naive, it doesn't catch longer loops. */
    if (idx == 0 && lookupRecord[i].lookupListIndex == c->lookup_index)
      continue;

1122 1123
    if (unlikely (!buffer->move_to (match_positions[idx])))
      break;
1124

1125 1126 1127
    if (unlikely (buffer->max_ops <= 0))
      break;

1128 1129 1130
    unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
    if (!c->recurse (lookupRecord[i].lookupListIndex))
      continue;
1131

1132 1133
    unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len ();
    int delta = new_len - orig_len;
1134

1135
    if (!delta)
E
Ebrahim Byagowi 已提交
1136
      continue;
1137

B
Behdad Esfahbod 已提交
1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160
    /* Recursed lookup changed buffer len.  Adjust.
     *
     * TODO:
     *
     * Right now, if buffer length increased by n, we assume n new glyphs
     * were added right after the current position, and if buffer length
     * was decreased by n, we assume n match positions after the current
     * one where removed.  The former (buffer length increased) case is
     * fine, but the decrease case can be improved in at least two ways,
     * both of which are significant:
     *
     *   - If recursed-to lookup is MultipleSubst and buffer length
     *     decreased, then it's current match position that was deleted,
     *     NOT the one after it.
     *
     *   - If buffer length was decreased by n, it does not necessarily
     *     mean that n match positions where removed, as there might
     *     have been marks and default-ignorables in the sequence.  We
     *     should instead drop match positions between current-position
     *     and current-position + n instead.
     *
     * It should be possible to construct tests for both of these cases.
     */
1161

1162
    end += delta;
1163
    if (end <= int (match_positions[idx]))
1164
    {
1165
      /* End might end up being smaller than match_positions[idx] if the recursed
1166
       * lookup ended up removing many items, more than we have had matched.
1167 1168 1169
       * Just never rewind end back and get out of here.
       * https://bugs.chromium.org/p/chromium/issues/detail?id=659496 */
      end = match_positions[idx];
1170
      /* There can't be any further changes. */
1171 1172
      break;
    }
1173

1174 1175 1176 1177
    unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */

    if (delta > 0)
    {
1178
      if (unlikely (delta + count > HB_MAX_CONTEXT_LENGTH))
1179
	break;
1180 1181 1182
    }
    else
    {
1183
      /* NOTE: delta is negative. */
1184 1185
      delta = MAX (delta, (int) next - (int) count);
      next -= delta;
1186
    }
1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200

    /* Shift! */
    memmove (match_positions + next + delta, match_positions + next,
	     (count - next) * sizeof (match_positions[0]));
    next += delta;
    count += delta;

    /* Fill in new entries. */
    for (unsigned int j = idx + 1; j < next; j++)
      match_positions[j] = match_positions[j - 1] + 1;

    /* And fixup the rest. */
    for (; next < count; next++)
      match_positions[next] += delta;
1201 1202
  }

1203 1204
  buffer->move_to (end);

B
Behdad Esfahbod 已提交
1205
  return_trace (true);
1206
}
1207

B
Behdad Esfahbod 已提交
1208

1209 1210 1211

/* Contextual lookups */

1212 1213 1214 1215 1216 1217
struct ContextClosureLookupContext
{
  ContextClosureFuncs funcs;
  const void *intersects_data;
};

1218 1219 1220 1221 1222 1223
struct ContextCollectGlyphsLookupContext
{
  ContextCollectGlyphsFuncs funcs;
  const void *collect_data;
};

1224
struct ContextApplyLookupContext
B
Behdad Esfahbod 已提交
1225
{
1226
  ContextApplyFuncs funcs;
B
Behdad Esfahbod 已提交
1227
  const void *match_data;
1228 1229
};

1230 1231 1232 1233 1234 1235 1236 1237 1238 1239
static inline bool context_intersects (const hb_set_t *glyphs,
				       unsigned int inputCount, /* Including the first glyph (not matched) */
				       const HBUINT16 input[], /* Array of input values--start with second glyph */
				       ContextClosureLookupContext &lookup_context)
{
  return intersects_array (glyphs,
			   inputCount ? inputCount - 1 : 0, input,
			   lookup_context.funcs.intersects, lookup_context.intersects_data);
}

B
Behdad Esfahbod 已提交
1240
static inline void context_closure_lookup (hb_closure_context_t *c,
1241
					   unsigned int inputCount, /* Including the first glyph (not matched) */
B
Behdad Esfahbod 已提交
1242
					   const HBUINT16 input[], /* Array of input values--start with second glyph */
1243 1244 1245 1246
					   unsigned int lookupCount,
					   const LookupRecord lookupRecord[],
					   ContextClosureLookupContext &lookup_context)
{
1247 1248 1249
  if (context_intersects (c->glyphs,
			  inputCount, input,
			  lookup_context))
1250 1251
    recurse_lookups (c,
		     lookupCount, lookupRecord);
1252 1253
}

1254 1255
static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
						  unsigned int inputCount, /* Including the first glyph (not matched) */
B
Behdad Esfahbod 已提交
1256
						  const HBUINT16 input[], /* Array of input values--start with second glyph */
1257 1258 1259 1260
						  unsigned int lookupCount,
						  const LookupRecord lookupRecord[],
						  ContextCollectGlyphsLookupContext &lookup_context)
{
B
Minor  
Behdad Esfahbod 已提交
1261
  collect_array (c, c->input,
1262 1263 1264 1265 1266
		 inputCount ? inputCount - 1 : 0, input,
		 lookup_context.funcs.collect, lookup_context.collect_data);
  recurse_lookups (c,
		   lookupCount, lookupRecord);
}
1267

1268 1269
static inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
					       unsigned int inputCount, /* Including the first glyph (not matched) */
B
Behdad Esfahbod 已提交
1270
					       const HBUINT16 input[], /* Array of input values--start with second glyph */
B
Behdad Esfahbod 已提交
1271 1272
					       unsigned int lookupCount HB_UNUSED,
					       const LookupRecord lookupRecord[] HB_UNUSED,
1273 1274 1275 1276 1277 1278
					       ContextApplyLookupContext &lookup_context)
{
  return would_match_input (c,
			    inputCount, input,
			    lookup_context.funcs.match, lookup_context.match_data);
}
1279
static inline bool context_apply_lookup (hb_ot_apply_context_t *c,
1280
					 unsigned int inputCount, /* Including the first glyph (not matched) */
B
Behdad Esfahbod 已提交
1281
					 const HBUINT16 input[], /* Array of input values--start with second glyph */
1282 1283 1284
					 unsigned int lookupCount,
					 const LookupRecord lookupRecord[],
					 ContextApplyLookupContext &lookup_context)
1285
{
1286
  unsigned int match_length = 0;
1287
  unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
B
Behdad Esfahbod 已提交
1288
  return match_input (c,
B
Behdad Esfahbod 已提交
1289
		      inputCount, input,
1290 1291
		      lookup_context.funcs.match, lookup_context.match_data,
		      &match_length, match_positions)
1292 1293
      && (c->buffer->unsafe_to_break (c->buffer->idx, c->buffer->idx + match_length),
	  apply_lookup (c,
1294 1295
		       inputCount, match_positions,
		       lookupCount, lookupRecord,
1296
		       match_length));
1297 1298
}

B
Behdad Esfahbod 已提交
1299 1300
struct Rule
{
1301 1302 1303
  inline bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const
  {
    return context_intersects (glyphs,
1304
			       inputCount, inputZ.arrayZ,
1305 1306 1307
			       lookup_context);
  }

B
Behdad Esfahbod 已提交
1308
  inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
1309
  {
B
Behdad Esfahbod 已提交
1310
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
1311 1312
    const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord> >
						       (inputZ.as_array ((inputCount ? inputCount - 1 : 0)));
B
Behdad Esfahbod 已提交
1313
    context_closure_lookup (c,
1314 1315
			    inputCount, inputZ.arrayZ,
			    lookupCount, lookupRecord.arrayZ,
B
Behdad Esfahbod 已提交
1316
			    lookup_context);
1317 1318
  }

1319 1320 1321
  inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Behdad Esfahbod 已提交
1322 1323
    const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord> >
						       (inputZ.as_array (inputCount ? inputCount - 1 : 0));
1324
    context_collect_glyphs_lookup (c,
1325 1326
				   inputCount, inputZ.arrayZ,
				   lookupCount, lookupRecord.arrayZ,
1327 1328 1329
				   lookup_context);
  }

1330 1331
  inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
  {
B
Behdad Esfahbod 已提交
1332
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
1333 1334
    const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord> >
						       (inputZ.as_array (inputCount ? inputCount - 1 : 0));
1335
    return_trace (context_would_apply_lookup (c, inputCount, inputZ.arrayZ, lookupCount, lookupRecord.arrayZ, lookup_context));
1336 1337
  }

1338
  inline bool apply (hb_ot_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
B
Behdad Esfahbod 已提交
1339
  {
B
Behdad Esfahbod 已提交
1340
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
1341 1342
    const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord> >
						       (inputZ.as_array (inputCount ? inputCount - 1 : 0));
1343
    return_trace (context_apply_lookup (c, inputCount, inputZ.arrayZ, lookupCount, lookupRecord.arrayZ, lookup_context));
1344 1345
  }

B
Behdad Esfahbod 已提交
1346
  public:
B
Behdad Esfahbod 已提交
1347 1348
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1349
    TRACE_SANITIZE (this);
1350 1351
    return_trace (inputCount.sanitize (c) &&
		  lookupCount.sanitize (c) &&
1352
		  c->check_range (inputZ.arrayZ,
B
Behdad Esfahbod 已提交
1353
				  inputZ[0].static_size * (inputCount ? inputCount - 1 : 0) +
1354
				  LookupRecord::static_size * lookupCount));
B
Behdad Esfahbod 已提交
1355 1356
  }

1357
  protected:
B
Behdad Esfahbod 已提交
1358
  HBUINT16	inputCount;		/* Total number of glyphs in input
1359
					 * glyph sequence--includes the first
1360
					 * glyph */
B
Behdad Esfahbod 已提交
1361
  HBUINT16	lookupCount;		/* Number of LookupRecords */
1362 1363
  UnsizedArrayOf<HBUINT16>
 		inputZ;			/* Array of match inputs--start with
1364
					 * second glyph */
1365 1366
/*UnsizedArrayOf<LookupRecord>
		lookupRecordX;*/	/* Array of LookupRecords--in
1367
					 * design order */
B
Behdad Esfahbod 已提交
1368
  public:
1369
  DEFINE_SIZE_ARRAY (4, inputZ);
1370 1371
};

B
Behdad Esfahbod 已提交
1372 1373
struct RuleSet
{
1374 1375 1376 1377 1378
  inline bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const
  {
    unsigned int num_rules = rule.len;
    for (unsigned int i = 0; i < num_rules; i++)
      if ((this+rule[i]).intersects (glyphs, lookup_context))
E
Ebrahim Byagowi 已提交
1379
	return true;
1380 1381 1382
    return false;
  }

B
Behdad Esfahbod 已提交
1383
  inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
1384
  {
B
Behdad Esfahbod 已提交
1385
    TRACE_CLOSURE (this);
1386 1387
    unsigned int num_rules = rule.len;
    for (unsigned int i = 0; i < num_rules; i++)
B
Behdad Esfahbod 已提交
1388
      (this+rule[i]).closure (c, lookup_context);
1389 1390
  }

1391 1392 1393 1394 1395 1396 1397 1398
  inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const
  {
    TRACE_COLLECT_GLYPHS (this);
    unsigned int num_rules = rule.len;
    for (unsigned int i = 0; i < num_rules; i++)
      (this+rule[i]).collect_glyphs (c, lookup_context);
  }

1399 1400
  inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
  {
B
Behdad Esfahbod 已提交
1401
    TRACE_WOULD_APPLY (this);
1402 1403 1404 1405
    unsigned int num_rules = rule.len;
    for (unsigned int i = 0; i < num_rules; i++)
    {
      if ((this+rule[i]).would_apply (c, lookup_context))
E
Ebrahim Byagowi 已提交
1406
	return_trace (true);
1407
    }
B
Behdad Esfahbod 已提交
1408
    return_trace (false);
1409 1410
  }

1411
  inline bool apply (hb_ot_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
B
Behdad Esfahbod 已提交
1412
  {
B
Behdad Esfahbod 已提交
1413
    TRACE_APPLY (this);
1414
    unsigned int num_rules = rule.len;
B
Behdad Esfahbod 已提交
1415 1416
    for (unsigned int i = 0; i < num_rules; i++)
    {
B
Behdad Esfahbod 已提交
1417
      if ((this+rule[i]).apply (c, lookup_context))
E
Ebrahim Byagowi 已提交
1418
	return_trace (true);
1419
    }
B
Behdad Esfahbod 已提交
1420
    return_trace (false);
1421 1422
  }

B
Behdad Esfahbod 已提交
1423 1424
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1425
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1426
    return_trace (rule.sanitize (c, this));
B
Behdad Esfahbod 已提交
1427 1428
  }

1429
  protected:
1430
  OffsetArrayOf<Rule>
1431
		rule;			/* Array of Rule tables
1432
					 * ordered by preference */
B
Behdad Esfahbod 已提交
1433
  public:
1434
  DEFINE_SIZE_ARRAY (2, rule);
1435 1436 1437
};


B
Behdad Esfahbod 已提交
1438 1439
struct ContextFormat1
{
1440 1441 1442 1443 1444 1445 1446 1447
  inline bool intersects (const hb_set_t *glyphs) const
  {
    struct ContextClosureLookupContext lookup_context = {
      {intersects_glyph},
      nullptr
    };

    unsigned int count = ruleSet.len;
1448
    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
1449 1450
    {
      if (unlikely (iter.get_coverage () >= count))
E
Ebrahim Byagowi 已提交
1451
	break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
1452 1453
      if (glyphs->has (iter.get_glyph ()) &&
	  (this+ruleSet[iter.get_coverage ()]).intersects (glyphs, lookup_context))
E
Ebrahim Byagowi 已提交
1454
	return true;
1455 1456 1457 1458
    }
    return false;
  }

1459
  inline void closure (hb_closure_context_t *c) const
1460
  {
B
Behdad Esfahbod 已提交
1461
    TRACE_CLOSURE (this);
1462 1463

    struct ContextClosureLookupContext lookup_context = {
1464
      {intersects_glyph},
B
Behdad Esfahbod 已提交
1465
      nullptr
1466 1467 1468
    };

    unsigned int count = ruleSet.len;
1469
    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
1470 1471
    {
      if (unlikely (iter.get_coverage () >= count))
E
Ebrahim Byagowi 已提交
1472
	break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
1473 1474 1475
      if (c->glyphs->has (iter.get_glyph ()))
	(this+ruleSet[iter.get_coverage ()]).closure (c, lookup_context);
    }
1476 1477
  }

B
Behdad Esfahbod 已提交
1478 1479
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
1480
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
1481
    (this+coverage).add_coverage (c->input);
1482 1483 1484

    struct ContextCollectGlyphsLookupContext lookup_context = {
      {collect_glyph},
B
Behdad Esfahbod 已提交
1485
      nullptr
1486 1487 1488 1489
    };

    unsigned int count = ruleSet.len;
    for (unsigned int i = 0; i < count; i++)
1490
      (this+ruleSet[i]).collect_glyphs (c, lookup_context);
B
Behdad Esfahbod 已提交
1491 1492
  }

1493 1494
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1495
    TRACE_WOULD_APPLY (this);
1496

1497
    const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
1498
    struct ContextApplyLookupContext lookup_context = {
1499
      {match_glyph},
B
Behdad Esfahbod 已提交
1500
      nullptr
1501
    };
B
Behdad Esfahbod 已提交
1502
    return_trace (rule_set.would_apply (c, lookup_context));
1503 1504
  }

1505
  inline const Coverage &get_coverage (void) const
1506
  { return this+coverage; }
1507

1508
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1509
  {
B
Behdad Esfahbod 已提交
1510
    TRACE_APPLY (this);
1511
    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
1512
    if (likely (index == NOT_COVERED))
B
Behdad Esfahbod 已提交
1513
      return_trace (false);
1514

1515
    const RuleSet &rule_set = this+ruleSet[index];
1516
    struct ContextApplyLookupContext lookup_context = {
1517
      {match_glyph},
B
Behdad Esfahbod 已提交
1518
      nullptr
1519
    };
B
Behdad Esfahbod 已提交
1520
    return_trace (rule_set.apply (c, lookup_context));
1521 1522
  }

1523 1524 1525 1526 1527 1528 1529
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

B
Behdad Esfahbod 已提交
1530 1531
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1532
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1533
    return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
1534 1535
  }

1536
  protected:
B
Behdad Esfahbod 已提交
1537
  HBUINT16	format;			/* Format identifier--format = 1 */
1538 1539 1540 1541 1542 1543
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of table */
  OffsetArrayOf<RuleSet>
		ruleSet;		/* Array of RuleSet tables
					 * ordered by Coverage Index */
1544
  public:
1545
  DEFINE_SIZE_ARRAY (6, ruleSet);
1546 1547 1548
};


B
Behdad Esfahbod 已提交
1549 1550
struct ContextFormat2
{
1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566
  inline bool intersects (const hb_set_t *glyphs) const
  {
    if (!(this+coverage).intersects (glyphs))
      return false;

    const ClassDef &class_def = this+classDef;

    struct ContextClosureLookupContext lookup_context = {
      {intersects_class},
      &class_def
    };

    unsigned int count = ruleSet.len;
    for (unsigned int i = 0; i < count; i++)
      if (class_def.intersects_class (glyphs, i) &&
	  (this+ruleSet[i]).intersects (glyphs, lookup_context))
E
Ebrahim Byagowi 已提交
1567
	return true;
1568 1569 1570 1571

    return false;
  }

1572
  inline void closure (hb_closure_context_t *c) const
1573
  {
B
Behdad Esfahbod 已提交
1574
    TRACE_CLOSURE (this);
1575
    if (!(this+coverage).intersects (c->glyphs))
B
Behdad Esfahbod 已提交
1576
      return;
1577 1578 1579 1580

    const ClassDef &class_def = this+classDef;

    struct ContextClosureLookupContext lookup_context = {
1581
      {intersects_class},
1582
      &class_def
1583 1584 1585 1586 1587 1588
    };

    unsigned int count = ruleSet.len;
    for (unsigned int i = 0; i < count; i++)
      if (class_def.intersects_class (c->glyphs, i)) {
	const RuleSet &rule_set = this+ruleSet[i];
B
Behdad Esfahbod 已提交
1589
	rule_set.closure (c, lookup_context);
1590
      }
1591 1592
  }

B
Behdad Esfahbod 已提交
1593 1594
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
1595
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
1596
    (this+coverage).add_coverage (c->input);
1597

1598
    const ClassDef &class_def = this+classDef;
1599 1600
    struct ContextCollectGlyphsLookupContext lookup_context = {
      {collect_class},
1601
      &class_def
1602 1603 1604 1605
    };

    unsigned int count = ruleSet.len;
    for (unsigned int i = 0; i < count; i++)
1606
      (this+ruleSet[i]).collect_glyphs (c, lookup_context);
B
Behdad Esfahbod 已提交
1607 1608
  }

1609 1610
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1611
    TRACE_WOULD_APPLY (this);
1612 1613

    const ClassDef &class_def = this+classDef;
1614
    unsigned int index = class_def.get_class (c->glyphs[0]);
1615 1616
    const RuleSet &rule_set = this+ruleSet[index];
    struct ContextApplyLookupContext lookup_context = {
1617
      {match_class},
1618 1619
      &class_def
    };
B
Behdad Esfahbod 已提交
1620
    return_trace (rule_set.would_apply (c, lookup_context));
1621 1622
  }

1623
  inline const Coverage &get_coverage (void) const
1624
  { return this+coverage; }
1625

1626
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1627
  {
B
Behdad Esfahbod 已提交
1628
    TRACE_APPLY (this);
1629
    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
B
Behdad Esfahbod 已提交
1630
    if (likely (index == NOT_COVERED)) return_trace (false);
1631 1632

    const ClassDef &class_def = this+classDef;
1633
    index = class_def.get_class (c->buffer->cur().codepoint);
1634
    const RuleSet &rule_set = this+ruleSet[index];
1635
    struct ContextApplyLookupContext lookup_context = {
1636
      {match_class},
B
Behdad Esfahbod 已提交
1637
      &class_def
1638
    };
B
Behdad Esfahbod 已提交
1639
    return_trace (rule_set.apply (c, lookup_context));
1640 1641
  }

1642 1643 1644 1645 1646 1647 1648
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

B
Behdad Esfahbod 已提交
1649 1650
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1651
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1652
    return_trace (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
1653 1654
  }

1655
  protected:
B
Behdad Esfahbod 已提交
1656
  HBUINT16	format;			/* Format identifier--format = 2 */
1657 1658 1659 1660 1661 1662 1663 1664 1665
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of table */
  OffsetTo<ClassDef>
		classDef;		/* Offset to glyph ClassDef table--from
					 * beginning of table */
  OffsetArrayOf<RuleSet>
		ruleSet;		/* Array of RuleSet tables
					 * ordered by class */
1666
  public:
1667
  DEFINE_SIZE_ARRAY (8, ruleSet);
1668 1669 1670
};


B
Behdad Esfahbod 已提交
1671 1672
struct ContextFormat3
{
1673 1674 1675 1676 1677 1678 1679 1680 1681 1682
  inline bool intersects (const hb_set_t *glyphs) const
  {
    if (!(this+coverageZ[0]).intersects (glyphs))
      return false;

    struct ContextClosureLookupContext lookup_context = {
      {intersects_coverage},
      this
    };
    return context_intersects (glyphs,
1683
			       glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
1684 1685 1686
			       lookup_context);
  }

1687
  inline void closure (hb_closure_context_t *c) const
1688
  {
B
Behdad Esfahbod 已提交
1689
    TRACE_CLOSURE (this);
1690
    if (!(this+coverageZ[0]).intersects (c->glyphs))
B
Behdad Esfahbod 已提交
1691
      return;
1692

B
Behdad Esfahbod 已提交
1693
    const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
1694
    struct ContextClosureLookupContext lookup_context = {
1695
      {intersects_coverage},
1696 1697
      this
    };
B
Behdad Esfahbod 已提交
1698
    context_closure_lookup (c,
1699
			    glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
B
Behdad Esfahbod 已提交
1700 1701
			    lookupCount, lookupRecord,
			    lookup_context);
1702 1703
  }

B
Behdad Esfahbod 已提交
1704 1705
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
1706
    TRACE_COLLECT_GLYPHS (this);
1707
    (this+coverageZ[0]).add_coverage (c->input);
1708

B
Behdad Esfahbod 已提交
1709
    const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
1710 1711
    struct ContextCollectGlyphsLookupContext lookup_context = {
      {collect_coverage},
1712
      this
1713 1714 1715
    };

    context_collect_glyphs_lookup (c,
1716
				   glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
1717 1718
				   lookupCount, lookupRecord,
				   lookup_context);
B
Behdad Esfahbod 已提交
1719 1720
  }

1721 1722
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1723
    TRACE_WOULD_APPLY (this);
1724

B
Behdad Esfahbod 已提交
1725
    const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
1726
    struct ContextApplyLookupContext lookup_context = {
1727
      {match_coverage},
1728 1729
      this
    };
1730
    return_trace (context_would_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, lookup_context));
1731 1732
  }

1733
  inline const Coverage &get_coverage (void) const
1734
  { return this+coverageZ[0]; }
1735

1736
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1737
  {
B
Behdad Esfahbod 已提交
1738
    TRACE_APPLY (this);
1739
    unsigned int index = (this+coverageZ[0]).get_coverage (c->buffer->cur().codepoint);
B
Behdad Esfahbod 已提交
1740
    if (likely (index == NOT_COVERED)) return_trace (false);
1741

B
Behdad Esfahbod 已提交
1742
    const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
1743
    struct ContextApplyLookupContext lookup_context = {
1744
      {match_coverage},
B
Behdad Esfahbod 已提交
1745
      this
1746
    };
1747
    return_trace (context_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, lookup_context));
1748 1749
  }

1750 1751 1752 1753 1754 1755 1756
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

B
Behdad Esfahbod 已提交
1757 1758
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1759
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1760
    if (!c->check_struct (this)) return_trace (false);
B
Behdad Esfahbod 已提交
1761
    unsigned int count = glyphCount;
B
Behdad Esfahbod 已提交
1762
    if (!count) return_trace (false); /* We want to access coverageZ[0] freely. */
1763
    if (!c->check_array (coverageZ.arrayZ, count)) return_trace (false);
B
Behdad Esfahbod 已提交
1764
    for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
1765
      if (!coverageZ[i].sanitize (c, this)) return_trace (false);
B
Behdad Esfahbod 已提交
1766
    const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
1767
    return_trace (c->check_array (lookupRecord, lookupCount));
B
Behdad Esfahbod 已提交
1768 1769
  }

1770
  protected:
B
Behdad Esfahbod 已提交
1771 1772
  HBUINT16	format;			/* Format identifier--format = 3 */
  HBUINT16	glyphCount;		/* Number of glyphs in the input glyph
1773
					 * sequence */
B
Behdad Esfahbod 已提交
1774
  HBUINT16	lookupCount;		/* Number of LookupRecords */
1775 1776
  UnsizedArrayOf<OffsetTo<Coverage> >
		coverageZ;		/* Array of offsets to Coverage
1777
					 * table in glyph sequence order */
1778 1779
/*UnsizedArrayOf<LookupRecord>
		lookupRecordX;*/	/* Array of LookupRecords--in
1780
					 * design order */
B
Behdad Esfahbod 已提交
1781
  public:
1782
  DEFINE_SIZE_ARRAY (6, coverageZ);
1783 1784
};

B
Behdad Esfahbod 已提交
1785 1786
struct Context
{
1787
  template <typename context_t>
1788
  inline typename context_t::return_t dispatch (context_t *c) const
1789
  {
1790
    TRACE_DISPATCH (this, u.format);
1791
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1792
    switch (u.format) {
B
Behdad Esfahbod 已提交
1793 1794 1795 1796
    case 1: return_trace (c->dispatch (u.format1));
    case 2: return_trace (c->dispatch (u.format2));
    case 3: return_trace (c->dispatch (u.format3));
    default:return_trace (c->default_return_value ());
1797 1798 1799
    }
  }

1800
  protected:
1801
  union {
B
Behdad Esfahbod 已提交
1802
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1803 1804 1805
  ContextFormat1	format1;
  ContextFormat2	format2;
  ContextFormat3	format3;
1806 1807 1808
  } u;
};

1809 1810 1811

/* Chaining Contextual lookups */

1812
struct ChainContextClosureLookupContext
B
Behdad Esfahbod 已提交
1813
{
1814 1815 1816 1817
  ContextClosureFuncs funcs;
  const void *intersects_data[3];
};

1818 1819 1820 1821 1822 1823
struct ChainContextCollectGlyphsLookupContext
{
  ContextCollectGlyphsFuncs funcs;
  const void *collect_data[3];
};

1824 1825 1826
struct ChainContextApplyLookupContext
{
  ContextApplyFuncs funcs;
B
Behdad Esfahbod 已提交
1827
  const void *match_data[3];
1828 1829
};

1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849
static inline bool chain_context_intersects (const hb_set_t *glyphs,
					     unsigned int backtrackCount,
					     const HBUINT16 backtrack[],
					     unsigned int inputCount, /* Including the first glyph (not matched) */
					     const HBUINT16 input[], /* Array of input values--start with second glyph */
					     unsigned int lookaheadCount,
					     const HBUINT16 lookahead[],
					     ChainContextClosureLookupContext &lookup_context)
{
  return intersects_array (glyphs,
			   backtrackCount, backtrack,
			   lookup_context.funcs.intersects, lookup_context.intersects_data[0])
      && intersects_array (glyphs,
			   inputCount ? inputCount - 1 : 0, input,
			   lookup_context.funcs.intersects, lookup_context.intersects_data[1])
      && intersects_array (glyphs,
			  lookaheadCount, lookahead,
			  lookup_context.funcs.intersects, lookup_context.intersects_data[2]);
}

B
Behdad Esfahbod 已提交
1850
static inline void chain_context_closure_lookup (hb_closure_context_t *c,
1851
						 unsigned int backtrackCount,
B
Behdad Esfahbod 已提交
1852
						 const HBUINT16 backtrack[],
1853
						 unsigned int inputCount, /* Including the first glyph (not matched) */
B
Behdad Esfahbod 已提交
1854
						 const HBUINT16 input[], /* Array of input values--start with second glyph */
1855
						 unsigned int lookaheadCount,
B
Behdad Esfahbod 已提交
1856
						 const HBUINT16 lookahead[],
1857 1858 1859 1860
						 unsigned int lookupCount,
						 const LookupRecord lookupRecord[],
						 ChainContextClosureLookupContext &lookup_context)
{
1861 1862 1863 1864 1865
  if (chain_context_intersects (c->glyphs,
				backtrackCount, backtrack,
				inputCount, input,
				lookaheadCount, lookahead,
				lookup_context))
1866 1867
    recurse_lookups (c,
		     lookupCount, lookupRecord);
1868 1869
}

1870
static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
E
Ebrahim Byagowi 已提交
1871 1872 1873 1874 1875 1876 1877 1878 1879
							unsigned int backtrackCount,
							const HBUINT16 backtrack[],
							unsigned int inputCount, /* Including the first glyph (not matched) */
							const HBUINT16 input[], /* Array of input values--start with second glyph */
							unsigned int lookaheadCount,
							const HBUINT16 lookahead[],
							unsigned int lookupCount,
							const LookupRecord lookupRecord[],
							ChainContextCollectGlyphsLookupContext &lookup_context)
1880
{
B
Minor  
Behdad Esfahbod 已提交
1881
  collect_array (c, c->before,
1882 1883
		 backtrackCount, backtrack,
		 lookup_context.funcs.collect, lookup_context.collect_data[0]);
B
Minor  
Behdad Esfahbod 已提交
1884
  collect_array (c, c->input,
1885 1886
		 inputCount ? inputCount - 1 : 0, input,
		 lookup_context.funcs.collect, lookup_context.collect_data[1]);
B
Minor  
Behdad Esfahbod 已提交
1887
  collect_array (c, c->after,
1888 1889 1890 1891 1892 1893
		 lookaheadCount, lookahead,
		 lookup_context.funcs.collect, lookup_context.collect_data[2]);
  recurse_lookups (c,
		   lookupCount, lookupRecord);
}

1894 1895
static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c,
						     unsigned int backtrackCount,
B
Behdad Esfahbod 已提交
1896
						     const HBUINT16 backtrack[] HB_UNUSED,
1897
						     unsigned int inputCount, /* Including the first glyph (not matched) */
B
Behdad Esfahbod 已提交
1898
						     const HBUINT16 input[], /* Array of input values--start with second glyph */
1899
						     unsigned int lookaheadCount,
B
Behdad Esfahbod 已提交
1900
						     const HBUINT16 lookahead[] HB_UNUSED,
B
Behdad Esfahbod 已提交
1901 1902
						     unsigned int lookupCount HB_UNUSED,
						     const LookupRecord lookupRecord[] HB_UNUSED,
1903 1904
						     ChainContextApplyLookupContext &lookup_context)
{
1905
  return (c->zero_context ? !backtrackCount && !lookaheadCount : true)
1906
      && would_match_input (c,
1907 1908 1909 1910
			    inputCount, input,
			    lookup_context.funcs.match, lookup_context.match_data[1]);
}

1911
static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
1912
					       unsigned int backtrackCount,
B
Behdad Esfahbod 已提交
1913
					       const HBUINT16 backtrack[],
1914
					       unsigned int inputCount, /* Including the first glyph (not matched) */
B
Behdad Esfahbod 已提交
1915
					       const HBUINT16 input[], /* Array of input values--start with second glyph */
1916
					       unsigned int lookaheadCount,
B
Behdad Esfahbod 已提交
1917
					       const HBUINT16 lookahead[],
1918 1919 1920
					       unsigned int lookupCount,
					       const LookupRecord lookupRecord[],
					       ChainContextApplyLookupContext &lookup_context)
1921
{
1922
  unsigned int start_index = 0, match_length = 0, end_index = 0;
1923
  unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
B
Behdad Esfahbod 已提交
1924
  return match_input (c,
B
Behdad Esfahbod 已提交
1925 1926
		      inputCount, input,
		      lookup_context.funcs.match, lookup_context.match_data[1],
1927
		      &match_length, match_positions)
B
Behdad Esfahbod 已提交
1928 1929
      && match_backtrack (c,
			  backtrackCount, backtrack,
1930 1931
			  lookup_context.funcs.match, lookup_context.match_data[0],
			  &start_index)
B
Behdad Esfahbod 已提交
1932
      && match_lookahead (c,
B
Behdad Esfahbod 已提交
1933 1934
			  lookaheadCount, lookahead,
			  lookup_context.funcs.match, lookup_context.match_data[2],
1935 1936
			  match_length, &end_index)
      && (c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index),
E
Ebrahim Byagowi 已提交
1937 1938 1939 1940
	  apply_lookup (c,
			inputCount, match_positions,
			lookupCount, lookupRecord,
			match_length));
1941
}
1942

B
Behdad Esfahbod 已提交
1943 1944
struct ChainRule
{
1945 1946 1947 1948 1949 1950
  inline bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
  {
    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
    return chain_context_intersects (glyphs,
				     backtrack.len, backtrack.arrayZ,
1951
				     input.lenP1, input.arrayZ,
1952 1953 1954 1955
				     lookahead.len, lookahead.arrayZ,
				     lookup_context);
  }

B
Behdad Esfahbod 已提交
1956
  inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
1957
  {
B
Behdad Esfahbod 已提交
1958
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
1959 1960
    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
1961
    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
B
Behdad Esfahbod 已提交
1962
    chain_context_closure_lookup (c,
1963
				  backtrack.len, backtrack.arrayZ,
1964
				  input.lenP1, input.arrayZ,
1965 1966
				  lookahead.len, lookahead.arrayZ,
				  lookup.len, lookup.arrayZ,
B
Behdad Esfahbod 已提交
1967
				  lookup_context);
1968 1969
  }

1970 1971 1972
  inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Behdad Esfahbod 已提交
1973 1974
    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
1975 1976
    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
    chain_context_collect_glyphs_lookup (c,
1977
					 backtrack.len, backtrack.arrayZ,
1978
					 input.lenP1, input.arrayZ,
1979 1980
					 lookahead.len, lookahead.arrayZ,
					 lookup.len, lookup.arrayZ,
1981 1982 1983
					 lookup_context);
  }

1984 1985
  inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
  {
B
Behdad Esfahbod 已提交
1986
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
1987 1988
    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
1989
    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
B
Behdad Esfahbod 已提交
1990
    return_trace (chain_context_would_apply_lookup (c,
1991
						    backtrack.len, backtrack.arrayZ,
1992
						    input.lenP1, input.arrayZ,
1993 1994
						    lookahead.len, lookahead.arrayZ, lookup.len,
						    lookup.arrayZ, lookup_context));
1995 1996
  }

1997
  inline bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
B
Behdad Esfahbod 已提交
1998
  {
B
Behdad Esfahbod 已提交
1999
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
2000 2001
    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
2002
    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
B
Behdad Esfahbod 已提交
2003
    return_trace (chain_context_apply_lookup (c,
2004
					      backtrack.len, backtrack.arrayZ,
2005
					      input.lenP1, input.arrayZ,
2006 2007
					      lookahead.len, lookahead.arrayZ, lookup.len,
					      lookup.arrayZ, lookup_context));
2008 2009
  }

B
Behdad Esfahbod 已提交
2010 2011
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
2012
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
2013
    if (!backtrack.sanitize (c)) return_trace (false);
B
Behdad Esfahbod 已提交
2014
    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
B
Behdad Esfahbod 已提交
2015
    if (!input.sanitize (c)) return_trace (false);
B
Behdad Esfahbod 已提交
2016
    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
B
Behdad Esfahbod 已提交
2017
    if (!lookahead.sanitize (c)) return_trace (false);
B
Behdad Esfahbod 已提交
2018
    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
B
Behdad Esfahbod 已提交
2019
    return_trace (lookup.sanitize (c));
B
Behdad Esfahbod 已提交
2020
  }
2021

2022
  protected:
B
Behdad Esfahbod 已提交
2023
  ArrayOf<HBUINT16>
B
Behdad Esfahbod 已提交
2024
		backtrack;		/* Array of backtracking values
2025 2026
					 * (to be matched before the input
					 * sequence) */
B
Behdad Esfahbod 已提交
2027
  HeadlessArrayOf<HBUINT16>
B
Behdad Esfahbod 已提交
2028
		inputX;			/* Array of input values (start with
2029
					 * second glyph) */
B
Behdad Esfahbod 已提交
2030
  ArrayOf<HBUINT16>
B
Behdad Esfahbod 已提交
2031
		lookaheadX;		/* Array of lookahead values's (to be
2032
					 * matched after the input sequence) */
B
Behdad Esfahbod 已提交
2033
  ArrayOf<LookupRecord>
2034
		lookupX;		/* Array of LookupRecords--in
2035
					 * design order) */
2036
  public:
B
Behdad Esfahbod 已提交
2037
  DEFINE_SIZE_MIN (8);
2038 2039
};

B
Behdad Esfahbod 已提交
2040 2041
struct ChainRuleSet
{
2042 2043 2044 2045 2046
  inline bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
  {
    unsigned int num_rules = rule.len;
    for (unsigned int i = 0; i < num_rules; i++)
      if ((this+rule[i]).intersects (glyphs, lookup_context))
E
Ebrahim Byagowi 已提交
2047
	return true;
2048 2049
    return false;
  }
B
Behdad Esfahbod 已提交
2050
  inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
2051
  {
B
Behdad Esfahbod 已提交
2052
    TRACE_CLOSURE (this);
2053 2054
    unsigned int num_rules = rule.len;
    for (unsigned int i = 0; i < num_rules; i++)
B
Behdad Esfahbod 已提交
2055
      (this+rule[i]).closure (c, lookup_context);
2056 2057
  }

2058 2059 2060 2061 2062 2063 2064 2065
  inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
  {
    TRACE_COLLECT_GLYPHS (this);
    unsigned int num_rules = rule.len;
    for (unsigned int i = 0; i < num_rules; i++)
      (this+rule[i]).collect_glyphs (c, lookup_context);
  }

2066 2067
  inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
  {
B
Behdad Esfahbod 已提交
2068
    TRACE_WOULD_APPLY (this);
2069 2070 2071
    unsigned int num_rules = rule.len;
    for (unsigned int i = 0; i < num_rules; i++)
      if ((this+rule[i]).would_apply (c, lookup_context))
E
Ebrahim Byagowi 已提交
2072
	return_trace (true);
2073

B
Behdad Esfahbod 已提交
2074
    return_trace (false);
2075 2076
  }

2077
  inline bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
B
Behdad Esfahbod 已提交
2078
  {
B
Behdad Esfahbod 已提交
2079
    TRACE_APPLY (this);
2080
    unsigned int num_rules = rule.len;
B
Behdad Esfahbod 已提交
2081
    for (unsigned int i = 0; i < num_rules; i++)
B
Behdad Esfahbod 已提交
2082
      if ((this+rule[i]).apply (c, lookup_context))
E
Ebrahim Byagowi 已提交
2083
	return_trace (true);
2084

B
Behdad Esfahbod 已提交
2085
    return_trace (false);
2086
  }
2087

B
Behdad Esfahbod 已提交
2088 2089
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
2090
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
2091
    return_trace (rule.sanitize (c, this));
B
Behdad Esfahbod 已提交
2092 2093
  }

2094
  protected:
2095 2096 2097
  OffsetArrayOf<ChainRule>
		rule;			/* Array of ChainRule tables
					 * ordered by preference */
2098
  public:
2099
  DEFINE_SIZE_ARRAY (2, rule);
2100 2101
};

B
Behdad Esfahbod 已提交
2102 2103
struct ChainContextFormat1
{
2104 2105 2106 2107 2108 2109 2110 2111
  inline bool intersects (const hb_set_t *glyphs) const
  {
    struct ChainContextClosureLookupContext lookup_context = {
      {intersects_glyph},
      {nullptr, nullptr, nullptr}
    };

    unsigned int count = ruleSet.len;
2112
    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
2113 2114
    {
      if (unlikely (iter.get_coverage () >= count))
E
Ebrahim Byagowi 已提交
2115
	break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
2116 2117
      if (glyphs->has (iter.get_glyph ()) &&
	  (this+ruleSet[iter.get_coverage ()]).intersects (glyphs, lookup_context))
E
Ebrahim Byagowi 已提交
2118
	return true;
2119 2120 2121 2122
    }
    return false;
  }

2123
  inline void closure (hb_closure_context_t *c) const
2124
  {
B
Behdad Esfahbod 已提交
2125
    TRACE_CLOSURE (this);
2126 2127

    struct ChainContextClosureLookupContext lookup_context = {
2128
      {intersects_glyph},
B
Behdad Esfahbod 已提交
2129
      {nullptr, nullptr, nullptr}
2130 2131 2132
    };

    unsigned int count = ruleSet.len;
2133
    for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
2134 2135
    {
      if (unlikely (iter.get_coverage () >= count))
E
Ebrahim Byagowi 已提交
2136
	break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
2137 2138 2139
      if (c->glyphs->has (iter.get_glyph ()))
	(this+ruleSet[iter.get_coverage ()]).closure (c, lookup_context);
    }
2140 2141
  }

B
Behdad Esfahbod 已提交
2142 2143
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
2144
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
2145
    (this+coverage).add_coverage (c->input);
2146 2147 2148

    struct ChainContextCollectGlyphsLookupContext lookup_context = {
      {collect_glyph},
B
Behdad Esfahbod 已提交
2149
      {nullptr, nullptr, nullptr}
2150 2151 2152 2153 2154
    };

    unsigned int count = ruleSet.len;
    for (unsigned int i = 0; i < count; i++)
      (this+ruleSet[i]).collect_glyphs (c, lookup_context);
B
Behdad Esfahbod 已提交
2155 2156
  }

2157 2158
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
2159
    TRACE_WOULD_APPLY (this);
2160

2161
    const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
2162
    struct ChainContextApplyLookupContext lookup_context = {
2163
      {match_glyph},
B
Behdad Esfahbod 已提交
2164
      {nullptr, nullptr, nullptr}
2165
    };
B
Behdad Esfahbod 已提交
2166
    return_trace (rule_set.would_apply (c, lookup_context));
2167 2168
  }

2169
  inline const Coverage &get_coverage (void) const
2170
  { return this+coverage; }
2171

2172
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
2173
  {
B
Behdad Esfahbod 已提交
2174
    TRACE_APPLY (this);
2175
    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
B
Behdad Esfahbod 已提交
2176
    if (likely (index == NOT_COVERED)) return_trace (false);
2177

2178
    const ChainRuleSet &rule_set = this+ruleSet[index];
2179
    struct ChainContextApplyLookupContext lookup_context = {
2180
      {match_glyph},
B
Behdad Esfahbod 已提交
2181
      {nullptr, nullptr, nullptr}
2182
    };
B
Behdad Esfahbod 已提交
2183
    return_trace (rule_set.apply (c, lookup_context));
2184
  }
B
Behdad Esfahbod 已提交
2185

2186 2187 2188 2189 2190 2191 2192
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

B
Behdad Esfahbod 已提交
2193 2194
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
2195
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
2196
    return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
2197 2198
  }

2199
  protected:
B
Behdad Esfahbod 已提交
2200
  HBUINT16	format;			/* Format identifier--format = 1 */
2201 2202
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
2203
					 * beginning of table */
2204 2205 2206
  OffsetArrayOf<ChainRuleSet>
		ruleSet;		/* Array of ChainRuleSet tables
					 * ordered by Coverage Index */
2207
  public:
2208
  DEFINE_SIZE_ARRAY (6, ruleSet);
2209 2210
};

B
Behdad Esfahbod 已提交
2211 2212
struct ChainContextFormat2
{
2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232
  inline bool intersects (const hb_set_t *glyphs) const
  {
    if (!(this+coverage).intersects (glyphs))
      return false;

    const ClassDef &backtrack_class_def = this+backtrackClassDef;
    const ClassDef &input_class_def = this+inputClassDef;
    const ClassDef &lookahead_class_def = this+lookaheadClassDef;

    struct ChainContextClosureLookupContext lookup_context = {
      {intersects_class},
      {&backtrack_class_def,
       &input_class_def,
       &lookahead_class_def}
    };

    unsigned int count = ruleSet.len;
    for (unsigned int i = 0; i < count; i++)
      if (input_class_def.intersects_class (glyphs, i) &&
	  (this+ruleSet[i]).intersects (glyphs, lookup_context))
E
Ebrahim Byagowi 已提交
2233
	return true;
2234 2235 2236

    return false;
  }
2237
  inline void closure (hb_closure_context_t *c) const
2238
  {
B
Behdad Esfahbod 已提交
2239
    TRACE_CLOSURE (this);
2240
    if (!(this+coverage).intersects (c->glyphs))
B
Behdad Esfahbod 已提交
2241
      return;
2242 2243 2244 2245 2246 2247

    const ClassDef &backtrack_class_def = this+backtrackClassDef;
    const ClassDef &input_class_def = this+inputClassDef;
    const ClassDef &lookahead_class_def = this+lookaheadClassDef;

    struct ChainContextClosureLookupContext lookup_context = {
2248
      {intersects_class},
2249 2250 2251 2252 2253 2254 2255 2256 2257
      {&backtrack_class_def,
       &input_class_def,
       &lookahead_class_def}
    };

    unsigned int count = ruleSet.len;
    for (unsigned int i = 0; i < count; i++)
      if (input_class_def.intersects_class (c->glyphs, i)) {
	const ChainRuleSet &rule_set = this+ruleSet[i];
B
Behdad Esfahbod 已提交
2258
	rule_set.closure (c, lookup_context);
2259
      }
2260 2261
  }

B
Behdad Esfahbod 已提交
2262 2263
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
2264
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
2265
    (this+coverage).add_coverage (c->input);
2266

2267 2268 2269 2270
    const ClassDef &backtrack_class_def = this+backtrackClassDef;
    const ClassDef &input_class_def = this+inputClassDef;
    const ClassDef &lookahead_class_def = this+lookaheadClassDef;

2271 2272
    struct ChainContextCollectGlyphsLookupContext lookup_context = {
      {collect_class},
2273 2274 2275
      {&backtrack_class_def,
       &input_class_def,
       &lookahead_class_def}
2276 2277 2278 2279 2280
    };

    unsigned int count = ruleSet.len;
    for (unsigned int i = 0; i < count; i++)
      (this+ruleSet[i]).collect_glyphs (c, lookup_context);
B
Behdad Esfahbod 已提交
2281 2282
  }

2283 2284
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
2285
    TRACE_WOULD_APPLY (this);
2286

2287
    const ClassDef &backtrack_class_def = this+backtrackClassDef;
2288
    const ClassDef &input_class_def = this+inputClassDef;
2289
    const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2290

2291
    unsigned int index = input_class_def.get_class (c->glyphs[0]);
2292 2293
    const ChainRuleSet &rule_set = this+ruleSet[index];
    struct ChainContextApplyLookupContext lookup_context = {
2294
      {match_class},
2295 2296 2297
      {&backtrack_class_def,
       &input_class_def,
       &lookahead_class_def}
2298
    };
B
Behdad Esfahbod 已提交
2299
    return_trace (rule_set.would_apply (c, lookup_context));
2300 2301
  }

2302
  inline const Coverage &get_coverage (void) const
2303
  { return this+coverage; }
2304

2305
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
2306
  {
B
Behdad Esfahbod 已提交
2307
    TRACE_APPLY (this);
2308
    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
B
Behdad Esfahbod 已提交
2309
    if (likely (index == NOT_COVERED)) return_trace (false);
2310 2311 2312 2313 2314

    const ClassDef &backtrack_class_def = this+backtrackClassDef;
    const ClassDef &input_class_def = this+inputClassDef;
    const ClassDef &lookahead_class_def = this+lookaheadClassDef;

2315
    index = input_class_def.get_class (c->buffer->cur().codepoint);
2316
    const ChainRuleSet &rule_set = this+ruleSet[index];
2317
    struct ChainContextApplyLookupContext lookup_context = {
2318
      {match_class},
B
Behdad Esfahbod 已提交
2319 2320 2321
      {&backtrack_class_def,
       &input_class_def,
       &lookahead_class_def}
2322
    };
B
Behdad Esfahbod 已提交
2323
    return_trace (rule_set.apply (c, lookup_context));
2324 2325
  }

2326 2327 2328 2329 2330 2331 2332
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

B
Behdad Esfahbod 已提交
2333 2334
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
2335
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
2336 2337 2338 2339 2340
    return_trace (coverage.sanitize (c, this) &&
		  backtrackClassDef.sanitize (c, this) &&
		  inputClassDef.sanitize (c, this) &&
		  lookaheadClassDef.sanitize (c, this) &&
		  ruleSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
2341 2342
  }

2343
  protected:
B
Behdad Esfahbod 已提交
2344
  HBUINT16	format;			/* Format identifier--format = 2 */
2345 2346
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
2347
					 * beginning of table */
2348 2349
  OffsetTo<ClassDef>
		backtrackClassDef;	/* Offset to glyph ClassDef table
2350 2351
					 * containing backtrack sequence
					 * data--from beginning of table */
2352 2353
  OffsetTo<ClassDef>
		inputClassDef;		/* Offset to glyph ClassDef
2354 2355
					 * table containing input sequence
					 * data--from beginning of table */
2356 2357
  OffsetTo<ClassDef>
		lookaheadClassDef;	/* Offset to glyph ClassDef table
2358 2359
					 * containing lookahead sequence
					 * data--from beginning of table */
2360 2361 2362
  OffsetArrayOf<ChainRuleSet>
		ruleSet;		/* Array of ChainRuleSet tables
					 * ordered by class */
2363
  public:
2364
  DEFINE_SIZE_ARRAY (12, ruleSet);
2365 2366
};

B
Behdad Esfahbod 已提交
2367 2368
struct ChainContextFormat3
{
2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387
  inline bool intersects (const hb_set_t *glyphs) const
  {
    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);

    if (!(this+input[0]).intersects (glyphs))
      return false;

    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
    struct ChainContextClosureLookupContext lookup_context = {
      {intersects_coverage},
      {this, this, this}
    };
    return chain_context_intersects (glyphs,
				     backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
				     input.len, (const HBUINT16 *) input.arrayZ + 1,
				     lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
				     lookup_context);
  }

2388
  inline void closure (hb_closure_context_t *c) const
2389
  {
B
Behdad Esfahbod 已提交
2390
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
2391 2392 2393 2394 2395 2396 2397 2398
    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);

    if (!(this+input[0]).intersects (c->glyphs))
      return;

    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
    struct ChainContextClosureLookupContext lookup_context = {
2399
      {intersects_coverage},
B
Behdad Esfahbod 已提交
2400 2401 2402
      {this, this, this}
    };
    chain_context_closure_lookup (c,
2403 2404 2405 2406
				  backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
				  input.len, (const HBUINT16 *) input.arrayZ + 1,
				  lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
				  lookup.len, lookup.arrayZ,
B
Behdad Esfahbod 已提交
2407
				  lookup_context);
2408 2409
  }

B
Behdad Esfahbod 已提交
2410 2411
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
2412 2413 2414
    TRACE_COLLECT_GLYPHS (this);
    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);

B
Minor  
Behdad Esfahbod 已提交
2415
    (this+input[0]).add_coverage (c->input);
2416 2417 2418 2419 2420 2421 2422 2423

    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
    struct ChainContextCollectGlyphsLookupContext lookup_context = {
      {collect_coverage},
      {this, this, this}
    };
    chain_context_collect_glyphs_lookup (c,
2424 2425 2426 2427
					 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
					 input.len, (const HBUINT16 *) input.arrayZ + 1,
					 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
					 lookup.len, lookup.arrayZ,
2428
					 lookup_context);
B
Behdad Esfahbod 已提交
2429 2430
  }

2431 2432
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
2433
    TRACE_WOULD_APPLY (this);
2434

B
Behdad Esfahbod 已提交
2435
    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2436 2437 2438
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
    struct ChainContextApplyLookupContext lookup_context = {
2439
      {match_coverage},
2440 2441
      {this, this, this}
    };
B
Behdad Esfahbod 已提交
2442
    return_trace (chain_context_would_apply_lookup (c,
2443 2444 2445 2446
						    backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
						    input.len, (const HBUINT16 *) input.arrayZ + 1,
						    lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
						    lookup.len, lookup.arrayZ, lookup_context));
2447 2448
  }

2449 2450 2451 2452 2453 2454
  inline const Coverage &get_coverage (void) const
  {
    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
    return this+input[0];
  }

2455
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
2456
  {
B
Behdad Esfahbod 已提交
2457
    TRACE_APPLY (this);
2458
    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2459

2460
    unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint);
B
Behdad Esfahbod 已提交
2461
    if (likely (index == NOT_COVERED)) return_trace (false);
2462

2463 2464
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2465
    struct ChainContextApplyLookupContext lookup_context = {
2466
      {match_coverage},
B
Behdad Esfahbod 已提交
2467
      {this, this, this}
2468
    };
B
Behdad Esfahbod 已提交
2469
    return_trace (chain_context_apply_lookup (c,
2470 2471 2472 2473
					      backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
					      input.len, (const HBUINT16 *) input.arrayZ + 1,
					      lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
					      lookup.len, lookup.arrayZ, lookup_context));
2474 2475
  }

2476 2477 2478 2479 2480 2481 2482
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

B
Behdad Esfahbod 已提交
2483 2484
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
2485
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
2486
    if (!backtrack.sanitize (c, this)) return_trace (false);
B
Behdad Esfahbod 已提交
2487
    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
B
Behdad Esfahbod 已提交
2488 2489
    if (!input.sanitize (c, this)) return_trace (false);
    if (!input.len) return_trace (false); /* To be consistent with Context. */
B
Behdad Esfahbod 已提交
2490
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
B
Behdad Esfahbod 已提交
2491
    if (!lookahead.sanitize (c, this)) return_trace (false);
B
Behdad Esfahbod 已提交
2492
    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
B
Behdad Esfahbod 已提交
2493
    return_trace (lookup.sanitize (c));
B
Behdad Esfahbod 已提交
2494 2495
  }

2496
  protected:
B
Behdad Esfahbod 已提交
2497
  HBUINT16	format;			/* Format identifier--format = 3 */
B
Behdad Esfahbod 已提交
2498
  OffsetArrayOf<Coverage>
2499
		backtrack;		/* Array of coverage tables
2500 2501
					 * in backtracking sequence, in  glyph
					 * sequence order */
B
Behdad Esfahbod 已提交
2502
  OffsetArrayOf<Coverage>
2503
		inputX		;	/* Array of coverage
2504 2505
					 * tables in input sequence, in glyph
					 * sequence order */
B
Behdad Esfahbod 已提交
2506
  OffsetArrayOf<Coverage>
2507
		lookaheadX;		/* Array of coverage tables
2508 2509
					 * in lookahead sequence, in glyph
					 * sequence order */
B
Behdad Esfahbod 已提交
2510
  ArrayOf<LookupRecord>
2511
		lookupX;		/* Array of LookupRecords--in
B
Behdad Esfahbod 已提交
2512
					 * design order) */
2513
  public:
B
Behdad Esfahbod 已提交
2514
  DEFINE_SIZE_MIN (10);
2515 2516
};

B
Behdad Esfahbod 已提交
2517 2518
struct ChainContext
{
2519
  template <typename context_t>
2520
  inline typename context_t::return_t dispatch (context_t *c) const
2521
  {
2522
    TRACE_DISPATCH (this, u.format);
2523
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
2524
    switch (u.format) {
B
Behdad Esfahbod 已提交
2525 2526 2527 2528
    case 1: return_trace (c->dispatch (u.format1));
    case 2: return_trace (c->dispatch (u.format2));
    case 3: return_trace (c->dispatch (u.format3));
    default:return_trace (c->default_return_value ());
2529 2530 2531
    }
  }

2532
  protected:
2533
  union {
B
Behdad Esfahbod 已提交
2534
  HBUINT16		format;	/* Format identifier */
B
Behdad Esfahbod 已提交
2535 2536 2537
  ChainContextFormat1	format1;
  ChainContextFormat2	format2;
  ChainContextFormat3	format3;
2538 2539 2540 2541
  } u;
};


2542
template <typename T>
2543 2544 2545 2546
struct ExtensionFormat1
{
  inline unsigned int get_type (void) const { return extensionLookupType; }

2547 2548 2549 2550
  template <typename X>
  inline const X& get_subtable (void) const
  {
    unsigned int offset = extensionOffset;
B
Behdad Esfahbod 已提交
2551 2552
    if (unlikely (!offset)) return Null(typename T::SubTable);
    return StructAtOffset<typename T::SubTable> (this, offset);
2553 2554 2555 2556 2557 2558
  }

  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
  {
    TRACE_DISPATCH (this, format);
2559
    if (unlikely (!c->may_dispatch (this, this))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
2560
    return_trace (get_subtable<typename T::SubTable> ().dispatch (c, get_type ()));
2561 2562 2563
  }

  /* This is called from may_dispatch() above with hb_sanitize_context_t. */
B
Behdad Esfahbod 已提交
2564 2565
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
2566
    TRACE_SANITIZE (this);
2567 2568
    return_trace (c->check_struct (this) &&
		  extensionOffset != 0 &&
B
Behdad Esfahbod 已提交
2569
		  extensionLookupType != T::SubTable::Extension);
B
Behdad Esfahbod 已提交
2570 2571
  }

2572
  protected:
B
Behdad Esfahbod 已提交
2573 2574
  HBUINT16	format;			/* Format identifier. Set to 1. */
  HBUINT16	extensionLookupType;	/* Lookup type of subtable referenced
2575 2576
					 * by ExtensionOffset (i.e. the
					 * extension subtable). */
B
Behdad Esfahbod 已提交
2577
  HBUINT32	extensionOffset;	/* Offset to the extension subtable,
2578
					 * of lookup type subtable. */
2579 2580
  public:
  DEFINE_SIZE_STATIC (8);
2581 2582
};

B
Behdad Esfahbod 已提交
2583
template <typename T>
2584 2585 2586 2587 2588
struct Extension
{
  inline unsigned int get_type (void) const
  {
    switch (u.format) {
B
Behdad Esfahbod 已提交
2589
    case 1: return u.format1.get_type ();
2590 2591 2592
    default:return 0;
    }
  }
2593 2594 2595
  template <typename X>
  inline const X& get_subtable (void) const
  {
2596
    switch (u.format) {
B
Behdad Esfahbod 已提交
2597 2598
    case 1: return u.format1.template get_subtable<typename T::SubTable> ();
    default:return Null(typename T::SubTable);
2599
    }
2600 2601
  }

B
Behdad Esfahbod 已提交
2602
  template <typename context_t>
2603
  inline typename context_t::return_t dispatch (context_t *c) const
B
Behdad Esfahbod 已提交
2604
  {
2605
    TRACE_DISPATCH (this, u.format);
2606
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
2607
    switch (u.format) {
B
Behdad Esfahbod 已提交
2608 2609
    case 1: return_trace (u.format1.dispatch (c));
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
2610 2611 2612
    }
  }

2613
  protected:
2614
  union {
B
Behdad Esfahbod 已提交
2615
  HBUINT16		format;		/* Format identifier */
2616
  ExtensionFormat1<T>	format1;
2617 2618 2619 2620
  } u;
};


B
Behdad Esfahbod 已提交
2621 2622 2623 2624
/*
 * GSUB/GPOS Common
 */

B
Behdad Esfahbod 已提交
2625 2626 2627 2628 2629 2630 2631
struct hb_ot_layout_lookup_accelerator_t
{
  template <typename TLookup>
  inline void init (const TLookup &lookup)
  {
    digest.init ();
    lookup.add_coverage (&digest);
2632 2633 2634 2635 2636 2637 2638 2639

    subtables.init ();
    OT::hb_get_subtables_context_t c_get_subtables (subtables);
    lookup.dispatch (&c_get_subtables);
  }
  inline void fini (void)
  {
    subtables.fini ();
B
Behdad Esfahbod 已提交
2640 2641 2642 2643 2644
  }

  inline bool may_have (hb_codepoint_t g) const
  { return digest.may_have (g); }

2645 2646
  inline bool apply (hb_ot_apply_context_t *c) const
  {
E
Ebrahim Byagowi 已提交
2647 2648 2649 2650
    for (unsigned int i = 0; i < subtables.len; i++)
      if (subtables[i].apply (c))
	return true;
    return false;
2651 2652 2653
  }

  private:
B
Behdad Esfahbod 已提交
2654
  hb_set_digest_t digest;
2655
  hb_get_subtables_context_t::array_t subtables;
B
Behdad Esfahbod 已提交
2656 2657
};

B
Behdad Esfahbod 已提交
2658 2659
struct GSUBGPOS
{
B
Minor  
Behdad Esfahbod 已提交
2660
  inline bool has_data (void) const { return version.to_int (); }
2661 2662 2663 2664
  inline unsigned int get_script_count (void) const
  { return (this+scriptList).len; }
  inline const Tag& get_script_tag (unsigned int i) const
  { return (this+scriptList).get_tag (i); }
B
Behdad Esfahbod 已提交
2665 2666 2667 2668
  inline unsigned int get_script_tags (unsigned int start_offset,
				       unsigned int *script_count /* IN/OUT */,
				       hb_tag_t     *script_tags /* OUT */) const
  { return (this+scriptList).get_tags (start_offset, script_count, script_tags); }
2669 2670 2671 2672 2673 2674 2675
  inline const Script& get_script (unsigned int i) const
  { return (this+scriptList)[i]; }
  inline bool find_script_index (hb_tag_t tag, unsigned int *index) const
  { return (this+scriptList).find_index (tag, index); }

  inline unsigned int get_feature_count (void) const
  { return (this+featureList).len; }
2676 2677
  inline hb_tag_t get_feature_tag (unsigned int i) const
  { return i == Index::NOT_FOUND_INDEX ? HB_TAG_NONE : (this+featureList).get_tag (i); }
B
Behdad Esfahbod 已提交
2678 2679 2680 2681
  inline unsigned int get_feature_tags (unsigned int start_offset,
					unsigned int *feature_count /* IN/OUT */,
					hb_tag_t     *feature_tags /* OUT */) const
  { return (this+featureList).get_tags (start_offset, feature_count, feature_tags); }
2682 2683 2684 2685 2686 2687 2688 2689 2690
  inline const Feature& get_feature (unsigned int i) const
  { return (this+featureList)[i]; }
  inline bool find_feature_index (hb_tag_t tag, unsigned int *index) const
  { return (this+featureList).find_index (tag, index); }

  inline unsigned int get_lookup_count (void) const
  { return (this+lookupList).len; }
  inline const Lookup& get_lookup (unsigned int i) const
  { return (this+lookupList)[i]; }
B
Behdad Esfahbod 已提交
2691

2692 2693
  inline bool find_variations_index (const int *coords, unsigned int num_coords,
				     unsigned int *index) const
2694
  { return (version.to_int () >= 0x00010001u ? this+featureVars : Null(FeatureVariations))
2695
	   .find_index (coords, num_coords, index); }
2696 2697 2698 2699 2700 2701
  inline const Feature& get_feature_variation (unsigned int feature_index,
					       unsigned int variations_index) const
  {
    if (FeatureVariations::NOT_FOUND_INDEX != variations_index &&
	version.to_int () >= 0x00010001u)
    {
2702 2703
      const Feature *feature = (this+featureVars).find_substitute (variations_index,
								   feature_index);
2704
      if (feature)
E
Ebrahim Byagowi 已提交
2705
	return *feature;
2706 2707 2708
    }
    return get_feature (feature_index);
  }
2709

B
Behdad Esfahbod 已提交
2710
  template <typename TLookup>
2711 2712 2713 2714 2715
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    struct GSUBGPOS *out = c->serializer->embed (*this);
    if (unlikely (!out)) return_trace (false);
2716 2717
    out->scriptList.serialize_subset (c, this+scriptList, out);
    out->featureList.serialize_subset (c, this+featureList, out);
B
Behdad Esfahbod 已提交
2718 2719 2720 2721 2722 2723 2724 2725

    typedef OffsetListOf<TLookup> TLookupList;
    /* TODO Use intersects() to count how many subtables survive? */
    CastR<OffsetTo<TLookupList> > (out->lookupList)
      .serialize_subset (c,
			 this+CastR<const OffsetTo<TLookupList> > (lookupList),
			 out);

2726
    if (version.to_int () >= 0x00010001u)
2727
     out->featureVars.serialize_subset (c, this+featureVars, out);
2728 2729 2730 2731 2732 2733 2734 2735 2736
    return_trace (true);
  }

  inline unsigned int get_size (void) const
  {
    return min_size +
	   (version.to_int () >= 0x00010001u ? featureVars.static_size : 0);
  }

2737
  template <typename TLookup>
B
Behdad Esfahbod 已提交
2738 2739
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
2740
    TRACE_SANITIZE (this);
2741
    typedef OffsetListOf<TLookup> TLookupList;
B
Behdad Esfahbod 已提交
2742 2743 2744 2745
    return_trace (version.sanitize (c) &&
		  likely (version.major == 1) &&
		  scriptList.sanitize (c, this) &&
		  featureList.sanitize (c, this) &&
2746
		  CastR<OffsetTo<TLookupList> > (lookupList).sanitize (c, this) &&
2747
		  (version.to_int () < 0x00010001u || featureVars.sanitize (c, this)));
B
Behdad Esfahbod 已提交
2748 2749
  }

B
WIP  
Behdad Esfahbod 已提交
2750 2751 2752 2753 2754
  template <typename T>
  struct accelerator_t
  {
    inline void init (hb_face_t *face)
    {
B
Behdad Esfahbod 已提交
2755
      this->table = hb_sanitize_context_t().reference_table<T> (face);
2756 2757 2758 2759 2760
      if (unlikely (this->table->is_blacklisted (this->table.get_blob (), face)))
      {
	hb_blob_destroy (this->table.get_blob ());
	this->table = hb_blob_get_empty ();
      }
B
WIP  
Behdad Esfahbod 已提交
2761

2762
      this->lookup_count = table->get_lookup_count ();
B
WIP  
Behdad Esfahbod 已提交
2763 2764 2765

      this->accels = (hb_ot_layout_lookup_accelerator_t *) calloc (this->lookup_count, sizeof (hb_ot_layout_lookup_accelerator_t));
      if (unlikely (!this->accels))
E
Ebrahim Byagowi 已提交
2766
	this->lookup_count = 0;
B
WIP  
Behdad Esfahbod 已提交
2767 2768

      for (unsigned int i = 0; i < this->lookup_count; i++)
2769
	this->accels[i].init (table->get_lookup (i));
B
WIP  
Behdad Esfahbod 已提交
2770 2771 2772 2773
    }

    inline void fini (void)
    {
2774 2775 2776
      for (unsigned int i = 0; i < this->lookup_count; i++)
	this->accels[i].fini ();
      free (this->accels);
B
Behdad Esfahbod 已提交
2777
      this->table.destroy ();
B
WIP  
Behdad Esfahbod 已提交
2778 2779
    }

B
Behdad Esfahbod 已提交
2780
    hb_blob_ptr_t<T> table;
2781 2782
    unsigned int lookup_count;
    hb_ot_layout_lookup_accelerator_t *accels;
B
WIP  
Behdad Esfahbod 已提交
2783 2784
  };

2785
  protected:
B
Behdad Esfahbod 已提交
2786
  FixedVersion<>version;	/* Version of the GSUB/GPOS table--initially set
2787
				 * to 0x00010000u */
B
Behdad Esfahbod 已提交
2788 2789 2790 2791 2792 2793
  OffsetTo<ScriptList>
		scriptList;  	/* ScriptList table */
  OffsetTo<FeatureList>
		featureList; 	/* FeatureList table */
  OffsetTo<LookupList>
		lookupList; 	/* LookupList table */
B
Behdad Esfahbod 已提交
2794
  LOffsetTo<FeatureVariations>
2795 2796 2797 2798
		featureVars;	/* Offset to Feature Variations
				   table--from beginning of table
				 * (may be NULL).  Introduced
				 * in version 0x00010001. */
2799
  public:
2800
  DEFINE_SIZE_MIN (10);
B
Behdad Esfahbod 已提交
2801
};
2802

2803

B
Behdad Esfahbod 已提交
2804
} /* namespace OT */
2805

B
Behdad Esfahbod 已提交
2806

2807
#endif /* HB_OT_LAYOUT_GSUBGPOS_HH */