hb-ot-layout-gsubgpos.hh 89.9 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_auto_t<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_,
103
                        hb_map_t *done_lookups_,
104
		        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 110
			  debug_depth (0),
                          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);
202

203
    return;
B
Behdad Esfahbod 已提交
204 205
  }

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

  hb_collect_glyphs_context_t (hb_face_t *face_,
B
Behdad Esfahbod 已提交
217 218 219 220
			       hb_set_t  *glyphs_before, /* OUT. May be nullptr */
			       hb_set_t  *glyphs_input,  /* OUT. May be nullptr */
			       hb_set_t  *glyphs_after,  /* OUT. May be nullptr */
			       hb_set_t  *glyphs_output, /* OUT. May be nullptr */
221
			       unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
222
			      face (face_),
B
Minor  
Behdad Esfahbod 已提交
223 224 225 226
			      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 已提交
227
			      recurse_func (nullptr),
228
			      recursed_lookups (hb_set_create ()),
B
Behdad Esfahbod 已提交
229
			      nesting_level_left (nesting_level_left_),
230 231
			      debug_depth (0) {}
  ~hb_collect_glyphs_context_t (void) { hb_set_destroy (recursed_lookups); }
B
Behdad Esfahbod 已提交
232 233

  void set_recurse_func (recurse_func_t func) { recurse_func = func; }
234 235 236 237
};



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

253 254
  hb_add_coverage_context_t (set_t *set_) :
			    set (set_),
255 256
			    debug_depth (0) {}

257
  set_t *set;
258
  unsigned int debug_depth;
259 260 261
};


B
Behdad Esfahbod 已提交
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
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
  {
    inline void init (const void *obj_, hb_apply_func_t apply_func_)
    {
      obj = obj_;
      apply_func = apply_func_;
    }

    inline bool apply (OT::hb_ot_apply_context_t *c) const { return apply_func (obj, c); }

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

289
  typedef hb_vector_t<hb_applicable_t, 2> array_t;
B
Behdad Esfahbod 已提交
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311

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


312 313
struct hb_ot_apply_context_t :
       hb_dispatch_context_t<hb_ot_apply_context_t, bool, HB_DEBUG_APPLY>
314
{
315
  struct matcher_t
B
Behdad Esfahbod 已提交
316
  {
317 318
    inline matcher_t (void) :
	     lookup_props (0),
319 320
	     ignore_zwnj (false),
	     ignore_zwj (false),
321 322 323 324
	     mask (-1),
#define arg1(arg) (arg) /* Remove the macro to see why it's needed! */
	     syllable arg1(0),
#undef arg1
B
Behdad Esfahbod 已提交
325 326
	     match_func (nullptr),
	     match_data (nullptr) {};
327

B
Behdad Esfahbod 已提交
328
    typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data);
329 330

    inline void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; }
331
    inline void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
332 333 334 335 336 337 338
    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_; }

339 340 341 342 343 344 345
    enum may_match_t {
      MATCH_NO,
      MATCH_YES,
      MATCH_MAYBE
    };

    inline may_match_t may_match (const hb_glyph_info_t &info,
B
Behdad Esfahbod 已提交
346
				  const HBUINT16          *glyph_data) const
B
Behdad Esfahbod 已提交
347
    {
348 349 350 351 352 353 354 355
      if (!(info.mask & mask) ||
	  (syllable && syllable != info.syllable ()))
	return MATCH_NO;

      if (match_func)
        return match_func (info.codepoint, *glyph_data, match_data) ? MATCH_YES : MATCH_NO;

      return MATCH_MAYBE;
B
Behdad Esfahbod 已提交
356
    }
357 358 359 360 361 362 363 364

    enum may_skip_t {
      SKIP_NO,
      SKIP_YES,
      SKIP_MAYBE
    };

    inline may_skip_t
365
    may_skip (const hb_ot_apply_context_t *c,
366
	      const hb_glyph_info_t    &info) const
B
Behdad Esfahbod 已提交
367
    {
B
Behdad Esfahbod 已提交
368
      if (!c->check_glyph_property (&info, lookup_props))
369 370
	return SKIP_YES;

371
      if (unlikely (_hb_glyph_info_is_default_ignorable_and_not_hidden (&info) &&
372
		    (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) &&
373
		    (ignore_zwj || !_hb_glyph_info_is_zwj (&info))))
374 375 376
	return SKIP_MAYBE;

      return SKIP_NO;
B
Behdad Esfahbod 已提交
377
    }
378 379 380 381

    protected:
    unsigned int lookup_props;
    bool ignore_zwnj;
382
    bool ignore_zwj;
383 384 385 386 387 388
    hb_mask_t mask;
    uint8_t syllable;
    match_func_t match_func;
    const void *match_data;
  };

389
  struct skipping_iterator_t
390
  {
391
    inline void init (hb_ot_apply_context_t *c_, bool context_match = false)
B
Behdad Esfahbod 已提交
392
    {
393
      c = c_;
B
Behdad Esfahbod 已提交
394 395
      match_glyph_data = nullptr;
      matcher.set_match_func (nullptr, nullptr);
396
      matcher.set_lookup_props (c->lookup_props);
B
Behdad Esfahbod 已提交
397
      /* Ignore ZWNJ if we are matching GPOS, or matching GSUB context and asked to. */
398
      matcher.set_ignore_zwnj (c->table_index == 1 || (context_match && c->auto_zwnj));
B
Behdad Esfahbod 已提交
399 400
      /* Ignore ZWJ if we are matching context, or asked to. */
      matcher.set_ignore_zwj  (context_match || c->auto_zwj);
401 402 403 404 405
      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 已提交
406
    }
B
Behdad Esfahbod 已提交
407 408
    inline void set_match_func (matcher_t::match_func_t match_func_,
				const void *match_data_,
B
Behdad Esfahbod 已提交
409
				const HBUINT16 glyph_data[])
410
    {
B
Behdad Esfahbod 已提交
411
      matcher.set_match_func (match_func_, match_data_);
412
      match_glyph_data = glyph_data;
413
    }
414

415 416 417 418 419 420 421 422 423
    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);
    }

424
    inline void reject (void) { num_items++; match_glyph_data--; }
425

426
    inline matcher_t::may_skip_t
B
Behdad Esfahbod 已提交
427
    may_skip (const hb_glyph_info_t    &info) const
428 429 430 431
    {
      return matcher.may_skip (c, info);
    }

B
Behdad Esfahbod 已提交
432
    inline bool next (void)
B
Behdad Esfahbod 已提交
433
    {
434
      assert (num_items > 0);
435
      while (idx + num_items < end)
B
Behdad Esfahbod 已提交
436
      {
B
Behdad Esfahbod 已提交
437
	idx++;
438 439
	const hb_glyph_info_t &info = c->buffer->info[idx];

B
Minor  
Behdad Esfahbod 已提交
440
	matcher_t::may_skip_t skip = matcher.may_skip (c, info);
441 442 443
	if (unlikely (skip == matcher_t::SKIP_YES))
	  continue;

444
	matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
B
Behdad Esfahbod 已提交
445 446 447
	if (match == matcher_t::MATCH_YES ||
	    (match == matcher_t::MATCH_MAYBE &&
	     skip == matcher_t::SKIP_NO))
448 449 450 451 452 453 454
	{
	  num_items--;
	  match_glyph_data++;
	  return true;
	}

	if (skip == matcher_t::SKIP_NO)
B
Behdad Esfahbod 已提交
455
	  return false;
456 457
      }
      return false;
B
Behdad Esfahbod 已提交
458
    }
B
Behdad Esfahbod 已提交
459
    inline bool prev (void)
B
Behdad Esfahbod 已提交
460
    {
461
      assert (num_items > 0);
B
Behdad Esfahbod 已提交
462
      while (idx > num_items - 1)
B
Behdad Esfahbod 已提交
463 464
      {
	idx--;
465 466
	const hb_glyph_info_t &info = c->buffer->out_info[idx];

B
Minor  
Behdad Esfahbod 已提交
467
	matcher_t::may_skip_t skip = matcher.may_skip (c, info);
468 469 470
	if (unlikely (skip == matcher_t::SKIP_YES))
	  continue;

471
	matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
B
Behdad Esfahbod 已提交
472 473 474
	if (match == matcher_t::MATCH_YES ||
	    (match == matcher_t::MATCH_MAYBE &&
	     skip == matcher_t::SKIP_NO))
475 476 477 478 479 480 481
	{
	  num_items--;
	  match_glyph_data++;
	  return true;
	}

	if (skip == matcher_t::SKIP_NO)
B
Behdad Esfahbod 已提交
482
	  return false;
483 484
      }
      return false;
B
Behdad Esfahbod 已提交
485 486 487
    }

    unsigned int idx;
488
    protected:
489
    hb_ot_apply_context_t *c;
490
    matcher_t matcher;
B
Behdad Esfahbod 已提交
491
    const HBUINT16 *match_glyph_data;
492

B
Behdad Esfahbod 已提交
493
    unsigned int num_items;
494
    unsigned int end;
B
Behdad Esfahbod 已提交
495 496
  };

B
Behdad Esfahbod 已提交
497 498

  inline const char *get_name (void) { return "APPLY"; }
499
  typedef return_t (*recurse_func_t) (hb_ot_apply_context_t *c, unsigned int lookup_index);
B
Behdad Esfahbod 已提交
500 501 502 503
  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 已提交
504
  return_t recurse (unsigned int sub_lookup_index)
B
Behdad Esfahbod 已提交
505
  {
506
    if (unlikely (nesting_level_left == 0 || !recurse_func || buffer->max_ops-- <= 0))
B
Behdad Esfahbod 已提交
507 508 509
      return default_return_value ();

    nesting_level_left--;
B
Behdad Esfahbod 已提交
510
    bool ret = recurse_func (this, sub_lookup_index);
B
Behdad Esfahbod 已提交
511 512 513 514
    nesting_level_left++;
    return ret;
  }

515 516
  skipping_iterator_t iter_input, iter_context;

B
Behdad Esfahbod 已提交
517 518 519 520 521
  hb_font_t *font;
  hb_face_t *face;
  hb_buffer_t *buffer;
  recurse_func_t recurse_func;
  const GDEF &gdef;
522
  const VariationStore &var_store;
523 524 525 526

  hb_direction_t direction;
  hb_mask_t lookup_mask;
  unsigned int table_index; /* GSUB/GPOS */
527
  unsigned int lookup_index;
528 529
  unsigned int lookup_props;
  unsigned int nesting_level_left;
B
Behdad Esfahbod 已提交
530 531
  unsigned int debug_depth;

532
  bool has_glyph_classes;
533 534
  bool auto_zwnj;
  bool auto_zwj;
D
David Corbett 已提交
535
  bool random;
536

B
Behdad Esfahbod 已提交
537
  uint32_t random_state;
538

B
Behdad Esfahbod 已提交
539

540
  hb_ot_apply_context_t (unsigned int table_index_,
B
Behdad Esfahbod 已提交
541 542
		      hb_font_t *font_,
		      hb_buffer_t *buffer_) :
543
			iter_input (), iter_context (),
B
Behdad Esfahbod 已提交
544
			font (font_), face (font->face), buffer (buffer_),
B
Behdad Esfahbod 已提交
545
			recurse_func (nullptr),
546
			gdef (_get_gdef (face)),
547
			var_store (gdef.get_var_store ()),
548 549 550
			direction (buffer_->props.direction),
			lookup_mask (1),
			table_index (table_index_),
551
			lookup_index ((unsigned int) -1),
552 553 554
			lookup_props (0),
			nesting_level_left (HB_MAX_NESTING_LEVEL),
			debug_depth (0),
555
			has_glyph_classes (gdef.has_glyph_classes ()),
556 557
			auto_zwnj (true),
			auto_zwj (true),
D
David Corbett 已提交
558
			random (false),
B
Behdad Esfahbod 已提交
559
			random_state (1) { init_iters (); }
B
Behdad Esfahbod 已提交
560

B
Behdad Esfahbod 已提交
561
  inline void init_iters (void)
562 563 564 565
  {
    iter_input.init (this, false);
    iter_context.init (this, true);
  }
B
Behdad Esfahbod 已提交
566

B
Behdad Esfahbod 已提交
567 568 569
  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 (); }
570 571 572
  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 已提交
573
  inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; init_iters (); }
574

B
Behdad Esfahbod 已提交
575 576
  inline uint32_t random_number (void)
  {
B
Behdad Esfahbod 已提交
577 578 579
    /* http://www.cplusplus.com/reference/random/minstd_rand/ */
    random_state = random_state * 48271 % 2147483647;
    return random_state;
B
Behdad Esfahbod 已提交
580 581
  }

582 583 584
  inline bool
  match_properties_mark (hb_codepoint_t  glyph,
			 unsigned int    glyph_props,
B
Behdad Esfahbod 已提交
585
			 unsigned int    match_props) const
586 587
  {
    /* If using mark filtering sets, the high short of
B
Behdad Esfahbod 已提交
588
     * match_props has the set index.
589
     */
B
Behdad Esfahbod 已提交
590 591
    if (match_props & LookupFlag::UseMarkFilteringSet)
      return gdef.mark_set_covers (match_props >> 16, glyph);
592

B
Behdad Esfahbod 已提交
593
    /* The second byte of match_props has the meaning
594 595 596
     * "ignore marks of attachment type different than
     * the attachment type specified."
     */
B
Behdad Esfahbod 已提交
597 598
    if (match_props & LookupFlag::MarkAttachmentType)
      return (match_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);
599 600 601 602 603

    return true;
  }

  inline bool
B
Behdad Esfahbod 已提交
604
  check_glyph_property (const hb_glyph_info_t *info,
B
Behdad Esfahbod 已提交
605
			unsigned int  match_props) const
606
  {
B
Behdad Esfahbod 已提交
607 608 609
    hb_codepoint_t glyph = info->codepoint;
    unsigned int glyph_props = _hb_glyph_info_get_glyph_props (info);

610
    /* Not covered, if, for example, glyph class is ligature and
B
Behdad Esfahbod 已提交
611
     * match_props includes LookupFlags::IgnoreLigatures
612
     */
B
Behdad Esfahbod 已提交
613
    if (glyph_props & match_props & LookupFlag::IgnoreFlags)
614 615
      return false;

616
    if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK))
B
Behdad Esfahbod 已提交
617
      return match_properties_mark (glyph, glyph_props, match_props);
618 619 620 621

    return true;
  }

622
  inline void _set_glyph_props (hb_codepoint_t glyph_index,
623
			  unsigned int class_guess = 0,
624 625
			  bool ligature = false,
			  bool component = false) const
626
  {
627 628 629 630
    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)
631
    {
632
      add_in |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED;
633 634 635 636 637 638 639 640 641 642
      /* In the only place that the MULTIPLIED bit is used, Uniscribe
       * seems to only care about the "last" transformation between
       * Ligature and Multiple substitions.  Ie. if you ligate, expand,
       * 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;
643
    if (likely (has_glyph_classes))
644
      _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | gdef.get_glyph_props (glyph_index));
645
    else if (class_guess)
646
      _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | class_guess);
647
  }
B
Behdad Esfahbod 已提交
648

649
  inline void replace_glyph (hb_codepoint_t glyph_index) const
650
  {
651 652
    _set_glyph_props (glyph_index);
    buffer->replace_glyph (glyph_index);
653
  }
654
  inline void replace_glyph_inplace (hb_codepoint_t glyph_index) const
655
  {
656 657 658 659 660 661
    _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
  {
662
    _set_glyph_props (glyph_index, class_guess, true);
663 664
    buffer->replace_glyph (glyph_index);
  }
665 666
  inline void output_glyph_for_component (hb_codepoint_t glyph_index,
					  unsigned int class_guess) const
B
Behdad Esfahbod 已提交
667
  {
668
    _set_glyph_props (glyph_index, class_guess, false, true);
669
    buffer->output_glyph (glyph_index);
B
Behdad Esfahbod 已提交
670
  }
671 672
};

673

B
Behdad Esfahbod 已提交
674

675
typedef bool (*intersects_func_t) (const hb_set_t *glyphs, const HBUINT16 &value, const void *data);
B
Behdad Esfahbod 已提交
676 677
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);
678

679 680 681 682
struct ContextClosureFuncs
{
  intersects_func_t intersects;
};
683 684 685 686
struct ContextCollectGlyphsFuncs
{
  collect_glyphs_func_t collect;
};
687
struct ContextApplyFuncs
B
Behdad Esfahbod 已提交
688
{
689
  match_func_t match;
690 691
};

692

693
static inline bool intersects_glyph (const hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
694 695 696
{
  return glyphs->has (value);
}
697
static inline bool intersects_class (const hb_set_t *glyphs, const HBUINT16 &value, const void *data)
698 699 700 701
{
  const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
  return class_def.intersects_class (glyphs, value);
}
702
static inline bool intersects_coverage (const hb_set_t *glyphs, const HBUINT16 &value, const void *data)
703 704 705 706 707
{
  const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
  return (data+coverage).intersects (glyphs);
}

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

720

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


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

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

  for (unsigned int i = 1; i < count; i++)
772
    if (likely (!match_func (c->glyphs[i], input[i - 1], match_data)))
773 774 775 776
      return false;

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

788
  if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return_trace (false);
789

B
Behdad Esfahbod 已提交
790 791
  hb_buffer_t *buffer = c->buffer;

792
  hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
793
  skippy_iter.reset (buffer->idx, count - 1);
794
  skippy_iter.set_match_func (match_func, match_data, input);
795

796 797 798 799 800 801 802 803 804 805 806
  /*
   * 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.
807 808 809 810 811 812 813 814 815 816
   *   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.
817
   *     https://github.com/harfbuzz/harfbuzz/issues/545
818 819
   */

820
  unsigned int total_component_count = 0;
B
Behdad Esfahbod 已提交
821
  total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur());
822

B
Behdad Esfahbod 已提交
823 824
  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 已提交
825

826 827 828 829 830 831
  enum {
    LIGBASE_NOT_CHECKED,
    LIGBASE_MAY_NOT_SKIP,
    LIGBASE_MAY_SKIP
  } ligbase = LIGBASE_NOT_CHECKED;

B
Behdad Esfahbod 已提交
832
  match_positions[0] = buffer->idx;
B
Minor  
Behdad Esfahbod 已提交
833
  for (unsigned int i = 1; i < count; i++)
B
Behdad Esfahbod 已提交
834
  {
B
Behdad Esfahbod 已提交
835
    if (!skippy_iter.next ()) return_trace (false);
B
Behdad Esfahbod 已提交
836 837

    match_positions[i] = skippy_iter.idx;
838

B
Behdad Esfahbod 已提交
839 840
    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]);
841

842 843
    if (first_lig_id && first_lig_comp)
    {
844 845
      /* If first component was attached to a previous ligature component,
       * all subsequent components should be attached to the same ligature
846
       * component, otherwise we shouldn't ligate them... */
847
      if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
848 849 850
      {
        /* ...unless, we are attached to a base ligature and that base
	 * ligature is ignorable. */
851
        if (ligbase == LIGBASE_NOT_CHECKED)
852
	{
853 854 855 856
	  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)
857
	  {
858 859 860 861 862 863
	    if (_hb_glyph_info_get_lig_comp (&out[j - 1]) == 0)
	    {
	      j--;
	      found = true;
	      break;
	    }
864 865 866
	    j--;
	  }

B
Behdad Esfahbod 已提交
867
	  if (found && skippy_iter.may_skip (out[j]) == hb_ot_apply_context_t::matcher_t::SKIP_YES)
868 869 870 871
	    ligbase = LIGBASE_MAY_SKIP;
	  else
	    ligbase = LIGBASE_MAY_NOT_SKIP;
	}
872

873
        if (ligbase == LIGBASE_MAY_NOT_SKIP)
874 875 876 877
	  return_trace (false);
      }
    }
    else
878
    {
879 880 881 882
      /* 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 已提交
883
	return_trace (false);
884 885
    }

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

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

891 892 893
  if (p_total_component_count)
    *p_total_component_count = total_component_count;

B
Behdad Esfahbod 已提交
894
  return_trace (true);
B
Behdad Esfahbod 已提交
895
}
896
static inline bool ligate_input (hb_ot_apply_context_t *c,
897
				 unsigned int count, /* Including the first glyph */
898
				 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
899
				 unsigned int match_length,
900 901 902
				 hb_codepoint_t lig_glyph,
				 unsigned int total_component_count)
{
B
Behdad Esfahbod 已提交
903
  TRACE_APPLY (nullptr);
904

B
Behdad Esfahbod 已提交
905 906 907
  hb_buffer_t *buffer = c->buffer;

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

909 910 911 912 913
  /* - 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 已提交
914
   *   If it *is* a mark ligature, we don't allocate a new ligature id, and leave
915 916
   *   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 已提交
917
   *   and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA with a
918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940
   *   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
   */

941 942 943
  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 已提交
944 945
    if (!_hb_glyph_info_is_mark (&buffer->info[match_positions[i]]))
    {
946
      is_base_ligature = false;
B
Behdad Esfahbod 已提交
947 948 949
      is_mark_ligature = false;
      break;
    }
950
  bool is_ligature = !is_base_ligature && !is_mark_ligature;
B
Behdad Esfahbod 已提交
951

952 953
  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 已提交
954 955
  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());
956 957
  unsigned int components_so_far = last_num_components;

958
  if (is_ligature)
959
  {
B
Behdad Esfahbod 已提交
960
    _hb_glyph_info_set_lig_props_for_ligature (&buffer->cur(), lig_id, total_component_count);
B
Behdad Esfahbod 已提交
961
    if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
962
    {
B
Minor  
Behdad Esfahbod 已提交
963
      _hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER);
964
    }
965
  }
966
  c->replace_glyph_with_ligature (lig_glyph, klass);
967 968 969

  for (unsigned int i = 1; i < count; i++)
  {
B
Behdad Esfahbod 已提交
970
    while (buffer->idx < match_positions[i] && buffer->successful)
971
    {
972 973
      if (is_ligature)
      {
974 975
        unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
	if (this_comp == 0)
976
	  this_comp = last_num_components;
977
	unsigned int new_lig_comp = components_so_far - last_num_components +
978 979
				    MIN (this_comp, last_num_components);
	  _hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
980
      }
B
Behdad Esfahbod 已提交
981
      buffer->next_glyph ();
982 983
    }

B
Behdad Esfahbod 已提交
984 985
    last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
    last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
986 987 988
    components_so_far += last_num_components;

    /* Skip the base glyph */
B
Behdad Esfahbod 已提交
989
    buffer->idx++;
990 991 992 993
  }

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

1009
static inline bool match_backtrack (hb_ot_apply_context_t *c,
1010
				    unsigned int count,
B
Behdad Esfahbod 已提交
1011
				    const HBUINT16 backtrack[],
1012
				    match_func_t match_func,
1013 1014
				    const void *match_data,
				    unsigned int *match_start)
1015
{
B
Behdad Esfahbod 已提交
1016
  TRACE_APPLY (nullptr);
1017

1018
  hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
1019
  skippy_iter.reset (c->buffer->backtrack_len (), count);
1020
  skippy_iter.set_match_func (match_func, match_data, backtrack);
1021

1022
  for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
1023
    if (!skippy_iter.prev ())
B
Behdad Esfahbod 已提交
1024
      return_trace (false);
1025

1026 1027
  *match_start = skippy_iter.idx;

B
Behdad Esfahbod 已提交
1028
  return_trace (true);
1029 1030
}

1031
static inline bool match_lookahead (hb_ot_apply_context_t *c,
B
Behdad Esfahbod 已提交
1032
				    unsigned int count,
B
Behdad Esfahbod 已提交
1033
				    const HBUINT16 lookahead[],
B
Behdad Esfahbod 已提交
1034
				    match_func_t match_func,
B
Behdad Esfahbod 已提交
1035
				    const void *match_data,
1036 1037
				    unsigned int offset,
				    unsigned int *end_index)
1038
{
B
Behdad Esfahbod 已提交
1039
  TRACE_APPLY (nullptr);
1040

1041
  hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
1042
  skippy_iter.reset (c->buffer->idx + offset - 1, count);
1043
  skippy_iter.set_match_func (match_func, match_data, lookahead);
1044

B
Minor  
Behdad Esfahbod 已提交
1045
  for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
1046
    if (!skippy_iter.next ())
B
Behdad Esfahbod 已提交
1047
      return_trace (false);
1048

1049 1050
  *end_index = skippy_iter.idx + 1;

B
Behdad Esfahbod 已提交
1051
  return_trace (true);
1052 1053
}

B
Behdad Esfahbod 已提交
1054

1055

B
Behdad Esfahbod 已提交
1056 1057
struct LookupRecord
{
B
Behdad Esfahbod 已提交
1058 1059
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1060
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1061
    return_trace (c->check_struct (this));
B
Behdad Esfahbod 已提交
1062 1063
  }

B
Behdad Esfahbod 已提交
1064
  HBUINT16	sequenceIndex;		/* Index into current glyph
1065
					 * sequence--first glyph = 0 */
B
Behdad Esfahbod 已提交
1066
  HBUINT16	lookupListIndex;	/* Lookup to apply to that
1067
					 * position--zero--based */
B
Behdad Esfahbod 已提交
1068 1069
  public:
  DEFINE_SIZE_STATIC (4);
1070 1071
};

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

1081
static inline bool apply_lookup (hb_ot_apply_context_t *c,
1082
				 unsigned int count, /* Including the first glyph */
1083
				 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
1084
				 unsigned int lookupCount,
1085 1086
				 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
				 unsigned int match_length)
1087
{
B
Behdad Esfahbod 已提交
1088
  TRACE_APPLY (nullptr);
1089

1090
  hb_buffer_t *buffer = c->buffer;
1091
  int end;
B
Behdad Esfahbod 已提交
1092

1093 1094 1095 1096 1097
  /* All positions are distance from beginning of *output* buffer.
   * Adjust. */
  {
    unsigned int bl = buffer->backtrack_len ();
    end = bl + match_length;
1098

1099 1100 1101 1102 1103
    int delta = bl - buffer->idx;
    /* Convert positions to new indexing. */
    for (unsigned int j = 0; j < count; j++)
      match_positions[j] += delta;
  }
1104

B
Behdad Esfahbod 已提交
1105
  for (unsigned int i = 0; i < lookupCount && buffer->successful; i++)
B
Behdad Esfahbod 已提交
1106
  {
1107 1108 1109
    unsigned int idx = lookupRecord[i].sequenceIndex;
    if (idx >= count)
      continue;
1110

1111 1112 1113 1114 1115
    /* 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;

1116 1117
    if (unlikely (!buffer->move_to (match_positions[idx])))
      break;
1118

1119 1120 1121
    if (unlikely (buffer->max_ops <= 0))
      break;

1122 1123 1124
    unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
    if (!c->recurse (lookupRecord[i].lookupListIndex))
      continue;
1125

1126 1127
    unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len ();
    int delta = new_len - orig_len;
1128

1129 1130
    if (!delta)
        continue;
1131

B
Behdad Esfahbod 已提交
1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154
    /* 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.
     */
1155

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

1168 1169 1170 1171
    unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */

    if (delta > 0)
    {
1172
      if (unlikely (delta + count > HB_MAX_CONTEXT_LENGTH))
1173
	break;
1174 1175 1176
    }
    else
    {
1177
      /* NOTE: delta is negative. */
1178 1179
      delta = MAX (delta, (int) next - (int) count);
      next -= delta;
1180
    }
1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194

    /* 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;
1195 1196
  }

1197 1198
  buffer->move_to (end);

B
Behdad Esfahbod 已提交
1199
  return_trace (true);
1200
}
1201

B
Behdad Esfahbod 已提交
1202

1203 1204 1205

/* Contextual lookups */

1206 1207 1208 1209 1210 1211
struct ContextClosureLookupContext
{
  ContextClosureFuncs funcs;
  const void *intersects_data;
};

1212 1213 1214 1215 1216 1217
struct ContextCollectGlyphsLookupContext
{
  ContextCollectGlyphsFuncs funcs;
  const void *collect_data;
};

1218
struct ContextApplyLookupContext
B
Behdad Esfahbod 已提交
1219
{
1220
  ContextApplyFuncs funcs;
B
Behdad Esfahbod 已提交
1221
  const void *match_data;
1222 1223
};

1224 1225 1226 1227 1228 1229 1230 1231 1232 1233
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 已提交
1234
static inline void context_closure_lookup (hb_closure_context_t *c,
1235
					   unsigned int inputCount, /* Including the first glyph (not matched) */
B
Behdad Esfahbod 已提交
1236
					   const HBUINT16 input[], /* Array of input values--start with second glyph */
1237 1238 1239 1240
					   unsigned int lookupCount,
					   const LookupRecord lookupRecord[],
					   ContextClosureLookupContext &lookup_context)
{
1241 1242 1243
  if (context_intersects (c->glyphs,
			  inputCount, input,
			  lookup_context))
1244 1245
    recurse_lookups (c,
		     lookupCount, lookupRecord);
1246 1247
}

1248 1249
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 已提交
1250
						  const HBUINT16 input[], /* Array of input values--start with second glyph */
1251 1252 1253 1254
						  unsigned int lookupCount,
						  const LookupRecord lookupRecord[],
						  ContextCollectGlyphsLookupContext &lookup_context)
{
B
Minor  
Behdad Esfahbod 已提交
1255
  collect_array (c, c->input,
1256 1257 1258 1259 1260
		 inputCount ? inputCount - 1 : 0, input,
		 lookup_context.funcs.collect, lookup_context.collect_data);
  recurse_lookups (c,
		   lookupCount, lookupRecord);
}
1261

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

B
Behdad Esfahbod 已提交
1293 1294
struct Rule
{
1295 1296 1297
  inline bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const
  {
    return context_intersects (glyphs,
1298
			       inputCount, inputZ.arrayZ,
1299 1300 1301
			       lookup_context);
  }

B
Behdad Esfahbod 已提交
1302
  inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
1303
  {
B
Behdad Esfahbod 已提交
1304
    TRACE_CLOSURE (this);
1305
    const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAtOffset<UnsizedArrayOf<LookupRecord> > (inputZ.arrayZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
B
Behdad Esfahbod 已提交
1306
    context_closure_lookup (c,
1307 1308
			    inputCount, inputZ.arrayZ,
			    lookupCount, lookupRecord.arrayZ,
B
Behdad Esfahbod 已提交
1309
			    lookup_context);
1310 1311
  }

1312 1313 1314
  inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const
  {
    TRACE_COLLECT_GLYPHS (this);
1315
    const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAtOffset<UnsizedArrayOf<LookupRecord> > (inputZ.arrayZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
1316
    context_collect_glyphs_lookup (c,
1317 1318
				   inputCount, inputZ.arrayZ,
				   lookupCount, lookupRecord.arrayZ,
1319 1320 1321
				   lookup_context);
  }

1322 1323
  inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
  {
B
Behdad Esfahbod 已提交
1324
    TRACE_WOULD_APPLY (this);
1325 1326
    const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAtOffset<UnsizedArrayOf<LookupRecord> > (inputZ.arrayZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
    return_trace (context_would_apply_lookup (c, inputCount, inputZ.arrayZ, lookupCount, lookupRecord.arrayZ, lookup_context));
1327 1328
  }

1329
  inline bool apply (hb_ot_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
B
Behdad Esfahbod 已提交
1330
  {
B
Behdad Esfahbod 已提交
1331
    TRACE_APPLY (this);
1332 1333
    const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAtOffset<UnsizedArrayOf<LookupRecord> > (inputZ.arrayZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
    return_trace (context_apply_lookup (c, inputCount, inputZ.arrayZ, lookupCount, lookupRecord.arrayZ, lookup_context));
1334 1335
  }

B
Behdad Esfahbod 已提交
1336
  public:
B
Behdad Esfahbod 已提交
1337 1338
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1339
    TRACE_SANITIZE (this);
1340 1341
    return_trace (inputCount.sanitize (c) &&
		  lookupCount.sanitize (c) &&
1342
		  c->check_range (inputZ.arrayZ,
B
Behdad Esfahbod 已提交
1343
				  inputZ[0].static_size * (inputCount ? inputCount - 1 : 0) +
1344
				  LookupRecord::static_size * lookupCount));
B
Behdad Esfahbod 已提交
1345 1346
  }

1347
  protected:
B
Behdad Esfahbod 已提交
1348
  HBUINT16	inputCount;		/* Total number of glyphs in input
1349
					 * glyph sequence--includes the first
1350
					 * glyph */
B
Behdad Esfahbod 已提交
1351
  HBUINT16	lookupCount;		/* Number of LookupRecords */
1352 1353
  UnsizedArrayOf<HBUINT16>
 		inputZ;			/* Array of match inputs--start with
1354
					 * second glyph */
1355 1356
/*UnsizedArrayOf<LookupRecord>
		lookupRecordX;*/	/* Array of LookupRecords--in
1357
					 * design order */
B
Behdad Esfahbod 已提交
1358
  public:
1359
  DEFINE_SIZE_ARRAY (4, inputZ);
1360 1361
};

B
Behdad Esfahbod 已提交
1362 1363
struct RuleSet
{
1364 1365 1366 1367 1368 1369 1370 1371 1372
  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))
        return true;
    return false;
  }

B
Behdad Esfahbod 已提交
1373
  inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
1374
  {
B
Behdad Esfahbod 已提交
1375
    TRACE_CLOSURE (this);
1376 1377
    unsigned int num_rules = rule.len;
    for (unsigned int i = 0; i < num_rules; i++)
B
Behdad Esfahbod 已提交
1378
      (this+rule[i]).closure (c, lookup_context);
1379 1380
  }

1381 1382 1383 1384 1385 1386 1387 1388
  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);
  }

1389 1390
  inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
  {
B
Behdad Esfahbod 已提交
1391
    TRACE_WOULD_APPLY (this);
1392 1393 1394 1395
    unsigned int num_rules = rule.len;
    for (unsigned int i = 0; i < num_rules; i++)
    {
      if ((this+rule[i]).would_apply (c, lookup_context))
B
Behdad Esfahbod 已提交
1396
        return_trace (true);
1397
    }
B
Behdad Esfahbod 已提交
1398
    return_trace (false);
1399 1400
  }

1401
  inline bool apply (hb_ot_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
B
Behdad Esfahbod 已提交
1402
  {
B
Behdad Esfahbod 已提交
1403
    TRACE_APPLY (this);
1404
    unsigned int num_rules = rule.len;
B
Behdad Esfahbod 已提交
1405 1406
    for (unsigned int i = 0; i < num_rules; i++)
    {
B
Behdad Esfahbod 已提交
1407
      if ((this+rule[i]).apply (c, lookup_context))
B
Behdad Esfahbod 已提交
1408
        return_trace (true);
1409
    }
B
Behdad Esfahbod 已提交
1410
    return_trace (false);
1411 1412
  }

B
Behdad Esfahbod 已提交
1413 1414
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1415
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1416
    return_trace (rule.sanitize (c, this));
B
Behdad Esfahbod 已提交
1417 1418
  }

1419
  protected:
1420
  OffsetArrayOf<Rule>
1421
		rule;			/* Array of Rule tables
1422
					 * ordered by preference */
B
Behdad Esfahbod 已提交
1423
  public:
1424
  DEFINE_SIZE_ARRAY (2, rule);
1425 1426 1427
};


B
Behdad Esfahbod 已提交
1428 1429
struct ContextFormat1
{
1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448
  inline bool intersects (const hb_set_t *glyphs) const
  {
    struct ContextClosureLookupContext lookup_context = {
      {intersects_glyph},
      nullptr
    };

    unsigned int count = ruleSet.len;
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
    {
      if (unlikely (iter.get_coverage () >= count))
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
      if (glyphs->has (iter.get_glyph ()) &&
	  (this+ruleSet[iter.get_coverage ()]).intersects (glyphs, lookup_context))
        return true;
    }
    return false;
  }

1449
  inline void closure (hb_closure_context_t *c) const
1450
  {
B
Behdad Esfahbod 已提交
1451
    TRACE_CLOSURE (this);
1452 1453

    struct ContextClosureLookupContext lookup_context = {
1454
      {intersects_glyph},
B
Behdad Esfahbod 已提交
1455
      nullptr
1456 1457 1458
    };

    unsigned int count = ruleSet.len;
1459 1460 1461 1462 1463 1464 1465
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
    {
      if (unlikely (iter.get_coverage () >= count))
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
      if (c->glyphs->has (iter.get_glyph ()))
	(this+ruleSet[iter.get_coverage ()]).closure (c, lookup_context);
    }
1466 1467
  }

B
Behdad Esfahbod 已提交
1468 1469
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
1470
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
1471
    (this+coverage).add_coverage (c->input);
1472 1473 1474

    struct ContextCollectGlyphsLookupContext lookup_context = {
      {collect_glyph},
B
Behdad Esfahbod 已提交
1475
      nullptr
1476 1477 1478 1479
    };

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

1483 1484
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1485
    TRACE_WOULD_APPLY (this);
1486

1487
    const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
1488
    struct ContextApplyLookupContext lookup_context = {
1489
      {match_glyph},
B
Behdad Esfahbod 已提交
1490
      nullptr
1491
    };
B
Behdad Esfahbod 已提交
1492
    return_trace (rule_set.would_apply (c, lookup_context));
1493 1494
  }

1495
  inline const Coverage &get_coverage (void) const
1496
  { return this+coverage; }
1497

1498
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1499
  {
B
Behdad Esfahbod 已提交
1500
    TRACE_APPLY (this);
1501
    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
1502
    if (likely (index == NOT_COVERED))
B
Behdad Esfahbod 已提交
1503
      return_trace (false);
1504

1505
    const RuleSet &rule_set = this+ruleSet[index];
1506
    struct ContextApplyLookupContext lookup_context = {
1507
      {match_glyph},
B
Behdad Esfahbod 已提交
1508
      nullptr
1509
    };
B
Behdad Esfahbod 已提交
1510
    return_trace (rule_set.apply (c, lookup_context));
1511 1512
  }

1513 1514 1515 1516 1517 1518 1519
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

B
Behdad Esfahbod 已提交
1520 1521
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1522
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1523
    return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
1524 1525
  }

1526
  protected:
B
Behdad Esfahbod 已提交
1527
  HBUINT16	format;			/* Format identifier--format = 1 */
1528 1529 1530 1531 1532 1533
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of table */
  OffsetArrayOf<RuleSet>
		ruleSet;		/* Array of RuleSet tables
					 * ordered by Coverage Index */
1534
  public:
1535
  DEFINE_SIZE_ARRAY (6, ruleSet);
1536 1537 1538
};


B
Behdad Esfahbod 已提交
1539 1540
struct ContextFormat2
{
1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561
  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))
        return true;

    return false;
  }

1562
  inline void closure (hb_closure_context_t *c) const
1563
  {
B
Behdad Esfahbod 已提交
1564
    TRACE_CLOSURE (this);
1565
    if (!(this+coverage).intersects (c->glyphs))
B
Behdad Esfahbod 已提交
1566
      return;
1567 1568 1569 1570

    const ClassDef &class_def = this+classDef;

    struct ContextClosureLookupContext lookup_context = {
1571
      {intersects_class},
1572
      &class_def
1573 1574 1575 1576 1577 1578
    };

    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 已提交
1579
	rule_set.closure (c, lookup_context);
1580
      }
1581 1582
  }

B
Behdad Esfahbod 已提交
1583 1584
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
1585
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
1586
    (this+coverage).add_coverage (c->input);
1587

1588
    const ClassDef &class_def = this+classDef;
1589 1590
    struct ContextCollectGlyphsLookupContext lookup_context = {
      {collect_class},
1591
      &class_def
1592 1593 1594 1595
    };

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

1599 1600
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1601
    TRACE_WOULD_APPLY (this);
1602 1603

    const ClassDef &class_def = this+classDef;
1604
    unsigned int index = class_def.get_class (c->glyphs[0]);
1605 1606
    const RuleSet &rule_set = this+ruleSet[index];
    struct ContextApplyLookupContext lookup_context = {
1607
      {match_class},
1608 1609
      &class_def
    };
B
Behdad Esfahbod 已提交
1610
    return_trace (rule_set.would_apply (c, lookup_context));
1611 1612
  }

1613
  inline const Coverage &get_coverage (void) const
1614
  { return this+coverage; }
1615

1616
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1617
  {
B
Behdad Esfahbod 已提交
1618
    TRACE_APPLY (this);
1619
    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
B
Behdad Esfahbod 已提交
1620
    if (likely (index == NOT_COVERED)) return_trace (false);
1621 1622

    const ClassDef &class_def = this+classDef;
1623
    index = class_def.get_class (c->buffer->cur().codepoint);
1624
    const RuleSet &rule_set = this+ruleSet[index];
1625
    struct ContextApplyLookupContext lookup_context = {
1626
      {match_class},
B
Behdad Esfahbod 已提交
1627
      &class_def
1628
    };
B
Behdad Esfahbod 已提交
1629
    return_trace (rule_set.apply (c, lookup_context));
1630 1631
  }

1632 1633 1634 1635 1636 1637 1638
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

B
Behdad Esfahbod 已提交
1639 1640
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1641
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1642
    return_trace (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
1643 1644
  }

1645
  protected:
B
Behdad Esfahbod 已提交
1646
  HBUINT16	format;			/* Format identifier--format = 2 */
1647 1648 1649 1650 1651 1652 1653 1654 1655
  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 */
1656
  public:
1657
  DEFINE_SIZE_ARRAY (8, ruleSet);
1658 1659 1660
};


B
Behdad Esfahbod 已提交
1661 1662
struct ContextFormat3
{
1663 1664 1665 1666 1667 1668 1669 1670 1671 1672
  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,
1673
			       glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
1674 1675 1676
			       lookup_context);
  }

1677
  inline void closure (hb_closure_context_t *c) const
1678
  {
B
Behdad Esfahbod 已提交
1679
    TRACE_CLOSURE (this);
1680
    if (!(this+coverageZ[0]).intersects (c->glyphs))
B
Behdad Esfahbod 已提交
1681
      return;
1682

1683
    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ.arrayZ, coverageZ[0].static_size * glyphCount);
1684
    struct ContextClosureLookupContext lookup_context = {
1685
      {intersects_coverage},
1686 1687
      this
    };
B
Behdad Esfahbod 已提交
1688
    context_closure_lookup (c,
1689
			    glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
B
Behdad Esfahbod 已提交
1690 1691
			    lookupCount, lookupRecord,
			    lookup_context);
1692 1693
  }

B
Behdad Esfahbod 已提交
1694 1695
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
1696
    TRACE_COLLECT_GLYPHS (this);
1697
    (this+coverageZ[0]).add_coverage (c->input);
1698

1699
    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ.arrayZ, coverageZ[0].static_size * glyphCount);
1700 1701
    struct ContextCollectGlyphsLookupContext lookup_context = {
      {collect_coverage},
1702
      this
1703 1704 1705
    };

    context_collect_glyphs_lookup (c,
1706
				   glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
1707 1708
				   lookupCount, lookupRecord,
				   lookup_context);
B
Behdad Esfahbod 已提交
1709 1710
  }

1711 1712
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1713
    TRACE_WOULD_APPLY (this);
1714

1715
    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ.arrayZ, coverageZ[0].static_size * glyphCount);
1716
    struct ContextApplyLookupContext lookup_context = {
1717
      {match_coverage},
1718 1719
      this
    };
1720
    return_trace (context_would_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, lookup_context));
1721 1722
  }

1723
  inline const Coverage &get_coverage (void) const
1724
  { return this+coverageZ[0]; }
1725

1726
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1727
  {
B
Behdad Esfahbod 已提交
1728
    TRACE_APPLY (this);
1729
    unsigned int index = (this+coverageZ[0]).get_coverage (c->buffer->cur().codepoint);
B
Behdad Esfahbod 已提交
1730
    if (likely (index == NOT_COVERED)) return_trace (false);
1731

1732
    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ.arrayZ, coverageZ[0].static_size * glyphCount);
1733
    struct ContextApplyLookupContext lookup_context = {
1734
      {match_coverage},
B
Behdad Esfahbod 已提交
1735
      this
1736
    };
1737
    return_trace (context_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, lookup_context));
1738 1739
  }

1740 1741 1742 1743 1744 1745 1746
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

B
Behdad Esfahbod 已提交
1747 1748
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1749
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1750
    if (!c->check_struct (this)) return_trace (false);
B
Behdad Esfahbod 已提交
1751
    unsigned int count = glyphCount;
B
Behdad Esfahbod 已提交
1752
    if (!count) return_trace (false); /* We want to access coverageZ[0] freely. */
1753
    if (!c->check_array (coverageZ.arrayZ, count)) return_trace (false);
B
Behdad Esfahbod 已提交
1754
    for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
1755
      if (!coverageZ[i].sanitize (c, this)) return_trace (false);
1756
    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ.arrayZ, coverageZ[0].static_size * count);
1757
    return_trace (c->check_array (lookupRecord, lookupCount));
B
Behdad Esfahbod 已提交
1758 1759
  }

1760
  protected:
B
Behdad Esfahbod 已提交
1761 1762
  HBUINT16	format;			/* Format identifier--format = 3 */
  HBUINT16	glyphCount;		/* Number of glyphs in the input glyph
1763
					 * sequence */
B
Behdad Esfahbod 已提交
1764
  HBUINT16	lookupCount;		/* Number of LookupRecords */
1765 1766
  UnsizedArrayOf<OffsetTo<Coverage> >
		coverageZ;		/* Array of offsets to Coverage
1767
					 * table in glyph sequence order */
1768 1769
/*UnsizedArrayOf<LookupRecord>
		lookupRecordX;*/	/* Array of LookupRecords--in
1770
					 * design order */
B
Behdad Esfahbod 已提交
1771
  public:
1772
  DEFINE_SIZE_ARRAY (6, coverageZ);
1773 1774
};

B
Behdad Esfahbod 已提交
1775 1776
struct Context
{
1777
  template <typename context_t>
1778
  inline typename context_t::return_t dispatch (context_t *c) const
1779
  {
1780
    TRACE_DISPATCH (this, u.format);
1781
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1782
    switch (u.format) {
B
Behdad Esfahbod 已提交
1783 1784 1785 1786
    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 ());
1787 1788 1789
    }
  }

1790
  protected:
1791
  union {
B
Behdad Esfahbod 已提交
1792
  HBUINT16		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1793 1794 1795
  ContextFormat1	format1;
  ContextFormat2	format2;
  ContextFormat3	format3;
1796 1797 1798
  } u;
};

1799 1800 1801

/* Chaining Contextual lookups */

1802
struct ChainContextClosureLookupContext
B
Behdad Esfahbod 已提交
1803
{
1804 1805 1806 1807
  ContextClosureFuncs funcs;
  const void *intersects_data[3];
};

1808 1809 1810 1811 1812 1813
struct ChainContextCollectGlyphsLookupContext
{
  ContextCollectGlyphsFuncs funcs;
  const void *collect_data[3];
};

1814 1815 1816
struct ChainContextApplyLookupContext
{
  ContextApplyFuncs funcs;
B
Behdad Esfahbod 已提交
1817
  const void *match_data[3];
1818 1819
};

1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839
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 已提交
1840
static inline void chain_context_closure_lookup (hb_closure_context_t *c,
1841
						 unsigned int backtrackCount,
B
Behdad Esfahbod 已提交
1842
						 const HBUINT16 backtrack[],
1843
						 unsigned int inputCount, /* Including the first glyph (not matched) */
B
Behdad Esfahbod 已提交
1844
						 const HBUINT16 input[], /* Array of input values--start with second glyph */
1845
						 unsigned int lookaheadCount,
B
Behdad Esfahbod 已提交
1846
						 const HBUINT16 lookahead[],
1847 1848 1849 1850
						 unsigned int lookupCount,
						 const LookupRecord lookupRecord[],
						 ChainContextClosureLookupContext &lookup_context)
{
1851 1852 1853 1854 1855
  if (chain_context_intersects (c->glyphs,
				backtrackCount, backtrack,
				inputCount, input,
				lookaheadCount, lookahead,
				lookup_context))
1856 1857
    recurse_lookups (c,
		     lookupCount, lookupRecord);
1858 1859
}

1860 1861
static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
						        unsigned int backtrackCount,
B
Behdad Esfahbod 已提交
1862
						        const HBUINT16 backtrack[],
1863
						        unsigned int inputCount, /* Including the first glyph (not matched) */
B
Behdad Esfahbod 已提交
1864
						        const HBUINT16 input[], /* Array of input values--start with second glyph */
1865
						        unsigned int lookaheadCount,
B
Behdad Esfahbod 已提交
1866
						        const HBUINT16 lookahead[],
1867 1868 1869 1870
						        unsigned int lookupCount,
						        const LookupRecord lookupRecord[],
						        ChainContextCollectGlyphsLookupContext &lookup_context)
{
B
Minor  
Behdad Esfahbod 已提交
1871
  collect_array (c, c->before,
1872 1873
		 backtrackCount, backtrack,
		 lookup_context.funcs.collect, lookup_context.collect_data[0]);
B
Minor  
Behdad Esfahbod 已提交
1874
  collect_array (c, c->input,
1875 1876
		 inputCount ? inputCount - 1 : 0, input,
		 lookup_context.funcs.collect, lookup_context.collect_data[1]);
B
Minor  
Behdad Esfahbod 已提交
1877
  collect_array (c, c->after,
1878 1879 1880 1881 1882 1883
		 lookaheadCount, lookahead,
		 lookup_context.funcs.collect, lookup_context.collect_data[2]);
  recurse_lookups (c,
		   lookupCount, lookupRecord);
}

1884 1885
static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c,
						     unsigned int backtrackCount,
B
Behdad Esfahbod 已提交
1886
						     const HBUINT16 backtrack[] HB_UNUSED,
1887
						     unsigned int inputCount, /* Including the first glyph (not matched) */
B
Behdad Esfahbod 已提交
1888
						     const HBUINT16 input[], /* Array of input values--start with second glyph */
1889
						     unsigned int lookaheadCount,
B
Behdad Esfahbod 已提交
1890
						     const HBUINT16 lookahead[] HB_UNUSED,
B
Behdad Esfahbod 已提交
1891 1892
						     unsigned int lookupCount HB_UNUSED,
						     const LookupRecord lookupRecord[] HB_UNUSED,
1893 1894
						     ChainContextApplyLookupContext &lookup_context)
{
1895
  return (c->zero_context ? !backtrackCount && !lookaheadCount : true)
1896
      && would_match_input (c,
1897 1898 1899 1900
			    inputCount, input,
			    lookup_context.funcs.match, lookup_context.match_data[1]);
}

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

B
Behdad Esfahbod 已提交
1933 1934
struct ChainRule
{
1935 1936 1937 1938 1939 1940
  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,
1941
				     input.lenP1, input.arrayZ,
1942 1943 1944 1945
				     lookahead.len, lookahead.arrayZ,
				     lookup_context);
  }

B
Behdad Esfahbod 已提交
1946
  inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
1947
  {
B
Behdad Esfahbod 已提交
1948
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
1949 1950
    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
1951
    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
B
Behdad Esfahbod 已提交
1952
    chain_context_closure_lookup (c,
1953
				  backtrack.len, backtrack.arrayZ,
1954
				  input.lenP1, input.arrayZ,
1955 1956
				  lookahead.len, lookahead.arrayZ,
				  lookup.len, lookup.arrayZ,
B
Behdad Esfahbod 已提交
1957
				  lookup_context);
1958 1959
  }

1960 1961 1962
  inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
  {
    TRACE_COLLECT_GLYPHS (this);
B
Behdad Esfahbod 已提交
1963 1964
    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
1965 1966
    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
    chain_context_collect_glyphs_lookup (c,
1967
					 backtrack.len, backtrack.arrayZ,
1968
					 input.lenP1, input.arrayZ,
1969 1970
					 lookahead.len, lookahead.arrayZ,
					 lookup.len, lookup.arrayZ,
1971 1972 1973
					 lookup_context);
  }

1974 1975
  inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
  {
B
Behdad Esfahbod 已提交
1976
    TRACE_WOULD_APPLY (this);
B
Behdad Esfahbod 已提交
1977 1978
    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
1979
    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
B
Behdad Esfahbod 已提交
1980
    return_trace (chain_context_would_apply_lookup (c,
1981
						    backtrack.len, backtrack.arrayZ,
1982
						    input.lenP1, input.arrayZ,
1983 1984
						    lookahead.len, lookahead.arrayZ, lookup.len,
						    lookup.arrayZ, lookup_context));
1985 1986
  }

1987
  inline bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
B
Behdad Esfahbod 已提交
1988
  {
B
Behdad Esfahbod 已提交
1989
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
1990 1991
    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
1992
    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
B
Behdad Esfahbod 已提交
1993
    return_trace (chain_context_apply_lookup (c,
1994
					      backtrack.len, backtrack.arrayZ,
1995
					      input.lenP1, input.arrayZ,
1996 1997
					      lookahead.len, lookahead.arrayZ, lookup.len,
					      lookup.arrayZ, lookup_context));
1998 1999
  }

B
Behdad Esfahbod 已提交
2000 2001
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
2002
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
2003
    if (!backtrack.sanitize (c)) return_trace (false);
B
Behdad Esfahbod 已提交
2004
    const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
B
Behdad Esfahbod 已提交
2005
    if (!input.sanitize (c)) return_trace (false);
B
Behdad Esfahbod 已提交
2006
    const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
B
Behdad Esfahbod 已提交
2007
    if (!lookahead.sanitize (c)) return_trace (false);
B
Behdad Esfahbod 已提交
2008
    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
B
Behdad Esfahbod 已提交
2009
    return_trace (lookup.sanitize (c));
B
Behdad Esfahbod 已提交
2010
  }
2011

2012
  protected:
B
Behdad Esfahbod 已提交
2013
  ArrayOf<HBUINT16>
B
Behdad Esfahbod 已提交
2014
		backtrack;		/* Array of backtracking values
2015 2016
					 * (to be matched before the input
					 * sequence) */
B
Behdad Esfahbod 已提交
2017
  HeadlessArrayOf<HBUINT16>
B
Behdad Esfahbod 已提交
2018
		inputX;			/* Array of input values (start with
2019
					 * second glyph) */
B
Behdad Esfahbod 已提交
2020
  ArrayOf<HBUINT16>
B
Behdad Esfahbod 已提交
2021
		lookaheadX;		/* Array of lookahead values's (to be
2022
					 * matched after the input sequence) */
B
Behdad Esfahbod 已提交
2023
  ArrayOf<LookupRecord>
2024
		lookupX;		/* Array of LookupRecords--in
2025
					 * design order) */
2026
  public:
B
Behdad Esfahbod 已提交
2027
  DEFINE_SIZE_MIN (8);
2028 2029
};

B
Behdad Esfahbod 已提交
2030 2031
struct ChainRuleSet
{
2032 2033 2034 2035 2036 2037 2038 2039
  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))
        return true;
    return false;
  }
B
Behdad Esfahbod 已提交
2040
  inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
2041
  {
B
Behdad Esfahbod 已提交
2042
    TRACE_CLOSURE (this);
2043 2044
    unsigned int num_rules = rule.len;
    for (unsigned int i = 0; i < num_rules; i++)
B
Behdad Esfahbod 已提交
2045
      (this+rule[i]).closure (c, lookup_context);
2046 2047
  }

2048 2049 2050 2051 2052 2053 2054 2055
  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);
  }

2056 2057
  inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
  {
B
Behdad Esfahbod 已提交
2058
    TRACE_WOULD_APPLY (this);
2059 2060 2061
    unsigned int num_rules = rule.len;
    for (unsigned int i = 0; i < num_rules; i++)
      if ((this+rule[i]).would_apply (c, lookup_context))
B
Behdad Esfahbod 已提交
2062
        return_trace (true);
2063

B
Behdad Esfahbod 已提交
2064
    return_trace (false);
2065 2066
  }

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

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

B
Behdad Esfahbod 已提交
2078 2079
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
2080
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
2081
    return_trace (rule.sanitize (c, this));
B
Behdad Esfahbod 已提交
2082 2083
  }

2084
  protected:
2085 2086 2087
  OffsetArrayOf<ChainRule>
		rule;			/* Array of ChainRule tables
					 * ordered by preference */
2088
  public:
2089
  DEFINE_SIZE_ARRAY (2, rule);
2090 2091
};

B
Behdad Esfahbod 已提交
2092 2093
struct ChainContextFormat1
{
2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112
  inline bool intersects (const hb_set_t *glyphs) const
  {
    struct ChainContextClosureLookupContext lookup_context = {
      {intersects_glyph},
      {nullptr, nullptr, nullptr}
    };

    unsigned int count = ruleSet.len;
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
    {
      if (unlikely (iter.get_coverage () >= count))
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
      if (glyphs->has (iter.get_glyph ()) &&
	  (this+ruleSet[iter.get_coverage ()]).intersects (glyphs, lookup_context))
        return true;
    }
    return false;
  }

2113
  inline void closure (hb_closure_context_t *c) const
2114
  {
B
Behdad Esfahbod 已提交
2115
    TRACE_CLOSURE (this);
2116 2117

    struct ChainContextClosureLookupContext lookup_context = {
2118
      {intersects_glyph},
B
Behdad Esfahbod 已提交
2119
      {nullptr, nullptr, nullptr}
2120 2121 2122
    };

    unsigned int count = ruleSet.len;
2123 2124 2125 2126 2127 2128 2129
    for (hb_auto_t<Coverage::Iter> iter (this+coverage); iter.more (); iter.next ())
    {
      if (unlikely (iter.get_coverage () >= count))
        break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
      if (c->glyphs->has (iter.get_glyph ()))
	(this+ruleSet[iter.get_coverage ()]).closure (c, lookup_context);
    }
2130 2131
  }

B
Behdad Esfahbod 已提交
2132 2133
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
2134
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
2135
    (this+coverage).add_coverage (c->input);
2136 2137 2138

    struct ChainContextCollectGlyphsLookupContext lookup_context = {
      {collect_glyph},
B
Behdad Esfahbod 已提交
2139
      {nullptr, nullptr, nullptr}
2140 2141 2142 2143 2144
    };

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

2147 2148
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
2149
    TRACE_WOULD_APPLY (this);
2150

2151
    const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
2152
    struct ChainContextApplyLookupContext lookup_context = {
2153
      {match_glyph},
B
Behdad Esfahbod 已提交
2154
      {nullptr, nullptr, nullptr}
2155
    };
B
Behdad Esfahbod 已提交
2156
    return_trace (rule_set.would_apply (c, lookup_context));
2157 2158
  }

2159
  inline const Coverage &get_coverage (void) const
2160
  { return this+coverage; }
2161

2162
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
2163
  {
B
Behdad Esfahbod 已提交
2164
    TRACE_APPLY (this);
2165
    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
B
Behdad Esfahbod 已提交
2166
    if (likely (index == NOT_COVERED)) return_trace (false);
2167

2168
    const ChainRuleSet &rule_set = this+ruleSet[index];
2169
    struct ChainContextApplyLookupContext lookup_context = {
2170
      {match_glyph},
B
Behdad Esfahbod 已提交
2171
      {nullptr, nullptr, nullptr}
2172
    };
B
Behdad Esfahbod 已提交
2173
    return_trace (rule_set.apply (c, lookup_context));
2174
  }
B
Behdad Esfahbod 已提交
2175

2176 2177 2178 2179 2180 2181 2182
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

B
Behdad Esfahbod 已提交
2183 2184
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
2185
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
2186
    return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
2187 2188
  }

2189
  protected:
B
Behdad Esfahbod 已提交
2190
  HBUINT16	format;			/* Format identifier--format = 1 */
2191 2192
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
2193
					 * beginning of table */
2194 2195 2196
  OffsetArrayOf<ChainRuleSet>
		ruleSet;		/* Array of ChainRuleSet tables
					 * ordered by Coverage Index */
2197
  public:
2198
  DEFINE_SIZE_ARRAY (6, ruleSet);
2199 2200
};

B
Behdad Esfahbod 已提交
2201 2202
struct ChainContextFormat2
{
2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226
  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))
        return true;

    return false;
  }
2227
  inline void closure (hb_closure_context_t *c) const
2228
  {
B
Behdad Esfahbod 已提交
2229
    TRACE_CLOSURE (this);
2230
    if (!(this+coverage).intersects (c->glyphs))
B
Behdad Esfahbod 已提交
2231
      return;
2232 2233 2234 2235 2236 2237

    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 = {
2238
      {intersects_class},
2239 2240 2241 2242 2243 2244 2245 2246 2247
      {&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 已提交
2248
	rule_set.closure (c, lookup_context);
2249
      }
2250 2251
  }

B
Behdad Esfahbod 已提交
2252 2253
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
2254
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
2255
    (this+coverage).add_coverage (c->input);
2256

2257 2258 2259 2260
    const ClassDef &backtrack_class_def = this+backtrackClassDef;
    const ClassDef &input_class_def = this+inputClassDef;
    const ClassDef &lookahead_class_def = this+lookaheadClassDef;

2261 2262
    struct ChainContextCollectGlyphsLookupContext lookup_context = {
      {collect_class},
2263 2264 2265
      {&backtrack_class_def,
       &input_class_def,
       &lookahead_class_def}
2266 2267 2268 2269 2270
    };

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

2273 2274
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
2275
    TRACE_WOULD_APPLY (this);
2276

2277
    const ClassDef &backtrack_class_def = this+backtrackClassDef;
2278
    const ClassDef &input_class_def = this+inputClassDef;
2279
    const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2280

2281
    unsigned int index = input_class_def.get_class (c->glyphs[0]);
2282 2283
    const ChainRuleSet &rule_set = this+ruleSet[index];
    struct ChainContextApplyLookupContext lookup_context = {
2284
      {match_class},
2285 2286 2287
      {&backtrack_class_def,
       &input_class_def,
       &lookahead_class_def}
2288
    };
B
Behdad Esfahbod 已提交
2289
    return_trace (rule_set.would_apply (c, lookup_context));
2290 2291
  }

2292
  inline const Coverage &get_coverage (void) const
2293
  { return this+coverage; }
2294

2295
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
2296
  {
B
Behdad Esfahbod 已提交
2297
    TRACE_APPLY (this);
2298
    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
B
Behdad Esfahbod 已提交
2299
    if (likely (index == NOT_COVERED)) return_trace (false);
2300 2301 2302 2303 2304

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

2305
    index = input_class_def.get_class (c->buffer->cur().codepoint);
2306
    const ChainRuleSet &rule_set = this+ruleSet[index];
2307
    struct ChainContextApplyLookupContext lookup_context = {
2308
      {match_class},
B
Behdad Esfahbod 已提交
2309 2310 2311
      {&backtrack_class_def,
       &input_class_def,
       &lookahead_class_def}
2312
    };
B
Behdad Esfahbod 已提交
2313
    return_trace (rule_set.apply (c, lookup_context));
2314 2315
  }

2316 2317 2318 2319 2320 2321 2322
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

B
Behdad Esfahbod 已提交
2323 2324
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
2325
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
2326 2327 2328 2329 2330
    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 已提交
2331 2332
  }

2333
  protected:
B
Behdad Esfahbod 已提交
2334
  HBUINT16	format;			/* Format identifier--format = 2 */
2335 2336
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
2337
					 * beginning of table */
2338 2339
  OffsetTo<ClassDef>
		backtrackClassDef;	/* Offset to glyph ClassDef table
2340 2341
					 * containing backtrack sequence
					 * data--from beginning of table */
2342 2343
  OffsetTo<ClassDef>
		inputClassDef;		/* Offset to glyph ClassDef
2344 2345
					 * table containing input sequence
					 * data--from beginning of table */
2346 2347
  OffsetTo<ClassDef>
		lookaheadClassDef;	/* Offset to glyph ClassDef table
2348 2349
					 * containing lookahead sequence
					 * data--from beginning of table */
2350 2351 2352
  OffsetArrayOf<ChainRuleSet>
		ruleSet;		/* Array of ChainRuleSet tables
					 * ordered by class */
2353
  public:
2354
  DEFINE_SIZE_ARRAY (12, ruleSet);
2355 2356
};

B
Behdad Esfahbod 已提交
2357 2358
struct ChainContextFormat3
{
2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377
  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);
  }

2378
  inline void closure (hb_closure_context_t *c) const
2379
  {
B
Behdad Esfahbod 已提交
2380
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
2381 2382 2383 2384 2385 2386 2387 2388
    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 = {
2389
      {intersects_coverage},
B
Behdad Esfahbod 已提交
2390 2391 2392
      {this, this, this}
    };
    chain_context_closure_lookup (c,
2393 2394 2395 2396
				  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 已提交
2397
				  lookup_context);
2398 2399
  }

B
Behdad Esfahbod 已提交
2400 2401
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
2402 2403 2404
    TRACE_COLLECT_GLYPHS (this);
    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);

B
Minor  
Behdad Esfahbod 已提交
2405
    (this+input[0]).add_coverage (c->input);
2406 2407 2408 2409 2410 2411 2412 2413

    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,
2414 2415 2416 2417
					 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
					 input.len, (const HBUINT16 *) input.arrayZ + 1,
					 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
					 lookup.len, lookup.arrayZ,
2418
					 lookup_context);
B
Behdad Esfahbod 已提交
2419 2420
  }

2421 2422
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
2423
    TRACE_WOULD_APPLY (this);
2424

B
Behdad Esfahbod 已提交
2425
    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2426 2427 2428
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
    struct ChainContextApplyLookupContext lookup_context = {
2429
      {match_coverage},
2430 2431
      {this, this, this}
    };
B
Behdad Esfahbod 已提交
2432
    return_trace (chain_context_would_apply_lookup (c,
2433 2434 2435 2436
						    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));
2437 2438
  }

2439 2440 2441 2442 2443 2444
  inline const Coverage &get_coverage (void) const
  {
    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
    return this+input[0];
  }

2445
  inline bool apply (hb_ot_apply_context_t *c) const
B
Behdad Esfahbod 已提交
2446
  {
B
Behdad Esfahbod 已提交
2447
    TRACE_APPLY (this);
2448
    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2449

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

2453 2454
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2455
    struct ChainContextApplyLookupContext lookup_context = {
2456
      {match_coverage},
B
Behdad Esfahbod 已提交
2457
      {this, this, this}
2458
    };
B
Behdad Esfahbod 已提交
2459
    return_trace (chain_context_apply_lookup (c,
2460 2461 2462 2463
					      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));
2464 2465
  }

2466 2467 2468 2469 2470 2471 2472
  inline bool subset (hb_subset_context_t *c) const
  {
    TRACE_SUBSET (this);
    // TODO(subset)
    return_trace (false);
  }

B
Behdad Esfahbod 已提交
2473 2474
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
2475
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
2476
    if (!backtrack.sanitize (c, this)) return_trace (false);
B
Behdad Esfahbod 已提交
2477
    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
B
Behdad Esfahbod 已提交
2478 2479
    if (!input.sanitize (c, this)) return_trace (false);
    if (!input.len) return_trace (false); /* To be consistent with Context. */
B
Behdad Esfahbod 已提交
2480
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
B
Behdad Esfahbod 已提交
2481
    if (!lookahead.sanitize (c, this)) return_trace (false);
B
Behdad Esfahbod 已提交
2482
    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
B
Behdad Esfahbod 已提交
2483
    return_trace (lookup.sanitize (c));
B
Behdad Esfahbod 已提交
2484 2485
  }

2486
  protected:
B
Behdad Esfahbod 已提交
2487
  HBUINT16	format;			/* Format identifier--format = 3 */
B
Behdad Esfahbod 已提交
2488
  OffsetArrayOf<Coverage>
2489
		backtrack;		/* Array of coverage tables
2490 2491
					 * in backtracking sequence, in  glyph
					 * sequence order */
B
Behdad Esfahbod 已提交
2492
  OffsetArrayOf<Coverage>
2493
		inputX		;	/* Array of coverage
2494 2495
					 * tables in input sequence, in glyph
					 * sequence order */
B
Behdad Esfahbod 已提交
2496
  OffsetArrayOf<Coverage>
2497
		lookaheadX;		/* Array of coverage tables
2498 2499
					 * in lookahead sequence, in glyph
					 * sequence order */
B
Behdad Esfahbod 已提交
2500
  ArrayOf<LookupRecord>
2501
		lookupX;		/* Array of LookupRecords--in
B
Behdad Esfahbod 已提交
2502
					 * design order) */
2503
  public:
B
Behdad Esfahbod 已提交
2504
  DEFINE_SIZE_MIN (10);
2505 2506
};

B
Behdad Esfahbod 已提交
2507 2508
struct ChainContext
{
2509
  template <typename context_t>
2510
  inline typename context_t::return_t dispatch (context_t *c) const
2511
  {
2512
    TRACE_DISPATCH (this, u.format);
2513
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
2514
    switch (u.format) {
B
Behdad Esfahbod 已提交
2515 2516 2517 2518
    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 ());
2519 2520 2521
    }
  }

2522
  protected:
2523
  union {
B
Behdad Esfahbod 已提交
2524
  HBUINT16		format;	/* Format identifier */
B
Behdad Esfahbod 已提交
2525 2526 2527
  ChainContextFormat1	format1;
  ChainContextFormat2	format2;
  ChainContextFormat3	format3;
2528 2529 2530 2531
  } u;
};


2532
template <typename T>
2533 2534 2535 2536
struct ExtensionFormat1
{
  inline unsigned int get_type (void) const { return extensionLookupType; }

2537 2538 2539 2540
  template <typename X>
  inline const X& get_subtable (void) const
  {
    unsigned int offset = extensionOffset;
B
Behdad Esfahbod 已提交
2541 2542
    if (unlikely (!offset)) return Null(typename T::SubTable);
    return StructAtOffset<typename T::SubTable> (this, offset);
2543 2544 2545 2546 2547 2548
  }

  template <typename context_t>
  inline typename context_t::return_t dispatch (context_t *c) const
  {
    TRACE_DISPATCH (this, format);
2549
    if (unlikely (!c->may_dispatch (this, this))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
2550
    return_trace (get_subtable<typename T::SubTable> ().dispatch (c, get_type ()));
2551 2552 2553
  }

  /* This is called from may_dispatch() above with hb_sanitize_context_t. */
B
Behdad Esfahbod 已提交
2554 2555
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
2556
    TRACE_SANITIZE (this);
2557 2558
    return_trace (c->check_struct (this) &&
		  extensionOffset != 0 &&
B
Behdad Esfahbod 已提交
2559
		  extensionLookupType != T::SubTable::Extension);
B
Behdad Esfahbod 已提交
2560 2561
  }

2562
  protected:
B
Behdad Esfahbod 已提交
2563 2564
  HBUINT16	format;			/* Format identifier. Set to 1. */
  HBUINT16	extensionLookupType;	/* Lookup type of subtable referenced
2565 2566
					 * by ExtensionOffset (i.e. the
					 * extension subtable). */
B
Behdad Esfahbod 已提交
2567
  HBUINT32	extensionOffset;	/* Offset to the extension subtable,
2568
					 * of lookup type subtable. */
2569 2570
  public:
  DEFINE_SIZE_STATIC (8);
2571 2572
};

B
Behdad Esfahbod 已提交
2573
template <typename T>
2574 2575 2576 2577 2578
struct Extension
{
  inline unsigned int get_type (void) const
  {
    switch (u.format) {
B
Behdad Esfahbod 已提交
2579
    case 1: return u.format1.get_type ();
2580 2581 2582
    default:return 0;
    }
  }
2583 2584 2585
  template <typename X>
  inline const X& get_subtable (void) const
  {
2586
    switch (u.format) {
B
Behdad Esfahbod 已提交
2587 2588
    case 1: return u.format1.template get_subtable<typename T::SubTable> ();
    default:return Null(typename T::SubTable);
2589
    }
2590 2591
  }

B
Behdad Esfahbod 已提交
2592
  template <typename context_t>
2593
  inline typename context_t::return_t dispatch (context_t *c) const
B
Behdad Esfahbod 已提交
2594
  {
2595
    TRACE_DISPATCH (this, u.format);
2596
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
B
Behdad Esfahbod 已提交
2597
    switch (u.format) {
B
Behdad Esfahbod 已提交
2598 2599
    case 1: return_trace (u.format1.dispatch (c));
    default:return_trace (c->default_return_value ());
B
Behdad Esfahbod 已提交
2600 2601 2602
    }
  }

2603
  protected:
2604
  union {
B
Behdad Esfahbod 已提交
2605
  HBUINT16		format;		/* Format identifier */
2606
  ExtensionFormat1<T>	format1;
2607 2608 2609 2610
  } u;
};


B
Behdad Esfahbod 已提交
2611 2612 2613 2614
/*
 * GSUB/GPOS Common
 */

B
Behdad Esfahbod 已提交
2615 2616 2617 2618 2619 2620 2621
struct hb_ot_layout_lookup_accelerator_t
{
  template <typename TLookup>
  inline void init (const TLookup &lookup)
  {
    digest.init ();
    lookup.add_coverage (&digest);
2622 2623 2624 2625 2626 2627 2628 2629

    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 已提交
2630 2631 2632 2633 2634
  }

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

2635
  public:
B
Behdad Esfahbod 已提交
2636
  hb_set_digest_t digest;
2637
  hb_get_subtables_context_t::array_t subtables;
B
Behdad Esfahbod 已提交
2638 2639
};

B
Behdad Esfahbod 已提交
2640 2641
struct GSUBGPOS
{
2642
  inline bool has_data (void) const { return version.to_int () != 0; }
2643 2644 2645 2646
  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 已提交
2647 2648 2649 2650
  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); }
2651 2652 2653 2654 2655 2656 2657
  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; }
2658 2659
  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 已提交
2660 2661 2662 2663
  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); }
2664 2665 2666 2667 2668 2669 2670 2671 2672
  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 已提交
2673

2674 2675
  inline bool find_variations_index (const int *coords, unsigned int num_coords,
				     unsigned int *index) const
2676
  { return (version.to_int () >= 0x00010001u ? this+featureVars : Null(FeatureVariations))
2677
	   .find_index (coords, num_coords, index); }
2678 2679 2680 2681 2682 2683
  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)
    {
2684 2685
      const Feature *feature = (this+featureVars).find_substitute (variations_index,
								   feature_index);
2686 2687 2688 2689 2690
      if (feature)
        return *feature;
    }
    return get_feature (feature_index);
  }
2691

B
Behdad Esfahbod 已提交
2692
  template <typename TLookup>
2693 2694 2695 2696 2697
  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);
2698 2699
    out->scriptList.serialize_subset (c, this+scriptList, out);
    out->featureList.serialize_subset (c, this+featureList, out);
B
Behdad Esfahbod 已提交
2700 2701 2702 2703 2704 2705 2706 2707

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

2708
    if (version.to_int () >= 0x00010001u)
2709
     out->featureVars.serialize_subset (c, this+featureVars, out);
2710 2711 2712 2713 2714 2715 2716 2717 2718
    return_trace (true);
  }

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

2719
  template <typename TLookup>
B
Behdad Esfahbod 已提交
2720 2721
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
2722
    TRACE_SANITIZE (this);
2723
    typedef OffsetListOf<TLookup> TLookupList;
B
Behdad Esfahbod 已提交
2724 2725 2726 2727
    return_trace (version.sanitize (c) &&
		  likely (version.major == 1) &&
		  scriptList.sanitize (c, this) &&
		  featureList.sanitize (c, this) &&
2728
		  CastR<OffsetTo<TLookupList> > (lookupList).sanitize (c, this) &&
2729
		  (version.to_int () < 0x00010001u || featureVars.sanitize (c, this)));
B
Behdad Esfahbod 已提交
2730 2731
  }

B
WIP  
Behdad Esfahbod 已提交
2732 2733 2734 2735 2736 2737
  template <typename T>
  struct accelerator_t
  {
    inline void init (hb_face_t *face)
    {
      this->blob = hb_sanitize_context_t().reference_table<T> (face);
B
Behdad Esfahbod 已提交
2738
      table = this->blob->template as<T> ();
B
WIP  
Behdad Esfahbod 已提交
2739

2740
      this->lookup_count = table->get_lookup_count ();
B
WIP  
Behdad Esfahbod 已提交
2741 2742 2743 2744 2745 2746

      this->accels = (hb_ot_layout_lookup_accelerator_t *) calloc (this->lookup_count, sizeof (hb_ot_layout_lookup_accelerator_t));
      if (unlikely (!this->accels))
        this->lookup_count = 0;

      for (unsigned int i = 0; i < this->lookup_count; i++)
2747
	this->accels[i].init (table->get_lookup (i));
B
WIP  
Behdad Esfahbod 已提交
2748 2749 2750 2751
    }

    inline void fini (void)
    {
2752 2753 2754
      for (unsigned int i = 0; i < this->lookup_count; i++)
	this->accels[i].fini ();
      free (this->accels);
B
WIP  
Behdad Esfahbod 已提交
2755 2756 2757
      hb_blob_destroy (this->blob);
    }

2758 2759 2760 2761
    hb_blob_t *blob;
    const T *table;
    unsigned int lookup_count;
    hb_ot_layout_lookup_accelerator_t *accels;
B
WIP  
Behdad Esfahbod 已提交
2762 2763
  };

2764
  protected:
B
Behdad Esfahbod 已提交
2765
  FixedVersion<>version;	/* Version of the GSUB/GPOS table--initially set
2766
				 * to 0x00010000u */
B
Behdad Esfahbod 已提交
2767 2768 2769 2770 2771 2772
  OffsetTo<ScriptList>
		scriptList;  	/* ScriptList table */
  OffsetTo<FeatureList>
		featureList; 	/* FeatureList table */
  OffsetTo<LookupList>
		lookupList; 	/* LookupList table */
B
Behdad Esfahbod 已提交
2773
  LOffsetTo<FeatureVariations>
2774 2775 2776 2777
		featureVars;	/* Offset to Feature Variations
				   table--from beginning of table
				 * (may be NULL).  Introduced
				 * in version 0x00010001. */
2778
  public:
2779
  DEFINE_SIZE_MIN (10);
B
Behdad Esfahbod 已提交
2780
};
2781

2782

B
Behdad Esfahbod 已提交
2783
} /* namespace OT */
2784

B
Behdad Esfahbod 已提交
2785

2786
#endif /* HB_OT_LAYOUT_GSUBGPOS_HH */