hb-ot-layout-gsubgpos.hh 90.2 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_,
E
Ebrahim Byagowi 已提交
217 218 219 220
			       hb_set_t  *glyphs_before, /* OUT.  May be NULL */
			       hb_set_t  *glyphs_input,  /* OUT.  May be NULL */
			       hb_set_t  *glyphs_after,  /* OUT.  May be NULL */
			       hb_set_t  *glyphs_output, /* OUT.  May be NULL */
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
};


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

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

    inline void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; }
281
    inline void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
282 283 284 285 286 287 288
    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_; }

289 290 291 292 293 294 295
    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 已提交
296
				  const HBUINT16          *glyph_data) const
B
Behdad Esfahbod 已提交
297
    {
298 299 300 301 302 303 304 305
      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 已提交
306
    }
307 308 309 310 311 312 313 314

    enum may_skip_t {
      SKIP_NO,
      SKIP_YES,
      SKIP_MAYBE
    };

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

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

      return SKIP_NO;
B
Behdad Esfahbod 已提交
327
    }
328 329 330 331

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

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

365 366 367 368 369 370 371 372 373
    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);
    }

374
    inline void reject (void) { num_items++; match_glyph_data--; }
375

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

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

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

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

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

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

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

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

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

B
Behdad Esfahbod 已提交
443
    unsigned int num_items;
444
    unsigned int end;
B
Behdad Esfahbod 已提交
445 446
  };

B
Behdad Esfahbod 已提交
447 448

  inline const char *get_name (void) { return "APPLY"; }
449
  typedef return_t (*recurse_func_t) (hb_ot_apply_context_t *c, unsigned int lookup_index);
B
Behdad Esfahbod 已提交
450 451 452 453
  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 已提交
454
  return_t recurse (unsigned int sub_lookup_index)
B
Behdad Esfahbod 已提交
455
  {
456
    if (unlikely (nesting_level_left == 0 || !recurse_func || buffer->max_ops-- <= 0))
B
Behdad Esfahbod 已提交
457 458 459
      return default_return_value ();

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

465 466
  skipping_iterator_t iter_input, iter_context;

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

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

482
  bool has_glyph_classes;
483 484
  bool auto_zwnj;
  bool auto_zwj;
D
David Corbett 已提交
485
  bool random;
486

B
Behdad Esfahbod 已提交
487
  uint32_t random_state;
488

B
Behdad Esfahbod 已提交
489

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

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

B
Behdad Esfahbod 已提交
517 518 519
  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 (); }
520 521 522
  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 已提交
523
  inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; init_iters (); }
524

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

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

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

    return true;
  }

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

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

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

    return true;
  }

572
  inline void _set_glyph_props (hb_codepoint_t glyph_index,
573
			  unsigned int class_guess = 0,
574 575
			  bool ligature = false,
			  bool component = false) const
576
  {
577 578 579 580
    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)
581
    {
582
      add_in |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED;
583 584 585 586 587 588 589 590 591 592
      /* 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;
593
    if (likely (has_glyph_classes))
594
      _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | gdef.get_glyph_props (glyph_index));
595
    else if (class_guess)
596
      _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | class_guess);
597
  }
B
Behdad Esfahbod 已提交
598

599
  inline void replace_glyph (hb_codepoint_t glyph_index) const
600
  {
601 602
    _set_glyph_props (glyph_index);
    buffer->replace_glyph (glyph_index);
603
  }
604
  inline void replace_glyph_inplace (hb_codepoint_t glyph_index) const
605
  {
606 607 608 609 610 611
    _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
  {
612
    _set_glyph_props (glyph_index, class_guess, true);
613 614
    buffer->replace_glyph (glyph_index);
  }
615 616
  inline void output_glyph_for_component (hb_codepoint_t glyph_index,
					  unsigned int class_guess) const
B
Behdad Esfahbod 已提交
617
  {
618
    _set_glyph_props (glyph_index, class_guess, false, true);
619
    buffer->output_glyph (glyph_index);
B
Behdad Esfahbod 已提交
620
  }
621 622
};

623

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

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

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

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

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

  typedef hb_vector_t<hb_applicable_t, 2> array_t;

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

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

  array_t &array;
  unsigned int debug_depth;
};



B
Behdad Esfahbod 已提交
682

683
typedef bool (*intersects_func_t) (const hb_set_t *glyphs, const HBUINT16 &value, const void *data);
B
Behdad Esfahbod 已提交
684 685
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);
686

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

700

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

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

728

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


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

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

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

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

796
  if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return_trace (false);
797

B
Behdad Esfahbod 已提交
798 799
  hb_buffer_t *buffer = c->buffer;

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

804 805 806 807 808 809 810 811 812 813 814
  /*
   * 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.
815 816 817 818 819 820 821 822 823 824
   *   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.
825
   *     https://github.com/harfbuzz/harfbuzz/issues/545
826 827
   */

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

B
Behdad Esfahbod 已提交
831 832
  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 已提交
833

834 835 836 837 838 839
  enum {
    LIGBASE_NOT_CHECKED,
    LIGBASE_MAY_NOT_SKIP,
    LIGBASE_MAY_SKIP
  } ligbase = LIGBASE_NOT_CHECKED;

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

    match_positions[i] = skippy_iter.idx;
846

B
Behdad Esfahbod 已提交
847 848
    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]);
849

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

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

881
        if (ligbase == LIGBASE_MAY_NOT_SKIP)
882 883 884 885
	  return_trace (false);
      }
    }
    else
886
    {
887 888 889 890
      /* 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 已提交
891
	return_trace (false);
892 893
    }

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

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

899 900 901
  if (p_total_component_count)
    *p_total_component_count = total_component_count;

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

B
Behdad Esfahbod 已提交
913 914 915
  hb_buffer_t *buffer = c->buffer;

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

917 918 919 920 921
  /* - 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 已提交
922
   *   If it *is* a mark ligature, we don't allocate a new ligature id, and leave
923 924
   *   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 已提交
925
   *   and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA with a
926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948
   *   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
   */

949 950 951
  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 已提交
952 953
    if (!_hb_glyph_info_is_mark (&buffer->info[match_positions[i]]))
    {
954
      is_base_ligature = false;
B
Behdad Esfahbod 已提交
955 956 957
      is_mark_ligature = false;
      break;
    }
958
  bool is_ligature = !is_base_ligature && !is_mark_ligature;
B
Behdad Esfahbod 已提交
959

960 961
  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 已提交
962 963
  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());
964 965
  unsigned int components_so_far = last_num_components;

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

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

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

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

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

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

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

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

1034 1035
  *match_start = skippy_iter.idx;

B
Behdad Esfahbod 已提交
1036
  return_trace (true);
1037 1038
}

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

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

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

1057 1058
  *end_index = skippy_iter.idx + 1;

B
Behdad Esfahbod 已提交
1059
  return_trace (true);
1060 1061
}

B
Behdad Esfahbod 已提交
1062

1063

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

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

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

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

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

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

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

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

1119 1120 1121 1122 1123
    /* 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;

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

1127 1128 1129
    if (unlikely (buffer->max_ops <= 0))
      break;

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

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

1137 1138
    if (!delta)
        continue;
1139

B
Behdad Esfahbod 已提交
1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162
    /* 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.
     */
1163

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

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

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

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

1205 1206
  buffer->move_to (end);

B
Behdad Esfahbod 已提交
1207
  return_trace (true);
1208
}
1209

B
Behdad Esfahbod 已提交
1210

1211 1212 1213

/* Contextual lookups */

1214 1215 1216 1217 1218 1219
struct ContextClosureLookupContext
{
  ContextClosureFuncs funcs;
  const void *intersects_data;
};

1220 1221 1222 1223 1224 1225
struct ContextCollectGlyphsLookupContext
{
  ContextCollectGlyphsFuncs funcs;
  const void *collect_data;
};

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

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

1256 1257
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 已提交
1258
						  const HBUINT16 input[], /* Array of input values--start with second glyph */
1259 1260 1261 1262
						  unsigned int lookupCount,
						  const LookupRecord lookupRecord[],
						  ContextCollectGlyphsLookupContext &lookup_context)
{
B
Minor  
Behdad Esfahbod 已提交
1263
  collect_array (c, c->input,
1264 1265 1266 1267 1268
		 inputCount ? inputCount - 1 : 0, input,
		 lookup_context.funcs.collect, lookup_context.collect_data);
  recurse_lookups (c,
		   lookupCount, lookupRecord);
}
1269

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

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

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

1320 1321 1322
  inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const
  {
    TRACE_COLLECT_GLYPHS (this);
1323
    const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAtOffset<UnsizedArrayOf<LookupRecord> > (inputZ.arrayZ, inputZ[0].static_size * (inputCount ? inputCount - 1 : 0));
1324
    context_collect_glyphs_lookup (c,
1325 1326
				   inputCount, inputZ.arrayZ,
				   lookupCount, lookupRecord.arrayZ,
1327 1328 1329
				   lookup_context);
  }

1330 1331
  inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
  {
B
Behdad Esfahbod 已提交
1332
    TRACE_WOULD_APPLY (this);
1333 1334
    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));
1335 1336
  }

1337
  inline bool apply (hb_ot_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
B
Behdad Esfahbod 已提交
1338
  {
B
Behdad Esfahbod 已提交
1339
    TRACE_APPLY (this);
1340 1341
    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));
1342 1343
  }

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

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

B
Behdad Esfahbod 已提交
1370 1371
struct RuleSet
{
1372 1373 1374 1375 1376 1377 1378 1379 1380
  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 已提交
1381
  inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
1382
  {
B
Behdad Esfahbod 已提交
1383
    TRACE_CLOSURE (this);
1384 1385
    unsigned int num_rules = rule.len;
    for (unsigned int i = 0; i < num_rules; i++)
B
Behdad Esfahbod 已提交
1386
      (this+rule[i]).closure (c, lookup_context);
1387 1388
  }

1389 1390 1391 1392 1393 1394 1395 1396
  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);
  }

1397 1398
  inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
  {
B
Behdad Esfahbod 已提交
1399
    TRACE_WOULD_APPLY (this);
1400 1401 1402 1403
    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 已提交
1404
        return_trace (true);
1405
    }
B
Behdad Esfahbod 已提交
1406
    return_trace (false);
1407 1408
  }

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

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

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


B
Behdad Esfahbod 已提交
1436 1437
struct ContextFormat1
{
1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456
  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;
  }

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

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

    unsigned int count = ruleSet.len;
1467 1468 1469 1470 1471 1472 1473
    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);
    }
1474 1475
  }

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

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

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

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

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

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

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

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

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

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

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


B
Behdad Esfahbod 已提交
1547 1548
struct ContextFormat2
{
1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569
  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;
  }

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

    const ClassDef &class_def = this+classDef;

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

    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 已提交
1587
	rule_set.closure (c, lookup_context);
1588
      }
1589 1590
  }

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

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

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

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

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

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

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

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

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

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

1653
  protected:
B
Behdad Esfahbod 已提交
1654
  HBUINT16	format;			/* Format identifier--format = 2 */
1655 1656 1657 1658 1659 1660 1661 1662 1663
  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 */
1664
  public:
1665
  DEFINE_SIZE_ARRAY (8, ruleSet);
1666 1667 1668
};


B
Behdad Esfahbod 已提交
1669 1670
struct ContextFormat3
{
1671 1672 1673 1674 1675 1676 1677 1678 1679 1680
  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,
1681
			       glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
1682 1683 1684
			       lookup_context);
  }

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

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

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

1707
    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ.arrayZ, coverageZ[0].static_size * glyphCount);
1708 1709
    struct ContextCollectGlyphsLookupContext lookup_context = {
      {collect_coverage},
1710
      this
1711 1712 1713
    };

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

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

1723
    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ.arrayZ, coverageZ[0].static_size * glyphCount);
1724
    struct ContextApplyLookupContext lookup_context = {
1725
      {match_coverage},
1726 1727
      this
    };
1728
    return_trace (context_would_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, lookup_context));
1729 1730
  }

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

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

1740
    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ.arrayZ, coverageZ[0].static_size * glyphCount);
1741
    struct ContextApplyLookupContext lookup_context = {
1742
      {match_coverage},
B
Behdad Esfahbod 已提交
1743
      this
1744
    };
1745
    return_trace (context_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, lookup_context));
1746 1747
  }

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

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

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

B
Behdad Esfahbod 已提交
1783 1784
struct Context
{
1785
  template <typename context_t>
1786
  inline typename context_t::return_t dispatch (context_t *c) const
1787
  {
1788
    TRACE_DISPATCH (this, u.format);
1789
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1790
    switch (u.format) {
B
Behdad Esfahbod 已提交
1791 1792 1793 1794
    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 ());
1795 1796 1797
    }
  }

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

1807 1808 1809

/* Chaining Contextual lookups */

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

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

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

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

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

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

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

B
Behdad Esfahbod 已提交
1941 1942
struct ChainRule
{
1943 1944 1945 1946 1947 1948
  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,
1949
				     input.lenP1, input.arrayZ,
1950 1951 1952 1953
				     lookahead.len, lookahead.arrayZ,
				     lookup_context);
  }

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

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

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

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

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

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

B
Behdad Esfahbod 已提交
2038 2039
struct ChainRuleSet
{
2040 2041 2042 2043 2044 2045 2046 2047
  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 已提交
2048
  inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
2049
  {
B
Behdad Esfahbod 已提交
2050
    TRACE_CLOSURE (this);
2051 2052
    unsigned int num_rules = rule.len;
    for (unsigned int i = 0; i < num_rules; i++)
B
Behdad Esfahbod 已提交
2053
      (this+rule[i]).closure (c, lookup_context);
2054 2055
  }

2056 2057 2058 2059 2060 2061 2062 2063
  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);
  }

2064 2065
  inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
  {
B
Behdad Esfahbod 已提交
2066
    TRACE_WOULD_APPLY (this);
2067 2068 2069
    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 已提交
2070
        return_trace (true);
2071

B
Behdad Esfahbod 已提交
2072
    return_trace (false);
2073 2074
  }

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

B
Behdad Esfahbod 已提交
2083
    return_trace (false);
2084
  }
2085

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

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

B
Behdad Esfahbod 已提交
2100 2101
struct ChainContextFormat1
{
2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120
  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;
  }

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

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

    unsigned int count = ruleSet.len;
2131 2132 2133 2134 2135 2136 2137
    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);
    }
2138 2139
  }

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

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

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

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

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

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

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

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

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

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

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

B
Behdad Esfahbod 已提交
2209 2210
struct ChainContextFormat2
{
2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234
  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;
  }
2235
  inline void closure (hb_closure_context_t *c) const
2236
  {
B
Behdad Esfahbod 已提交
2237
    TRACE_CLOSURE (this);
2238
    if (!(this+coverage).intersects (c->glyphs))
B
Behdad Esfahbod 已提交
2239
      return;
2240 2241 2242 2243 2244 2245

    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 = {
2246
      {intersects_class},
2247 2248 2249 2250 2251 2252 2253 2254 2255
      {&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 已提交
2256
	rule_set.closure (c, lookup_context);
2257
      }
2258 2259
  }

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

2265 2266 2267 2268
    const ClassDef &backtrack_class_def = this+backtrackClassDef;
    const ClassDef &input_class_def = this+inputClassDef;
    const ClassDef &lookahead_class_def = this+lookaheadClassDef;

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

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

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

2285
    const ClassDef &backtrack_class_def = this+backtrackClassDef;
2286
    const ClassDef &input_class_def = this+inputClassDef;
2287
    const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2288

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

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

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

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

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

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

B
Behdad Esfahbod 已提交
2331 2332
  inline bool sanitize (hb_sanitize_context_t *c) const
  {
B
Behdad Esfahbod 已提交
2333
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
2334 2335 2336 2337 2338
    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 已提交
2339 2340
  }

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

B
Behdad Esfahbod 已提交
2365 2366
struct ChainContextFormat3
{
2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385
  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);
  }

2386
  inline void closure (hb_closure_context_t *c) const
2387
  {
B
Behdad Esfahbod 已提交
2388
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
2389 2390 2391 2392 2393 2394 2395 2396
    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 = {
2397
      {intersects_coverage},
B
Behdad Esfahbod 已提交
2398 2399 2400
      {this, this, this}
    };
    chain_context_closure_lookup (c,
2401 2402 2403 2404
				  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 已提交
2405
				  lookup_context);
2406 2407
  }

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

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

    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,
2422 2423 2424 2425
					 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
					 input.len, (const HBUINT16 *) input.arrayZ + 1,
					 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
					 lookup.len, lookup.arrayZ,
2426
					 lookup_context);
B
Behdad Esfahbod 已提交
2427 2428
  }

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

B
Behdad Esfahbod 已提交
2433
    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2434 2435 2436
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
    struct ChainContextApplyLookupContext lookup_context = {
2437
      {match_coverage},
2438 2439
      {this, this, this}
    };
B
Behdad Esfahbod 已提交
2440
    return_trace (chain_context_would_apply_lookup (c,
2441 2442 2443 2444
						    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));
2445 2446
  }

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

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

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

2461 2462
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2463
    struct ChainContextApplyLookupContext lookup_context = {
2464
      {match_coverage},
B
Behdad Esfahbod 已提交
2465
      {this, this, this}
2466
    };
B
Behdad Esfahbod 已提交
2467
    return_trace (chain_context_apply_lookup (c,
2468 2469 2470 2471
					      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));
2472 2473
  }

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

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

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

B
Behdad Esfahbod 已提交
2515 2516
struct ChainContext
{
2517
  template <typename context_t>
2518
  inline typename context_t::return_t dispatch (context_t *c) const
2519
  {
2520
    TRACE_DISPATCH (this, u.format);
2521
    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
2522
    switch (u.format) {
B
Behdad Esfahbod 已提交
2523 2524 2525 2526
    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 ());
2527 2528 2529
    }
  }

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


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

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

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

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

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

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

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

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


B
Behdad Esfahbod 已提交
2619 2620 2621 2622
/*
 * GSUB/GPOS Common
 */

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

    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 已提交
2638 2639 2640 2641 2642
  }

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

2643 2644 2645 2646 2647 2648 2649 2650 2651
  inline bool apply (hb_ot_apply_context_t *c) const
  {
     for (unsigned int i = 0; i < subtables.len; i++)
       if (subtables[i].apply (c))
         return true;
     return false;
  }

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

B
Behdad Esfahbod 已提交
2656 2657
struct GSUBGPOS
{
2658
  inline bool has_data (void) const { return version.to_int () != 0; }
2659 2660 2661 2662
  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 已提交
2663 2664 2665 2666
  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); }
2667 2668 2669 2670 2671 2672 2673
  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; }
2674 2675
  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 已提交
2676 2677 2678 2679
  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); }
2680 2681 2682 2683 2684 2685 2686 2687 2688
  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 已提交
2689

2690 2691
  inline bool find_variations_index (const int *coords, unsigned int num_coords,
				     unsigned int *index) const
2692
  { return (version.to_int () >= 0x00010001u ? this+featureVars : Null(FeatureVariations))
2693
	   .find_index (coords, num_coords, index); }
2694 2695 2696 2697 2698 2699
  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)
    {
2700 2701
      const Feature *feature = (this+featureVars).find_substitute (variations_index,
								   feature_index);
2702 2703 2704 2705 2706
      if (feature)
        return *feature;
    }
    return get_feature (feature_index);
  }
2707

B
Behdad Esfahbod 已提交
2708
  template <typename TLookup>
2709 2710 2711 2712 2713
  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);
2714 2715
    out->scriptList.serialize_subset (c, this+scriptList, out);
    out->featureList.serialize_subset (c, this+featureList, out);
B
Behdad Esfahbod 已提交
2716 2717 2718 2719 2720 2721 2722 2723

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

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

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

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

B
WIP  
Behdad Esfahbod 已提交
2748 2749 2750 2751 2752 2753
  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 已提交
2754
      table = this->blob->template as<T> ();
B
WIP  
Behdad Esfahbod 已提交
2755

2756
      this->lookup_count = table->get_lookup_count ();
B
WIP  
Behdad Esfahbod 已提交
2757 2758 2759 2760 2761 2762

      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++)
2763
	this->accels[i].init (table->get_lookup (i));
B
WIP  
Behdad Esfahbod 已提交
2764 2765 2766 2767
    }

    inline void fini (void)
    {
2768 2769 2770
      for (unsigned int i = 0; i < this->lookup_count; i++)
	this->accels[i].fini ();
      free (this->accels);
B
WIP  
Behdad Esfahbod 已提交
2771 2772 2773
      hb_blob_destroy (this->blob);
    }

2774 2775 2776 2777
    hb_blob_t *blob;
    const T *table;
    unsigned int lookup_count;
    hb_ot_layout_lookup_accelerator_t *accels;
B
WIP  
Behdad Esfahbod 已提交
2778 2779
  };

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

2798

B
Behdad Esfahbod 已提交
2799
} /* namespace OT */
2800

B
Behdad Esfahbod 已提交
2801

2802
#endif /* HB_OT_LAYOUT_GSUBGPOS_HH */