hb-ot-layout-gsubgpos-private.hh 75.3 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_PRIVATE_HH
#define HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH
31

32
#include "hb-buffer-private.hh"
33
#include "hb-ot-layout-gdef-table.hh"
34
#include "hb-set-private.hh"
35

36

37 38
namespace OT {

B
Behdad Esfahbod 已提交
39

40

41
#define TRACE_DISPATCH(this) \
42 43 44 45
	hb_auto_trace_t<context_t::max_debug_depth, typename context_t::return_t> trace \
	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
	 "");

46 47 48 49
#ifndef HB_DEBUG_CLOSURE
#define HB_DEBUG_CLOSURE (HB_DEBUG+0)
#endif

B
Behdad Esfahbod 已提交
50
#define TRACE_CLOSURE(this) \
51
	hb_auto_trace_t<HB_DEBUG_CLOSURE, hb_void_t> trace \
52
	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
53
	 "");
54 55 56

struct hb_closure_context_t
{
57 58
  inline const char *get_name (void) { return "CLOSURE"; }
  static const unsigned int max_debug_depth = HB_DEBUG_CLOSURE;
59
  typedef hb_void_t return_t;
60 61
  typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
  template <typename T>
62
  inline return_t dispatch (const T &obj) { obj.closure (this); return HB_VOID; }
63
  static return_t default_return_value (void) { return HB_VOID; }
64
  bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
65 66
  return_t recurse (unsigned int lookup_index)
  {
67
    if (unlikely (nesting_level_left == 0 || !recurse_func))
68
      return default_return_value ();
69 70 71 72

    nesting_level_left--;
    recurse_func (this, lookup_index);
    nesting_level_left++;
73
    return HB_VOID;
74 75
  }

76
  hb_face_t *face;
77
  hb_set_t *glyphs;
78
  recurse_func_t recurse_func;
79 80 81 82
  unsigned int nesting_level_left;
  unsigned int debug_depth;

  hb_closure_context_t (hb_face_t *face_,
83
			hb_set_t *glyphs_,
84
		        unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) :
85 86
			  face (face_),
			  glyphs (glyphs_),
87
			  recurse_func (NULL),
88 89
			  nesting_level_left (nesting_level_left_),
			  debug_depth (0) {}
90 91

  void set_recurse_func (recurse_func_t func) { recurse_func = func; }
92 93 94 95
};



96 97 98 99
#ifndef HB_DEBUG_WOULD_APPLY
#define HB_DEBUG_WOULD_APPLY (HB_DEBUG+0)
#endif

B
Behdad Esfahbod 已提交
100
#define TRACE_WOULD_APPLY(this) \
101
	hb_auto_trace_t<HB_DEBUG_WOULD_APPLY, bool> trace \
102
	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
103
	 "%d glyphs", c->len);
104 105 106

struct hb_would_apply_context_t
{
107 108
  inline const char *get_name (void) { return "WOULD_APPLY"; }
  static const unsigned int max_debug_depth = HB_DEBUG_WOULD_APPLY;
B
Behdad Esfahbod 已提交
109 110
  typedef bool return_t;
  template <typename T>
111
  inline return_t dispatch (const T &obj) { return obj.would_apply (this); }
B
Behdad Esfahbod 已提交
112
  static return_t default_return_value (void) { return false; }
113
  bool stop_sublookup_iteration (return_t r) const { return r; }
B
Behdad Esfahbod 已提交
114

115
  hb_face_t *face;
116
  const hb_codepoint_t *glyphs;
117
  unsigned int len;
118
  bool zero_context;
119 120 121
  unsigned int debug_depth;

  hb_would_apply_context_t (hb_face_t *face_,
122 123
			    const hb_codepoint_t *glyphs_,
			    unsigned int len_,
B
Behdad Esfahbod 已提交
124
			    bool zero_context_) :
125
			      face (face_),
126 127
			      glyphs (glyphs_),
			      len (len_),
128
			      zero_context (zero_context_),
129
			      debug_depth (0) {}
130 131 132
};


133 134 135 136 137

#ifndef HB_DEBUG_COLLECT_GLYPHS
#define HB_DEBUG_COLLECT_GLYPHS (HB_DEBUG+0)
#endif

B
Behdad Esfahbod 已提交
138
#define TRACE_COLLECT_GLYPHS(this) \
139
	hb_auto_trace_t<HB_DEBUG_COLLECT_GLYPHS, hb_void_t> trace \
140
	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
141
	 "");
142 143 144

struct hb_collect_glyphs_context_t
{
145 146
  inline const char *get_name (void) { return "COLLECT_GLYPHS"; }
  static const unsigned int max_debug_depth = HB_DEBUG_COLLECT_GLYPHS;
147
  typedef hb_void_t return_t;
B
Behdad Esfahbod 已提交
148
  typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index);
B
Behdad Esfahbod 已提交
149
  template <typename T>
150
  inline return_t dispatch (const T &obj) { obj.collect_glyphs (this); return HB_VOID; }
151
  static return_t default_return_value (void) { return HB_VOID; }
152
  bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
B
Behdad Esfahbod 已提交
153 154
  return_t recurse (unsigned int lookup_index)
  {
B
Behdad Esfahbod 已提交
155 156 157
    if (unlikely (nesting_level_left == 0 || !recurse_func))
      return default_return_value ();

158 159
    /* Note that GPOS sets recurse_func to NULL already, so it doesn't get
     * past the previous check.  For GSUB, we only want to collect the output
160 161 162 163 164 165 166
     * 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.
     */
167 168

    if (output == hb_set_get_empty ())
169
      return HB_VOID;
170 171 172 173 174

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

B
Behdad Esfahbod 已提交
176
    nesting_level_left--;
177
    recurse_func (this, lookup_index);
B
Behdad Esfahbod 已提交
178
    nesting_level_left++;
179 180 181 182 183

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

184
    return HB_VOID;
B
Behdad Esfahbod 已提交
185 186
  }

187
  hb_face_t *face;
B
Minor  
Behdad Esfahbod 已提交
188 189 190 191
  hb_set_t *before;
  hb_set_t *input;
  hb_set_t *after;
  hb_set_t *output;
B
Behdad Esfahbod 已提交
192 193
  recurse_func_t recurse_func;
  unsigned int nesting_level_left;
194 195 196 197 198 199
  unsigned int debug_depth;

  hb_collect_glyphs_context_t (hb_face_t *face_,
			       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 */
B
Behdad Esfahbod 已提交
200 201
			       hb_set_t  *glyphs_output, /* OUT. May be NULL */
			       unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) :
202
			      face (face_),
B
Minor  
Behdad Esfahbod 已提交
203 204 205 206
			      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 已提交
207 208
			      recurse_func (NULL),
			      nesting_level_left (nesting_level_left_),
209
			      debug_depth (0) {}
B
Behdad Esfahbod 已提交
210 211

  void set_recurse_func (recurse_func_t func) { recurse_func = func; }
212 213 214 215
};



216 217
struct hb_get_coverage_context_t
{
218 219
  inline const char *get_name (void) { return "GET_COVERAGE"; }
  static const unsigned int max_debug_depth = 0;
220 221
  typedef const Coverage &return_t;
  template <typename T>
222
  inline return_t dispatch (const T &obj) { return obj.get_coverage (); }
223
  static return_t default_return_value (void) { return Null(Coverage); }
B
Behdad Esfahbod 已提交
224

225 226 227 228
  hb_get_coverage_context_t (void) :
			    debug_depth (0) {}

  unsigned int debug_depth;
229 230 231 232
};



B
Behdad Esfahbod 已提交
233
#ifndef HB_DEBUG_APPLY
234
#define HB_DEBUG_APPLY (HB_DEBUG+0)
B
Behdad Esfahbod 已提交
235 236
#endif

B
Behdad Esfahbod 已提交
237
#define TRACE_APPLY(this) \
238
	hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace \
239
	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
240
	 "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);
B
Behdad Esfahbod 已提交
241

242 243
struct hb_apply_context_t
{
244 245
  inline const char *get_name (void) { return "APPLY"; }
  static const unsigned int max_debug_depth = HB_DEBUG_APPLY;
246 247 248
  typedef bool return_t;
  typedef return_t (*recurse_func_t) (hb_apply_context_t *c, unsigned int lookup_index);
  template <typename T>
249
  inline return_t dispatch (const T &obj) { return obj.apply (this); }
B
Minor  
Behdad Esfahbod 已提交
250
  static return_t default_return_value (void) { return false; }
251
  bool stop_sublookup_iteration (return_t r) const { return r; }
252 253 254 255 256
  return_t recurse (unsigned int lookup_index)
  {
    if (unlikely (nesting_level_left == 0 || !recurse_func))
      return default_return_value ();

257
    nesting_level_left--;
258
    bool ret = recurse_func (this, lookup_index);
259
    nesting_level_left++;
260
    return ret;
261 262
  }

263
  unsigned int table_index; /* GSUB/GPOS */
264 265
  hb_font_t *font;
  hb_face_t *face;
B
Behdad Esfahbod 已提交
266
  hb_buffer_t *buffer;
267
  hb_direction_t direction;
B
Behdad Esfahbod 已提交
268
  hb_mask_t lookup_mask;
269
  bool auto_zwj;
270
  recurse_func_t recurse_func;
271
  unsigned int nesting_level_left;
272
  unsigned int lookup_props;
273
  const GDEF &gdef;
274
  bool has_glyph_classes;
275
  unsigned int debug_depth;
276

277

278 279
  hb_apply_context_t (unsigned int table_index_,
		      hb_font_t *font_,
B
Behdad Esfahbod 已提交
280
		      hb_buffer_t *buffer_) :
281
			table_index (table_index_),
282
			font (font_), face (font->face), buffer (buffer_),
283
			direction (buffer_->props.direction),
B
Behdad Esfahbod 已提交
284 285
			lookup_mask (1),
			auto_zwj (true),
286
			recurse_func (NULL),
B
Minor  
Behdad Esfahbod 已提交
287
			nesting_level_left (MAX_NESTING_LEVEL),
288
			lookup_props (0),
289
			gdef (*hb_ot_layout_from_face (face)->gdef),
290 291
			has_glyph_classes (gdef.has_glyph_classes ()),
			debug_depth (0) {}
292

B
Behdad Esfahbod 已提交
293 294
  inline void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; }
  inline void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; }
B
Behdad Esfahbod 已提交
295 296 297
  inline void set_recurse_func (recurse_func_t func) { recurse_func = func; }
  inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
  inline void set_lookup (const Lookup &l) { lookup_props = l.get_props (); }
298

299
  struct matcher_t
B
Behdad Esfahbod 已提交
300
  {
301 302
    inline matcher_t (void) :
	     lookup_props (0),
303 304
	     ignore_zwnj (false),
	     ignore_zwj (false),
305 306 307 308 309 310 311 312 313 314
	     mask (-1),
#define arg1(arg) (arg) /* Remove the macro to see why it's needed! */
	     syllable arg1(0),
#undef arg1
	     match_func (NULL),
	     match_data (NULL) {};

    typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data);

    inline void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; }
315
    inline void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
316 317 318 319 320 321 322
    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_; }

323 324 325 326 327 328 329 330
    enum may_match_t {
      MATCH_NO,
      MATCH_YES,
      MATCH_MAYBE
    };

    inline may_match_t may_match (const hb_glyph_info_t &info,
				  const USHORT          *glyph_data) const
B
Behdad Esfahbod 已提交
331
    {
332 333 334 335 336 337 338 339
      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 已提交
340
    }
341 342 343 344 345 346 347 348 349 350

    enum may_skip_t {
      SKIP_NO,
      SKIP_YES,
      SKIP_MAYBE
    };

    inline may_skip_t
    may_skip (const hb_apply_context_t *c,
	      const hb_glyph_info_t    &info) const
B
Behdad Esfahbod 已提交
351
    {
352 353
      unsigned int property;

B
Behdad Esfahbod 已提交
354
      property = _hb_glyph_info_get_glyph_props (&info);
355 356 357 358

      if (!c->match_properties (info.codepoint, property, lookup_props))
	return SKIP_YES;

359 360 361
      if (unlikely (_hb_glyph_info_is_default_ignorable (&info) &&
		    (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) &&
		    (ignore_zwj || !_hb_glyph_info_is_zwj (&info)) &&
362
		    !_hb_glyph_info_ligated (&info)))
363 364 365
	return SKIP_MAYBE;

      return SKIP_NO;
B
Behdad Esfahbod 已提交
366
    }
367 368 369 370

    protected:
    unsigned int lookup_props;
    bool ignore_zwnj;
371
    bool ignore_zwj;
372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
    hb_mask_t mask;
    uint8_t syllable;
    match_func_t match_func;
    const void *match_data;
  };

  struct skipping_forward_iterator_t
  {
    inline skipping_forward_iterator_t (hb_apply_context_t *c_,
					unsigned int start_index_,
					unsigned int num_items_,
					bool context_match = false) :
					 idx (start_index_),
					 c (c_),
					 match_glyph_data (NULL),
					 num_items (num_items_),
					 end (c->buffer->len)
B
Behdad Esfahbod 已提交
389
    {
390
      matcher.set_lookup_props (c->lookup_props);
391 392 393 394
      /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
      matcher.set_ignore_zwnj (context_match || c->table_index == 1);
      /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */
      matcher.set_ignore_zwj (context_match || c->table_index == 1 || c->auto_zwj);
395
      if (!context_match)
396
	matcher.set_mask (c->lookup_mask);
397
      matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
B
Behdad Esfahbod 已提交
398
    }
399 400 401 402 403
    inline void set_lookup_props (unsigned int lookup_props) { matcher.set_lookup_props (lookup_props); }
    inline void set_syllable (unsigned int syllable) { matcher.set_syllable (syllable); }
    inline void set_match_func (matcher_t::match_func_t match_func,
				const void *match_data,
				const USHORT glyph_data[])
404
    {
405 406
      matcher.set_match_func (match_func, match_data);
      match_glyph_data = glyph_data;
407
    }
408 409 410

    inline bool has_no_chance (void) const { return unlikely (num_items && idx + num_items >= end); }
    inline void reject (void) { num_items++; match_glyph_data--; }
B
Behdad Esfahbod 已提交
411
    inline bool next (void)
B
Behdad Esfahbod 已提交
412
    {
413
      assert (num_items > 0);
414
      while (!has_no_chance ())
B
Behdad Esfahbod 已提交
415
      {
B
Behdad Esfahbod 已提交
416
	idx++;
417 418
	const hb_glyph_info_t &info = c->buffer->info[idx];

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

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

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

    unsigned int idx;
440
    protected:
B
Behdad Esfahbod 已提交
441
    hb_apply_context_t *c;
442 443 444
    matcher_t matcher;
    const USHORT *match_glyph_data;

B
Behdad Esfahbod 已提交
445 446 447 448
    unsigned int num_items;
    unsigned int end;
  };

449
  struct skipping_backward_iterator_t
B
Behdad Esfahbod 已提交
450
  {
451 452 453
    inline skipping_backward_iterator_t (hb_apply_context_t *c_,
					 unsigned int start_index_,
					 unsigned int num_items_,
454 455 456 457 458
					 bool context_match = false) :
					  idx (start_index_),
					  c (c_),
					  match_glyph_data (NULL),
					  num_items (num_items_)
B
Behdad Esfahbod 已提交
459
    {
460
      matcher.set_lookup_props (c->lookup_props);
461 462 463 464
      /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
      matcher.set_ignore_zwnj (context_match || c->table_index == 1);
      /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */
      matcher.set_ignore_zwj (context_match || c->table_index == 1 || c->auto_zwj);
465
      if (!context_match)
466
	matcher.set_mask (c->lookup_mask);
467
      matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
B
Behdad Esfahbod 已提交
468
    }
469 470 471 472 473
    inline void set_lookup_props (unsigned int lookup_props) { matcher.set_lookup_props (lookup_props); }
    inline void set_syllable (unsigned int syllable) { matcher.set_syllable (syllable); }
    inline void set_match_func (matcher_t::match_func_t match_func,
				const void *match_data,
				const USHORT glyph_data[])
474
    {
475 476
      matcher.set_match_func (match_func, match_data);
      match_glyph_data = glyph_data;
477
    }
478 479 480

    inline bool has_no_chance (void) const { return unlikely (idx < num_items); }
    inline void reject (void) { num_items++; }
B
Behdad Esfahbod 已提交
481
    inline bool prev (void)
B
Behdad Esfahbod 已提交
482
    {
483
      assert (num_items > 0);
484
      while (!has_no_chance ())
B
Behdad Esfahbod 已提交
485 486
      {
	idx--;
487 488
	const hb_glyph_info_t &info = c->buffer->out_info[idx];

B
Minor  
Behdad Esfahbod 已提交
489
	matcher_t::may_skip_t skip = matcher.may_skip (c, info);
490 491 492 493

	if (unlikely (skip == matcher_t::SKIP_YES))
	  continue;

494
	matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
B
Behdad Esfahbod 已提交
495 496 497
	if (match == matcher_t::MATCH_YES ||
	    (match == matcher_t::MATCH_MAYBE &&
	     skip == matcher_t::SKIP_NO))
498 499 500 501 502 503 504
	{
	  num_items--;
	  match_glyph_data++;
	  return true;
	}

	if (skip == matcher_t::SKIP_NO)
B
Behdad Esfahbod 已提交
505
	  return false;
506 507
      }
      return false;
B
Behdad Esfahbod 已提交
508 509 510
    }

    unsigned int idx;
511
    protected:
B
Behdad Esfahbod 已提交
512
    hb_apply_context_t *c;
513 514 515
    matcher_t matcher;
    const USHORT *match_glyph_data;

B
Behdad Esfahbod 已提交
516 517 518
    unsigned int num_items;
  };

519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550
  inline bool
  match_properties_mark (hb_codepoint_t  glyph,
			 unsigned int    glyph_props,
			 unsigned int    lookup_props) const
  {
    /* If using mark filtering sets, the high short of
     * lookup_props has the set index.
     */
    if (lookup_props & LookupFlag::UseMarkFilteringSet)
      return gdef.mark_set_covers (lookup_props >> 16, glyph);

    /* The second byte of lookup_props has the meaning
     * "ignore marks of attachment type different than
     * the attachment type specified."
     */
    if (lookup_props & LookupFlag::MarkAttachmentType)
      return (lookup_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);

    return true;
  }

  inline bool
  match_properties (hb_codepoint_t  glyph,
		    unsigned int    glyph_props,
		    unsigned int    lookup_props) const
  {
    /* Not covered, if, for example, glyph class is ligature and
     * lookup_props includes LookupFlags::IgnoreLigatures
     */
    if (glyph_props & lookup_props & LookupFlag::IgnoreFlags)
      return false;

551
    if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK))
552 553 554 555 556 557 558
      return match_properties_mark (glyph, glyph_props, lookup_props);

    return true;
  }

  inline bool
  check_glyph_property (hb_glyph_info_t *info,
559
			unsigned int  lookup_props) const
560
  {
B
Behdad Esfahbod 已提交
561
    unsigned int property;
562

B
Behdad Esfahbod 已提交
563
    property = _hb_glyph_info_get_glyph_props (info);
564 565 566 567

    return match_properties (info->codepoint, property, lookup_props);
  }

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

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

619

B
Behdad Esfahbod 已提交
620

621
typedef bool (*intersects_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data);
622
typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data);
B
Behdad Esfahbod 已提交
623
typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data);
624

625 626 627 628
struct ContextClosureFuncs
{
  intersects_func_t intersects;
};
629 630 631 632
struct ContextCollectGlyphsFuncs
{
  collect_glyphs_func_t collect;
};
633
struct ContextApplyFuncs
B
Behdad Esfahbod 已提交
634
{
635
  match_func_t match;
636 637
};

638

639
static inline bool intersects_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED)
640 641 642
{
  return glyphs->has (value);
}
643
static inline bool intersects_class (hb_set_t *glyphs, const USHORT &value, const void *data)
644 645 646 647
{
  const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
  return class_def.intersects_class (glyphs, value);
}
648
static inline bool intersects_coverage (hb_set_t *glyphs, const USHORT &value, const void *data)
649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665
{
  const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
  return (data+coverage).intersects (glyphs);
}

static inline bool intersects_array (hb_closure_context_t *c,
				     unsigned int count,
				     const USHORT values[],
				     intersects_func_t intersects_func,
				     const void *intersects_data)
{
  for (unsigned int i = 0; i < count; i++)
    if (likely (!intersects_func (c->glyphs, values[i], intersects_data)))
      return false;
  return true;
}

666

667 668 669 670 671 672 673 674 675 676 677 678 679 680
static inline void collect_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED)
{
  glyphs->add (value);
}
static inline void collect_class (hb_set_t *glyphs, const USHORT &value, const void *data)
{
  const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
  class_def.add_class (glyphs, value);
}
static inline void collect_coverage (hb_set_t *glyphs, const USHORT &value, const void *data)
{
  const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
  (data+coverage).add_coverage (glyphs);
}
B
Behdad Esfahbod 已提交
681
static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
682
				  hb_set_t *glyphs,
683 684 685 686 687 688
				  unsigned int count,
				  const USHORT values[],
				  collect_glyphs_func_t collect_func,
				  const void *collect_data)
{
  for (unsigned int i = 0; i < count; i++)
689
    collect_func (glyphs, values[i], collect_data);
690 691 692
}


B
Behdad Esfahbod 已提交
693
static inline bool match_glyph (hb_codepoint_t glyph_id, const USHORT &value, const void *data HB_UNUSED)
B
Behdad Esfahbod 已提交
694
{
695 696
  return glyph_id == value;
}
B
Behdad Esfahbod 已提交
697
static inline bool match_class (hb_codepoint_t glyph_id, const USHORT &value, const void *data)
B
Behdad Esfahbod 已提交
698
{
B
Behdad Esfahbod 已提交
699
  const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
700 701
  return class_def.get_class (glyph_id) == value;
}
B
Behdad Esfahbod 已提交
702
static inline bool match_coverage (hb_codepoint_t glyph_id, const USHORT &value, const void *data)
B
Behdad Esfahbod 已提交
703
{
704
  const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
705
  return (data+coverage).get_coverage (glyph_id) != NOT_COVERED;
706 707
}

708 709 710 711 712 713 714 715 716 717
static inline bool would_match_input (hb_would_apply_context_t *c,
				      unsigned int count, /* Including the first glyph (not matched) */
				      const USHORT input[], /* Array of input values--start with second glyph */
				      match_func_t match_func,
				      const void *match_data)
{
  if (count != c->len)
    return false;

  for (unsigned int i = 1; i < count; i++)
718
    if (likely (!match_func (c->glyphs[i], input[i - 1], match_data)))
719 720 721 722
      return false;

  return true;
}
B
Behdad Esfahbod 已提交
723
static inline bool match_input (hb_apply_context_t *c,
B
Behdad Esfahbod 已提交
724 725 726
				unsigned int count, /* Including the first glyph (not matched) */
				const USHORT input[], /* Array of input values--start with second glyph */
				match_func_t match_func,
B
Behdad Esfahbod 已提交
727
				const void *match_data,
B
Behdad Esfahbod 已提交
728 729
				unsigned int *end_offset,
				unsigned int match_positions[MAX_CONTEXT_LENGTH],
730 731
				bool *p_is_mark_ligature = NULL,
				unsigned int *p_total_component_count = NULL)
B
Behdad Esfahbod 已提交
732
{
B
Cleanup  
Behdad Esfahbod 已提交
733
  TRACE_APPLY (NULL);
734

735 736
  if (unlikely (count > MAX_CONTEXT_LENGTH)) TRACE_RETURN (false);

B
Behdad Esfahbod 已提交
737 738 739
  hb_buffer_t *buffer = c->buffer;

  hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, buffer->idx, count - 1);
740
  skippy_iter.set_match_func (match_func, match_data, input);
741 742
  if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);

743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760
  /*
   * 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.
   *   However, it would be wrong to ligate that SHADDA,FATHA sequence.o
   *   There is an exception to this: 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...)
   */

B
Behdad Esfahbod 已提交
761
  bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->cur());
762 763

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

B
Behdad Esfahbod 已提交
766 767
  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 已提交
768

B
Behdad Esfahbod 已提交
769
  match_positions[0] = buffer->idx;
B
Minor  
Behdad Esfahbod 已提交
770
  for (unsigned int i = 1; i < count; i++)
B
Behdad Esfahbod 已提交
771
  {
772
    if (!skippy_iter.next ()) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
773 774

    match_positions[i] = skippy_iter.idx;
775

B
Behdad Esfahbod 已提交
776 777
    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]);
778 779 780 781 782 783 784 785 786 787 788 789 790 791 792

    if (first_lig_id && first_lig_comp) {
      /* If first component was attached to a previous ligature component,
       * all subsequent components should be attached to the same ligature
       * component, otherwise we shouldn't ligate them. */
      if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
	return TRACE_RETURN (false);
    } else {
      /* 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))
	return TRACE_RETURN (false);
    }

B
Behdad Esfahbod 已提交
793
    is_mark_ligature = is_mark_ligature && _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx]);
B
Behdad Esfahbod 已提交
794
    total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]);
B
Behdad Esfahbod 已提交
795 796
  }

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

799 800 801 802 803 804
  if (p_is_mark_ligature)
    *p_is_mark_ligature = is_mark_ligature;

  if (p_total_component_count)
    *p_total_component_count = total_component_count;

B
Behdad Esfahbod 已提交
805
  return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
806
}
807
static inline void ligate_input (hb_apply_context_t *c,
808 809 810
				 unsigned int count, /* Including the first glyph */
				 unsigned int match_positions[MAX_CONTEXT_LENGTH], /* Including the first glyph */
				 unsigned int match_length,
811 812 813 814
				 hb_codepoint_t lig_glyph,
				 bool is_mark_ligature,
				 unsigned int total_component_count)
{
815 816
  TRACE_APPLY (NULL);

B
Behdad Esfahbod 已提交
817 818 819
  hb_buffer_t *buffer = c->buffer;

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

821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848
  /*
   * - If it *is* a mark ligature, we don't allocate a new ligature id, and leave
   *   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,
   *   and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA wit a
   *   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
   */

849
  unsigned int klass = is_mark_ligature ? 0 : HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
B
Behdad Esfahbod 已提交
850 851 852
  unsigned int lig_id = is_mark_ligature ? 0 : _hb_allocate_lig_id (buffer);
  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());
853 854 855
  unsigned int components_so_far = last_num_components;

  if (!is_mark_ligature)
856
  {
B
Behdad Esfahbod 已提交
857
    _hb_glyph_info_set_lig_props_for_ligature (&buffer->cur(), lig_id, total_component_count);
B
Behdad Esfahbod 已提交
858
    if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
859
    {
B
Behdad Esfahbod 已提交
860
      _hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER);
861 862
      _hb_glyph_info_set_modified_combining_class (&buffer->cur(), 0);
    }
863
  }
864
  c->replace_glyph_with_ligature (lig_glyph, klass);
865 866 867

  for (unsigned int i = 1; i < count; i++)
  {
B
Behdad Esfahbod 已提交
868
    while (buffer->idx < match_positions[i])
869 870 871
    {
      if (!is_mark_ligature) {
	unsigned int new_lig_comp = components_so_far - last_num_components +
B
Behdad Esfahbod 已提交
872 873
				    MIN (MAX (_hb_glyph_info_get_lig_comp (&buffer->cur()), 1u), last_num_components);
	_hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
874
      }
B
Behdad Esfahbod 已提交
875
      buffer->next_glyph ();
876 877
    }

B
Behdad Esfahbod 已提交
878 879
    last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
    last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
880 881 882
    components_so_far += last_num_components;

    /* Skip the base glyph */
B
Behdad Esfahbod 已提交
883
    buffer->idx++;
884 885 886 887
  }

  if (!is_mark_ligature && last_lig_id) {
    /* Re-adjust components for any marks following. */
B
Behdad Esfahbod 已提交
888
    for (unsigned int i = buffer->idx; i < buffer->len; i++) {
B
Behdad Esfahbod 已提交
889
      if (last_lig_id == _hb_glyph_info_get_lig_id (&buffer->info[i])) {
890
	unsigned int new_lig_comp = components_so_far - last_num_components +
B
Behdad Esfahbod 已提交
891 892
				    MIN (MAX (_hb_glyph_info_get_lig_comp (&buffer->info[i]), 1u), last_num_components);
	_hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
893 894 895 896
      } else
	break;
    }
  }
B
Minor  
Behdad Esfahbod 已提交
897
  TRACE_RETURN (true);
898
}
B
Behdad Esfahbod 已提交
899

B
Behdad Esfahbod 已提交
900
static inline bool match_backtrack (hb_apply_context_t *c,
901 902 903
				    unsigned int count,
				    const USHORT backtrack[],
				    match_func_t match_func,
B
Behdad Esfahbod 已提交
904
				    const void *match_data)
905
{
B
Cleanup  
Behdad Esfahbod 已提交
906
  TRACE_APPLY (NULL);
907

908
  hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, c->buffer->backtrack_len (), count, true);
909 910
  skippy_iter.set_match_func (match_func, match_data, backtrack);
  if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
911

912
  for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
913
    if (!skippy_iter.prev ())
914
      return TRACE_RETURN (false);
915

916
  return TRACE_RETURN (true);
917 918
}

B
Behdad Esfahbod 已提交
919
static inline bool match_lookahead (hb_apply_context_t *c,
B
Behdad Esfahbod 已提交
920 921 922
				    unsigned int count,
				    const USHORT lookahead[],
				    match_func_t match_func,
B
Behdad Esfahbod 已提交
923
				    const void *match_data,
B
Behdad Esfahbod 已提交
924
				    unsigned int offset)
925
{
B
Cleanup  
Behdad Esfahbod 已提交
926
  TRACE_APPLY (NULL);
927

928
  hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx + offset - 1, count, true);
929 930
  skippy_iter.set_match_func (match_func, match_data, lookahead);
  if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
931

B
Minor  
Behdad Esfahbod 已提交
932
  for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
933
    if (!skippy_iter.next ())
934
      return TRACE_RETURN (false);
935

936
  return TRACE_RETURN (true);
937 938
}

B
Behdad Esfahbod 已提交
939

940

B
Behdad Esfahbod 已提交
941 942
struct LookupRecord
{
B
Behdad Esfahbod 已提交
943
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
944
    TRACE_SANITIZE (this);
945
    return TRACE_RETURN (c->check_struct (this));
B
Behdad Esfahbod 已提交
946 947
  }

948 949 950 951
  USHORT	sequenceIndex;		/* Index into current glyph
					 * sequence--first glyph = 0 */
  USHORT	lookupListIndex;	/* Lookup to apply to that
					 * position--zero--based */
B
Behdad Esfahbod 已提交
952 953
  public:
  DEFINE_SIZE_STATIC (4);
954 955
};

B
Behdad Esfahbod 已提交
956

957 958 959 960
template <typename context_t>
static inline void recurse_lookups (context_t *c,
				    unsigned int lookupCount,
				    const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
961 962
{
  for (unsigned int i = 0; i < lookupCount; i++)
B
Behdad Esfahbod 已提交
963
    c->recurse (lookupRecord[i].lookupListIndex);
964
}
B
Behdad Esfahbod 已提交
965

B
Behdad Esfahbod 已提交
966
static inline bool apply_lookup (hb_apply_context_t *c,
967
				 unsigned int count, /* Including the first glyph */
968
				 unsigned int match_positions[MAX_CONTEXT_LENGTH], /* Including the first glyph */
969
				 unsigned int lookupCount,
970 971
				 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
				 unsigned int match_length)
972
{
B
Cleanup  
Behdad Esfahbod 已提交
973
  TRACE_APPLY (NULL);
974

975 976
  hb_buffer_t *buffer = c->buffer;
  unsigned int end;
B
Behdad Esfahbod 已提交
977

978 979 980 981 982
  /* All positions are distance from beginning of *output* buffer.
   * Adjust. */
  {
    unsigned int bl = buffer->backtrack_len ();
    end = bl + match_length;
983

984 985 986 987 988
    int delta = bl - buffer->idx;
    /* Convert positions to new indexing. */
    for (unsigned int j = 0; j < count; j++)
      match_positions[j] += delta;
  }
989

990
  for (unsigned int i = 0; i < lookupCount; i++)
B
Behdad Esfahbod 已提交
991
  {
992 993 994
    unsigned int idx = lookupRecord[i].sequenceIndex;
    if (idx >= count)
      continue;
995

996
    buffer->move_to (match_positions[idx]);
997

998 999 1000
    unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
    if (!c->recurse (lookupRecord[i].lookupListIndex))
      continue;
1001

1002 1003
    unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len ();
    int delta = new_len - orig_len;
1004

1005 1006
    if (!delta)
        continue;
1007

1008
    /* Recursed lookup changed buffer len.  Adjust. */
1009

1010 1011 1012
    /* end can't go back past the current match position.
     * Note: this is only true because we do NOT allow MultipleSubst
     * with zero sequence len. */
1013
    end = MAX ((int) match_positions[idx] + 1, int (end) + delta);
1014

1015 1016 1017 1018 1019 1020
    unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */

    if (delta > 0)
    {
      if (unlikely (delta + count > MAX_CONTEXT_LENGTH))
	break;
1021 1022 1023
    }
    else
    {
1024 1025 1026
      /* NOTE: delta is negative. */
      delta = MAX (delta, (int) next - (int) count);
      next -= delta;
1027
    }
1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041

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

1044 1045
  buffer->move_to (end);

B
Behdad Esfahbod 已提交
1046
  return TRACE_RETURN (true);
1047
}
1048

B
Behdad Esfahbod 已提交
1049

1050 1051 1052

/* Contextual lookups */

1053 1054 1055 1056 1057 1058
struct ContextClosureLookupContext
{
  ContextClosureFuncs funcs;
  const void *intersects_data;
};

1059 1060 1061 1062 1063 1064
struct ContextCollectGlyphsLookupContext
{
  ContextCollectGlyphsFuncs funcs;
  const void *collect_data;
};

1065
struct ContextApplyLookupContext
B
Behdad Esfahbod 已提交
1066
{
1067
  ContextApplyFuncs funcs;
B
Behdad Esfahbod 已提交
1068
  const void *match_data;
1069 1070
};

B
Behdad Esfahbod 已提交
1071
static inline void context_closure_lookup (hb_closure_context_t *c,
1072 1073 1074 1075 1076 1077
					   unsigned int inputCount, /* Including the first glyph (not matched) */
					   const USHORT input[], /* Array of input values--start with second glyph */
					   unsigned int lookupCount,
					   const LookupRecord lookupRecord[],
					   ContextClosureLookupContext &lookup_context)
{
B
Behdad Esfahbod 已提交
1078 1079 1080
  if (intersects_array (c,
			inputCount ? inputCount - 1 : 0, input,
			lookup_context.funcs.intersects, lookup_context.intersects_data))
1081 1082
    recurse_lookups (c,
		     lookupCount, lookupRecord);
1083 1084
}

1085 1086 1087 1088 1089 1090 1091
static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
						  unsigned int inputCount, /* Including the first glyph (not matched) */
						  const USHORT input[], /* Array of input values--start with second glyph */
						  unsigned int lookupCount,
						  const LookupRecord lookupRecord[],
						  ContextCollectGlyphsLookupContext &lookup_context)
{
B
Minor  
Behdad Esfahbod 已提交
1092
  collect_array (c, c->input,
1093 1094 1095 1096 1097
		 inputCount ? inputCount - 1 : 0, input,
		 lookup_context.funcs.collect, lookup_context.collect_data);
  recurse_lookups (c,
		   lookupCount, lookupRecord);
}
1098

1099 1100 1101
static inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
					       unsigned int inputCount, /* Including the first glyph (not matched) */
					       const USHORT input[], /* Array of input values--start with second glyph */
B
Behdad Esfahbod 已提交
1102 1103
					       unsigned int lookupCount HB_UNUSED,
					       const LookupRecord lookupRecord[] HB_UNUSED,
1104 1105 1106 1107 1108 1109
					       ContextApplyLookupContext &lookup_context)
{
  return would_match_input (c,
			    inputCount, input,
			    lookup_context.funcs.match, lookup_context.match_data);
}
1110 1111 1112 1113 1114 1115
static inline bool context_apply_lookup (hb_apply_context_t *c,
					 unsigned int inputCount, /* Including the first glyph (not matched) */
					 const USHORT input[], /* Array of input values--start with second glyph */
					 unsigned int lookupCount,
					 const LookupRecord lookupRecord[],
					 ContextApplyLookupContext &lookup_context)
1116
{
1117 1118
  unsigned int match_length = 0;
  unsigned int match_positions[MAX_CONTEXT_LENGTH];
B
Behdad Esfahbod 已提交
1119
  return match_input (c,
B
Behdad Esfahbod 已提交
1120
		      inputCount, input,
1121 1122
		      lookup_context.funcs.match, lookup_context.match_data,
		      &match_length, match_positions)
1123
      && apply_lookup (c,
1124 1125 1126
		       inputCount, match_positions,
		       lookupCount, lookupRecord,
		       match_length);
1127 1128
}

B
Behdad Esfahbod 已提交
1129 1130
struct Rule
{
B
Behdad Esfahbod 已提交
1131
  inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
1132
  {
B
Behdad Esfahbod 已提交
1133
    TRACE_CLOSURE (this);
1134
    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
B
Behdad Esfahbod 已提交
1135 1136 1137 1138
    context_closure_lookup (c,
			    inputCount, input,
			    lookupCount, lookupRecord,
			    lookup_context);
1139 1140
  }

1141 1142 1143 1144 1145 1146 1147 1148 1149 1150
  inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const
  {
    TRACE_COLLECT_GLYPHS (this);
    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
    context_collect_glyphs_lookup (c,
				   inputCount, input,
				   lookupCount, lookupRecord,
				   lookup_context);
  }

1151 1152
  inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
  {
B
Behdad Esfahbod 已提交
1153
    TRACE_WOULD_APPLY (this);
1154 1155 1156 1157
    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
    return TRACE_RETURN (context_would_apply_lookup (c, inputCount, input, lookupCount, lookupRecord, lookup_context));
  }

1158
  inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
B
Behdad Esfahbod 已提交
1159
  {
B
Behdad Esfahbod 已提交
1160
    TRACE_APPLY (this);
B
Behdad Esfahbod 已提交
1161
    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
1162
    return TRACE_RETURN (context_apply_lookup (c, inputCount, input, lookupCount, lookupRecord, lookup_context));
1163 1164
  }

B
Behdad Esfahbod 已提交
1165
  public:
B
Behdad Esfahbod 已提交
1166
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
1167
    TRACE_SANITIZE (this);
B
Behdad Esfahbod 已提交
1168 1169 1170
    return inputCount.sanitize (c)
	&& lookupCount.sanitize (c)
	&& c->check_range (input,
1171 1172
			   input[0].static_size * inputCount
			   + lookupRecordX[0].static_size * lookupCount);
B
Behdad Esfahbod 已提交
1173 1174
  }

1175
  protected:
1176
  USHORT	inputCount;		/* Total number of glyphs in input
1177
					 * glyph sequence--includes the first
1178
					 * glyph */
1179
  USHORT	lookupCount;		/* Number of LookupRecords */
B
Behdad Esfahbod 已提交
1180
  USHORT	input[VAR];		/* Array of match inputs--start with
1181
					 * second glyph */
B
Behdad Esfahbod 已提交
1182
  LookupRecord	lookupRecordX[VAR];	/* Array of LookupRecords--in
1183
					 * design order */
B
Behdad Esfahbod 已提交
1184
  public:
1185
  DEFINE_SIZE_ARRAY2 (4, input, lookupRecordX);
1186 1187
};

B
Behdad Esfahbod 已提交
1188 1189
struct RuleSet
{
B
Behdad Esfahbod 已提交
1190
  inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
1191
  {
B
Behdad Esfahbod 已提交
1192
    TRACE_CLOSURE (this);
1193 1194
    unsigned int num_rules = rule.len;
    for (unsigned int i = 0; i < num_rules; i++)
B
Behdad Esfahbod 已提交
1195
      (this+rule[i]).closure (c, lookup_context);
1196 1197
  }

1198 1199 1200 1201 1202 1203 1204 1205
  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);
  }

1206 1207
  inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
  {
B
Behdad Esfahbod 已提交
1208
    TRACE_WOULD_APPLY (this);
1209 1210 1211 1212 1213 1214 1215 1216 1217
    unsigned int num_rules = rule.len;
    for (unsigned int i = 0; i < num_rules; i++)
    {
      if ((this+rule[i]).would_apply (c, lookup_context))
        return TRACE_RETURN (true);
    }
    return TRACE_RETURN (false);
  }

1218
  inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
B
Behdad Esfahbod 已提交
1219
  {
B
Behdad Esfahbod 已提交
1220
    TRACE_APPLY (this);
1221
    unsigned int num_rules = rule.len;
B
Behdad Esfahbod 已提交
1222 1223
    for (unsigned int i = 0; i < num_rules; i++)
    {
B
Behdad Esfahbod 已提交
1224
      if ((this+rule[i]).apply (c, lookup_context))
1225
        return TRACE_RETURN (true);
1226
    }
1227
    return TRACE_RETURN (false);
1228 1229
  }

B
Behdad Esfahbod 已提交
1230
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
1231
    TRACE_SANITIZE (this);
1232
    return TRACE_RETURN (rule.sanitize (c, this));
B
Behdad Esfahbod 已提交
1233 1234
  }

1235
  protected:
1236
  OffsetArrayOf<Rule>
1237
		rule;			/* Array of Rule tables
1238
					 * ordered by preference */
B
Behdad Esfahbod 已提交
1239
  public:
1240
  DEFINE_SIZE_ARRAY (2, rule);
1241 1242 1243
};


B
Behdad Esfahbod 已提交
1244 1245
struct ContextFormat1
{
1246
  inline void closure (hb_closure_context_t *c) const
1247
  {
B
Behdad Esfahbod 已提交
1248
    TRACE_CLOSURE (this);
1249 1250 1251 1252

    const Coverage &cov = (this+coverage);

    struct ContextClosureLookupContext lookup_context = {
1253
      {intersects_glyph},
1254 1255 1256 1257 1258 1259 1260
      NULL
    };

    unsigned int count = ruleSet.len;
    for (unsigned int i = 0; i < count; i++)
      if (cov.intersects_coverage (c->glyphs, i)) {
	const RuleSet &rule_set = this+ruleSet[i];
B
Behdad Esfahbod 已提交
1261
	rule_set.closure (c, lookup_context);
1262
      }
1263 1264
  }

B
Behdad Esfahbod 已提交
1265 1266
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
1267
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
1268
    (this+coverage).add_coverage (c->input);
1269 1270 1271 1272 1273 1274 1275 1276

    struct ContextCollectGlyphsLookupContext lookup_context = {
      {collect_glyph},
      NULL
    };

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

1280 1281
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1282
    TRACE_WOULD_APPLY (this);
1283

1284
    const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
1285
    struct ContextApplyLookupContext lookup_context = {
1286
      {match_glyph},
1287 1288 1289 1290 1291
      NULL
    };
    return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
  }

1292 1293 1294 1295 1296
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

1297
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1298
  {
B
Behdad Esfahbod 已提交
1299
    TRACE_APPLY (this);
1300
    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
1301
    if (likely (index == NOT_COVERED))
1302
      return TRACE_RETURN (false);
1303

1304
    const RuleSet &rule_set = this+ruleSet[index];
1305
    struct ContextApplyLookupContext lookup_context = {
1306
      {match_glyph},
1307
      NULL
1308
    };
1309
    return TRACE_RETURN (rule_set.apply (c, lookup_context));
1310 1311
  }

B
Behdad Esfahbod 已提交
1312
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
1313
    TRACE_SANITIZE (this);
1314
    return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
1315 1316
  }

1317
  protected:
1318 1319 1320 1321 1322 1323 1324
  USHORT	format;			/* Format identifier--format = 1 */
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
					 * beginning of table */
  OffsetArrayOf<RuleSet>
		ruleSet;		/* Array of RuleSet tables
					 * ordered by Coverage Index */
1325
  public:
1326
  DEFINE_SIZE_ARRAY (6, ruleSet);
1327 1328 1329
};


B
Behdad Esfahbod 已提交
1330 1331
struct ContextFormat2
{
1332
  inline void closure (hb_closure_context_t *c) const
1333
  {
B
Behdad Esfahbod 已提交
1334
    TRACE_CLOSURE (this);
1335
    if (!(this+coverage).intersects (c->glyphs))
B
Behdad Esfahbod 已提交
1336
      return;
1337 1338 1339 1340

    const ClassDef &class_def = this+classDef;

    struct ContextClosureLookupContext lookup_context = {
1341
      {intersects_class},
1342
      &class_def
1343 1344 1345 1346 1347 1348
    };

    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 已提交
1349
	rule_set.closure (c, lookup_context);
1350
      }
1351 1352
  }

B
Behdad Esfahbod 已提交
1353 1354
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
1355
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
1356
    (this+coverage).add_coverage (c->input);
1357

1358
    const ClassDef &class_def = this+classDef;
1359 1360
    struct ContextCollectGlyphsLookupContext lookup_context = {
      {collect_class},
1361
      &class_def
1362 1363 1364 1365
    };

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

1369 1370
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1371
    TRACE_WOULD_APPLY (this);
1372 1373

    const ClassDef &class_def = this+classDef;
1374
    unsigned int index = class_def.get_class (c->glyphs[0]);
1375 1376
    const RuleSet &rule_set = this+ruleSet[index];
    struct ContextApplyLookupContext lookup_context = {
1377
      {match_class},
1378 1379 1380 1381 1382
      &class_def
    };
    return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
  }

1383 1384 1385 1386 1387
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

1388
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1389
  {
B
Behdad Esfahbod 已提交
1390
    TRACE_APPLY (this);
1391
    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
1392
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
1393 1394

    const ClassDef &class_def = this+classDef;
1395
    index = class_def.get_class (c->buffer->cur().codepoint);
1396
    const RuleSet &rule_set = this+ruleSet[index];
1397
    struct ContextApplyLookupContext lookup_context = {
1398
      {match_class},
B
Behdad Esfahbod 已提交
1399
      &class_def
1400
    };
1401
    return TRACE_RETURN (rule_set.apply (c, lookup_context));
1402 1403
  }

B
Behdad Esfahbod 已提交
1404
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
1405
    TRACE_SANITIZE (this);
1406
    return TRACE_RETURN (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
1407 1408
  }

1409
  protected:
1410 1411 1412 1413 1414 1415 1416 1417 1418 1419
  USHORT	format;			/* Format identifier--format = 2 */
  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 */
1420
  public:
1421
  DEFINE_SIZE_ARRAY (8, ruleSet);
1422 1423 1424
};


B
Behdad Esfahbod 已提交
1425 1426
struct ContextFormat3
{
1427
  inline void closure (hb_closure_context_t *c) const
1428
  {
B
Behdad Esfahbod 已提交
1429
    TRACE_CLOSURE (this);
1430
    if (!(this+coverage[0]).intersects (c->glyphs))
B
Behdad Esfahbod 已提交
1431
      return;
1432 1433 1434

    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
    struct ContextClosureLookupContext lookup_context = {
1435
      {intersects_coverage},
1436 1437
      this
    };
B
Behdad Esfahbod 已提交
1438 1439 1440 1441
    context_closure_lookup (c,
			    glyphCount, (const USHORT *) (coverage + 1),
			    lookupCount, lookupRecord,
			    lookup_context);
1442 1443
  }

B
Behdad Esfahbod 已提交
1444 1445
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
1446
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
1447
    (this+coverage[0]).add_coverage (c->input);
1448 1449 1450 1451

    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
    struct ContextCollectGlyphsLookupContext lookup_context = {
      {collect_coverage},
1452
      this
1453 1454 1455 1456 1457 1458
    };

    context_collect_glyphs_lookup (c,
				   glyphCount, (const USHORT *) (coverage + 1),
				   lookupCount, lookupRecord,
				   lookup_context);
B
Behdad Esfahbod 已提交
1459 1460
  }

1461 1462
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1463
    TRACE_WOULD_APPLY (this);
1464 1465 1466

    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
    struct ContextApplyLookupContext lookup_context = {
1467
      {match_coverage},
1468 1469 1470 1471 1472
      this
    };
    return TRACE_RETURN (context_would_apply_lookup (c, glyphCount, (const USHORT *) (coverage + 1), lookupCount, lookupRecord, lookup_context));
  }

1473 1474 1475 1476 1477
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage[0];
  }

1478
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1479
  {
B
Behdad Esfahbod 已提交
1480
    TRACE_APPLY (this);
1481
    unsigned int index = (this+coverage[0]).get_coverage (c->buffer->cur().codepoint);
1482
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
1483

B
Behdad Esfahbod 已提交
1484
    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
1485
    struct ContextApplyLookupContext lookup_context = {
1486
      {match_coverage},
B
Behdad Esfahbod 已提交
1487
      this
1488
    };
1489
    return TRACE_RETURN (context_apply_lookup (c, glyphCount, (const USHORT *) (coverage + 1), lookupCount, lookupRecord, lookup_context));
1490 1491
  }

B
Behdad Esfahbod 已提交
1492
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
1493
    TRACE_SANITIZE (this);
1494
    if (!c->check_struct (this)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1495
    unsigned int count = glyphCount;
1496
    if (!c->check_array (coverage, coverage[0].static_size, count)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1497
    for (unsigned int i = 0; i < count; i++)
1498
      if (!coverage[i].sanitize (c, this)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1499
    LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * count);
1500
    return TRACE_RETURN (c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount));
B
Behdad Esfahbod 已提交
1501 1502
  }

1503
  protected:
1504 1505 1506
  USHORT	format;			/* Format identifier--format = 3 */
  USHORT	glyphCount;		/* Number of glyphs in the input glyph
					 * sequence */
1507
  USHORT	lookupCount;		/* Number of LookupRecords */
1508
  OffsetTo<Coverage>
B
Behdad Esfahbod 已提交
1509
		coverage[VAR];		/* Array of offsets to Coverage
1510
					 * table in glyph sequence order */
B
Behdad Esfahbod 已提交
1511
  LookupRecord	lookupRecordX[VAR];	/* Array of LookupRecords--in
1512
					 * design order */
B
Behdad Esfahbod 已提交
1513
  public:
1514
  DEFINE_SIZE_ARRAY2 (6, coverage, lookupRecordX);
1515 1516
};

B
Behdad Esfahbod 已提交
1517 1518
struct Context
{
1519
  template <typename context_t>
1520
  inline typename context_t::return_t dispatch (context_t *c) const
1521
  {
1522
    TRACE_DISPATCH (this);
1523
    switch (u.format) {
1524 1525 1526
    case 1: return TRACE_RETURN (c->dispatch (u.format1));
    case 2: return TRACE_RETURN (c->dispatch (u.format2));
    case 3: return TRACE_RETURN (c->dispatch (u.format3));
B
Behdad Esfahbod 已提交
1527
    default:return TRACE_RETURN (c->default_return_value ());
1528 1529 1530
    }
  }

B
Behdad Esfahbod 已提交
1531
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
1532
    TRACE_SANITIZE (this);
1533
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1534
    switch (u.format) {
1535 1536 1537 1538
    case 1: return TRACE_RETURN (u.format1.sanitize (c));
    case 2: return TRACE_RETURN (u.format2.sanitize (c));
    case 3: return TRACE_RETURN (u.format3.sanitize (c));
    default:return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
1539 1540 1541
    }
  }

1542
  protected:
1543
  union {
B
Behdad Esfahbod 已提交
1544
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1545 1546 1547
  ContextFormat1	format1;
  ContextFormat2	format2;
  ContextFormat3	format3;
1548 1549 1550
  } u;
};

1551 1552 1553

/* Chaining Contextual lookups */

1554
struct ChainContextClosureLookupContext
B
Behdad Esfahbod 已提交
1555
{
1556 1557 1558 1559
  ContextClosureFuncs funcs;
  const void *intersects_data[3];
};

1560 1561 1562 1563 1564 1565
struct ChainContextCollectGlyphsLookupContext
{
  ContextCollectGlyphsFuncs funcs;
  const void *collect_data[3];
};

1566 1567 1568
struct ChainContextApplyLookupContext
{
  ContextApplyFuncs funcs;
B
Behdad Esfahbod 已提交
1569
  const void *match_data[3];
1570 1571
};

B
Behdad Esfahbod 已提交
1572
static inline void chain_context_closure_lookup (hb_closure_context_t *c,
1573 1574 1575 1576 1577 1578 1579 1580 1581 1582
						 unsigned int backtrackCount,
						 const USHORT backtrack[],
						 unsigned int inputCount, /* Including the first glyph (not matched) */
						 const USHORT input[], /* Array of input values--start with second glyph */
						 unsigned int lookaheadCount,
						 const USHORT lookahead[],
						 unsigned int lookupCount,
						 const LookupRecord lookupRecord[],
						 ChainContextClosureLookupContext &lookup_context)
{
B
Behdad Esfahbod 已提交
1583 1584 1585 1586 1587 1588
  if (intersects_array (c,
			backtrackCount, backtrack,
			lookup_context.funcs.intersects, lookup_context.intersects_data[0])
   && intersects_array (c,
			inputCount ? inputCount - 1 : 0, input,
			lookup_context.funcs.intersects, lookup_context.intersects_data[1])
B
Minor  
Behdad Esfahbod 已提交
1589
   && intersects_array (c,
B
Behdad Esfahbod 已提交
1590 1591
		       lookaheadCount, lookahead,
		       lookup_context.funcs.intersects, lookup_context.intersects_data[2]))
1592 1593
    recurse_lookups (c,
		     lookupCount, lookupRecord);
1594 1595
}

1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606
static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
						        unsigned int backtrackCount,
						        const USHORT backtrack[],
						        unsigned int inputCount, /* Including the first glyph (not matched) */
						        const USHORT input[], /* Array of input values--start with second glyph */
						        unsigned int lookaheadCount,
						        const USHORT lookahead[],
						        unsigned int lookupCount,
						        const LookupRecord lookupRecord[],
						        ChainContextCollectGlyphsLookupContext &lookup_context)
{
B
Minor  
Behdad Esfahbod 已提交
1607
  collect_array (c, c->before,
1608 1609
		 backtrackCount, backtrack,
		 lookup_context.funcs.collect, lookup_context.collect_data[0]);
B
Minor  
Behdad Esfahbod 已提交
1610
  collect_array (c, c->input,
1611 1612
		 inputCount ? inputCount - 1 : 0, input,
		 lookup_context.funcs.collect, lookup_context.collect_data[1]);
B
Minor  
Behdad Esfahbod 已提交
1613
  collect_array (c, c->after,
1614 1615 1616 1617 1618 1619
		 lookaheadCount, lookahead,
		 lookup_context.funcs.collect, lookup_context.collect_data[2]);
  recurse_lookups (c,
		   lookupCount, lookupRecord);
}

1620 1621
static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c,
						     unsigned int backtrackCount,
B
Behdad Esfahbod 已提交
1622
						     const USHORT backtrack[] HB_UNUSED,
1623 1624 1625
						     unsigned int inputCount, /* Including the first glyph (not matched) */
						     const USHORT input[], /* Array of input values--start with second glyph */
						     unsigned int lookaheadCount,
B
Behdad Esfahbod 已提交
1626 1627 1628
						     const USHORT lookahead[] HB_UNUSED,
						     unsigned int lookupCount HB_UNUSED,
						     const LookupRecord lookupRecord[] HB_UNUSED,
1629 1630
						     ChainContextApplyLookupContext &lookup_context)
{
1631
  return (c->zero_context ? !backtrackCount && !lookaheadCount : true)
1632
      && would_match_input (c,
1633 1634 1635 1636
			    inputCount, input,
			    lookup_context.funcs.match, lookup_context.match_data[1]);
}

1637 1638 1639 1640 1641 1642 1643 1644 1645 1646
static inline bool chain_context_apply_lookup (hb_apply_context_t *c,
					       unsigned int backtrackCount,
					       const USHORT backtrack[],
					       unsigned int inputCount, /* Including the first glyph (not matched) */
					       const USHORT input[], /* Array of input values--start with second glyph */
					       unsigned int lookaheadCount,
					       const USHORT lookahead[],
					       unsigned int lookupCount,
					       const LookupRecord lookupRecord[],
					       ChainContextApplyLookupContext &lookup_context)
1647
{
1648 1649
  unsigned int match_length = 0;
  unsigned int match_positions[MAX_CONTEXT_LENGTH];
B
Behdad Esfahbod 已提交
1650
  return match_input (c,
B
Behdad Esfahbod 已提交
1651 1652
		      inputCount, input,
		      lookup_context.funcs.match, lookup_context.match_data[1],
1653
		      &match_length, match_positions)
B
Behdad Esfahbod 已提交
1654 1655 1656
      && match_backtrack (c,
			  backtrackCount, backtrack,
			  lookup_context.funcs.match, lookup_context.match_data[0])
B
Behdad Esfahbod 已提交
1657
      && match_lookahead (c,
B
Behdad Esfahbod 已提交
1658 1659
			  lookaheadCount, lookahead,
			  lookup_context.funcs.match, lookup_context.match_data[2],
1660
			  match_length)
1661
      && apply_lookup (c,
1662 1663 1664
		       inputCount, match_positions,
		       lookupCount, lookupRecord,
		       match_length);
1665
}
1666

B
Behdad Esfahbod 已提交
1667 1668
struct ChainRule
{
B
Behdad Esfahbod 已提交
1669
  inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
1670
  {
B
Behdad Esfahbod 已提交
1671
    TRACE_CLOSURE (this);
1672 1673 1674
    const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
    const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
B
Behdad Esfahbod 已提交
1675 1676 1677 1678 1679 1680
    chain_context_closure_lookup (c,
				  backtrack.len, backtrack.array,
				  input.len, input.array,
				  lookahead.len, lookahead.array,
				  lookup.len, lookup.array,
				  lookup_context);
1681 1682
  }

1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696
  inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
  {
    TRACE_COLLECT_GLYPHS (this);
    const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
    const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
    chain_context_collect_glyphs_lookup (c,
					 backtrack.len, backtrack.array,
					 input.len, input.array,
					 lookahead.len, lookahead.array,
					 lookup.len, lookup.array,
					 lookup_context);
  }

1697 1698
  inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
  {
B
Behdad Esfahbod 已提交
1699
    TRACE_WOULD_APPLY (this);
1700 1701 1702 1703 1704 1705 1706 1707 1708 1709
    const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
    const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
    return TRACE_RETURN (chain_context_would_apply_lookup (c,
							   backtrack.len, backtrack.array,
							   input.len, input.array,
							   lookahead.len, lookahead.array, lookup.len,
							   lookup.array, lookup_context));
  }

1710
  inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
B
Behdad Esfahbod 已提交
1711
  {
B
Behdad Esfahbod 已提交
1712
    TRACE_APPLY (this);
1713 1714 1715
    const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
    const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1716 1717 1718 1719 1720
    return TRACE_RETURN (chain_context_apply_lookup (c,
						     backtrack.len, backtrack.array,
						     input.len, input.array,
						     lookahead.len, lookahead.array, lookup.len,
						     lookup.array, lookup_context));
1721 1722
  }

B
Behdad Esfahbod 已提交
1723
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
1724
    TRACE_SANITIZE (this);
1725
    if (!backtrack.sanitize (c)) return TRACE_RETURN (false);
1726
    HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
1727
    if (!input.sanitize (c)) return TRACE_RETURN (false);
1728
    ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
1729
    if (!lookahead.sanitize (c)) return TRACE_RETURN (false);
1730
    ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1731
    return TRACE_RETURN (lookup.sanitize (c));
B
Behdad Esfahbod 已提交
1732
  }
1733

1734
  protected:
B
Behdad Esfahbod 已提交
1735 1736
  ArrayOf<USHORT>
		backtrack;		/* Array of backtracking values
1737 1738
					 * (to be matched before the input
					 * sequence) */
B
Behdad Esfahbod 已提交
1739 1740
  HeadlessArrayOf<USHORT>
		inputX;			/* Array of input values (start with
1741
					 * second glyph) */
B
Behdad Esfahbod 已提交
1742 1743
  ArrayOf<USHORT>
		lookaheadX;		/* Array of lookahead values's (to be
1744
					 * matched after the input sequence) */
B
Behdad Esfahbod 已提交
1745
  ArrayOf<LookupRecord>
1746
		lookupX;		/* Array of LookupRecords--in
1747
					 * design order) */
1748
  public:
B
Behdad Esfahbod 已提交
1749
  DEFINE_SIZE_MIN (8);
1750 1751
};

B
Behdad Esfahbod 已提交
1752 1753
struct ChainRuleSet
{
B
Behdad Esfahbod 已提交
1754
  inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
1755
  {
B
Behdad Esfahbod 已提交
1756
    TRACE_CLOSURE (this);
1757 1758
    unsigned int num_rules = rule.len;
    for (unsigned int i = 0; i < num_rules; i++)
B
Behdad Esfahbod 已提交
1759
      (this+rule[i]).closure (c, lookup_context);
1760 1761
  }

1762 1763 1764 1765 1766 1767 1768 1769
  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);
  }

1770 1771
  inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
  {
B
Behdad Esfahbod 已提交
1772
    TRACE_WOULD_APPLY (this);
1773 1774 1775 1776 1777 1778 1779 1780
    unsigned int num_rules = rule.len;
    for (unsigned int i = 0; i < num_rules; i++)
      if ((this+rule[i]).would_apply (c, lookup_context))
        return TRACE_RETURN (true);

    return TRACE_RETURN (false);
  }

1781
  inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
B
Behdad Esfahbod 已提交
1782
  {
B
Behdad Esfahbod 已提交
1783
    TRACE_APPLY (this);
1784
    unsigned int num_rules = rule.len;
B
Behdad Esfahbod 已提交
1785
    for (unsigned int i = 0; i < num_rules; i++)
B
Behdad Esfahbod 已提交
1786
      if ((this+rule[i]).apply (c, lookup_context))
1787
        return TRACE_RETURN (true);
1788

1789
    return TRACE_RETURN (false);
1790
  }
1791

B
Behdad Esfahbod 已提交
1792
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
1793
    TRACE_SANITIZE (this);
1794
    return TRACE_RETURN (rule.sanitize (c, this));
B
Behdad Esfahbod 已提交
1795 1796
  }

1797
  protected:
1798 1799 1800
  OffsetArrayOf<ChainRule>
		rule;			/* Array of ChainRule tables
					 * ordered by preference */
1801
  public:
1802
  DEFINE_SIZE_ARRAY (2, rule);
1803 1804
};

B
Behdad Esfahbod 已提交
1805 1806
struct ChainContextFormat1
{
1807
  inline void closure (hb_closure_context_t *c) const
1808
  {
B
Behdad Esfahbod 已提交
1809
    TRACE_CLOSURE (this);
1810 1811 1812
    const Coverage &cov = (this+coverage);

    struct ChainContextClosureLookupContext lookup_context = {
1813
      {intersects_glyph},
1814 1815 1816 1817 1818 1819 1820
      {NULL, NULL, NULL}
    };

    unsigned int count = ruleSet.len;
    for (unsigned int i = 0; i < count; i++)
      if (cov.intersects_coverage (c->glyphs, i)) {
	const ChainRuleSet &rule_set = this+ruleSet[i];
B
Behdad Esfahbod 已提交
1821
	rule_set.closure (c, lookup_context);
1822
      }
1823 1824
  }

B
Behdad Esfahbod 已提交
1825 1826
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
1827
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
1828
    (this+coverage).add_coverage (c->input);
1829 1830 1831 1832 1833 1834 1835 1836 1837

    struct ChainContextCollectGlyphsLookupContext lookup_context = {
      {collect_glyph},
      {NULL, NULL, NULL}
    };

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

1840 1841
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1842
    TRACE_WOULD_APPLY (this);
1843

1844
    const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
1845
    struct ChainContextApplyLookupContext lookup_context = {
1846
      {match_glyph},
1847 1848 1849 1850 1851
      {NULL, NULL, NULL}
    };
    return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
  }

1852 1853 1854 1855 1856
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

1857
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1858
  {
B
Behdad Esfahbod 已提交
1859
    TRACE_APPLY (this);
1860
    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
1861
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
1862

1863
    const ChainRuleSet &rule_set = this+ruleSet[index];
1864
    struct ChainContextApplyLookupContext lookup_context = {
1865
      {match_glyph},
1866 1867
      {NULL, NULL, NULL}
    };
1868
    return TRACE_RETURN (rule_set.apply (c, lookup_context));
1869
  }
B
Behdad Esfahbod 已提交
1870

B
Behdad Esfahbod 已提交
1871
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
1872
    TRACE_SANITIZE (this);
1873
    return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
1874 1875
  }

1876
  protected:
1877
  USHORT	format;			/* Format identifier--format = 1 */
1878 1879
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
1880
					 * beginning of table */
1881 1882 1883
  OffsetArrayOf<ChainRuleSet>
		ruleSet;		/* Array of ChainRuleSet tables
					 * ordered by Coverage Index */
1884
  public:
1885
  DEFINE_SIZE_ARRAY (6, ruleSet);
1886 1887
};

B
Behdad Esfahbod 已提交
1888 1889
struct ChainContextFormat2
{
1890
  inline void closure (hb_closure_context_t *c) const
1891
  {
B
Behdad Esfahbod 已提交
1892
    TRACE_CLOSURE (this);
1893
    if (!(this+coverage).intersects (c->glyphs))
B
Behdad Esfahbod 已提交
1894
      return;
1895 1896 1897 1898 1899 1900

    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 = {
1901
      {intersects_class},
1902 1903 1904 1905 1906 1907 1908 1909 1910
      {&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 已提交
1911
	rule_set.closure (c, lookup_context);
1912
      }
1913 1914
  }

B
Behdad Esfahbod 已提交
1915 1916
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
1917
    TRACE_COLLECT_GLYPHS (this);
B
Minor  
Behdad Esfahbod 已提交
1918
    (this+coverage).add_coverage (c->input);
1919

1920 1921 1922 1923
    const ClassDef &backtrack_class_def = this+backtrackClassDef;
    const ClassDef &input_class_def = this+inputClassDef;
    const ClassDef &lookahead_class_def = this+lookaheadClassDef;

1924 1925
    struct ChainContextCollectGlyphsLookupContext lookup_context = {
      {collect_class},
1926 1927 1928
      {&backtrack_class_def,
       &input_class_def,
       &lookahead_class_def}
1929 1930 1931 1932 1933
    };

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

1936 1937
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
1938
    TRACE_WOULD_APPLY (this);
1939

1940
    const ClassDef &backtrack_class_def = this+backtrackClassDef;
1941
    const ClassDef &input_class_def = this+inputClassDef;
1942
    const ClassDef &lookahead_class_def = this+lookaheadClassDef;
1943

1944
    unsigned int index = input_class_def.get_class (c->glyphs[0]);
1945 1946
    const ChainRuleSet &rule_set = this+ruleSet[index];
    struct ChainContextApplyLookupContext lookup_context = {
1947
      {match_class},
1948 1949 1950
      {&backtrack_class_def,
       &input_class_def,
       &lookahead_class_def}
1951 1952 1953 1954
    };
    return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
  }

1955 1956 1957 1958 1959
  inline const Coverage &get_coverage (void) const
  {
    return this+coverage;
  }

1960
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
1961
  {
B
Behdad Esfahbod 已提交
1962
    TRACE_APPLY (this);
1963
    unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
1964
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
1965 1966 1967 1968 1969

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

1970
    index = input_class_def.get_class (c->buffer->cur().codepoint);
1971
    const ChainRuleSet &rule_set = this+ruleSet[index];
1972
    struct ChainContextApplyLookupContext lookup_context = {
1973
      {match_class},
B
Behdad Esfahbod 已提交
1974 1975 1976
      {&backtrack_class_def,
       &input_class_def,
       &lookahead_class_def}
1977
    };
1978
    return TRACE_RETURN (rule_set.apply (c, lookup_context));
1979 1980
  }

B
Behdad Esfahbod 已提交
1981
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
1982
    TRACE_SANITIZE (this);
1983 1984 1985
    return TRACE_RETURN (coverage.sanitize (c, this) && backtrackClassDef.sanitize (c, this) &&
			 inputClassDef.sanitize (c, this) && lookaheadClassDef.sanitize (c, this) &&
			 ruleSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
1986 1987
  }

1988
  protected:
1989
  USHORT	format;			/* Format identifier--format = 2 */
1990 1991
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
1992
					 * beginning of table */
1993 1994
  OffsetTo<ClassDef>
		backtrackClassDef;	/* Offset to glyph ClassDef table
1995 1996
					 * containing backtrack sequence
					 * data--from beginning of table */
1997 1998
  OffsetTo<ClassDef>
		inputClassDef;		/* Offset to glyph ClassDef
1999 2000
					 * table containing input sequence
					 * data--from beginning of table */
2001 2002
  OffsetTo<ClassDef>
		lookaheadClassDef;	/* Offset to glyph ClassDef table
2003 2004
					 * containing lookahead sequence
					 * data--from beginning of table */
2005 2006 2007
  OffsetArrayOf<ChainRuleSet>
		ruleSet;		/* Array of ChainRuleSet tables
					 * ordered by class */
2008
  public:
2009
  DEFINE_SIZE_ARRAY (12, ruleSet);
2010 2011
};

B
Behdad Esfahbod 已提交
2012 2013
struct ChainContextFormat3
{
2014
  inline void closure (hb_closure_context_t *c) const
2015
  {
B
Behdad Esfahbod 已提交
2016
    TRACE_CLOSURE (this);
B
Behdad Esfahbod 已提交
2017 2018 2019 2020 2021 2022 2023 2024
    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 = {
2025
      {intersects_coverage},
B
Behdad Esfahbod 已提交
2026 2027 2028 2029 2030 2031 2032 2033
      {this, this, this}
    };
    chain_context_closure_lookup (c,
				  backtrack.len, (const USHORT *) backtrack.array,
				  input.len, (const USHORT *) input.array + 1,
				  lookahead.len, (const USHORT *) lookahead.array,
				  lookup.len, lookup.array,
				  lookup_context);
2034 2035
  }

B
Behdad Esfahbod 已提交
2036 2037
  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  {
2038 2039 2040
    TRACE_COLLECT_GLYPHS (this);
    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);

B
Minor  
Behdad Esfahbod 已提交
2041
    (this+input[0]).add_coverage (c->input);
2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054

    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,
					 backtrack.len, (const USHORT *) backtrack.array,
					 input.len, (const USHORT *) input.array + 1,
					 lookahead.len, (const USHORT *) lookahead.array,
					 lookup.len, lookup.array,
					 lookup_context);
B
Behdad Esfahbod 已提交
2055 2056
  }

2057 2058
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
B
Behdad Esfahbod 已提交
2059
    TRACE_WOULD_APPLY (this);
2060

B
Behdad Esfahbod 已提交
2061
    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2062 2063 2064
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
    struct ChainContextApplyLookupContext lookup_context = {
2065
      {match_coverage},
2066 2067 2068 2069 2070 2071 2072 2073 2074
      {this, this, this}
    };
    return TRACE_RETURN (chain_context_would_apply_lookup (c,
							   backtrack.len, (const USHORT *) backtrack.array,
							   input.len, (const USHORT *) input.array + 1,
							   lookahead.len, (const USHORT *) lookahead.array,
							   lookup.len, lookup.array, lookup_context));
  }

2075 2076 2077 2078 2079 2080
  inline const Coverage &get_coverage (void) const
  {
    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
    return this+input[0];
  }

2081
  inline bool apply (hb_apply_context_t *c) const
B
Behdad Esfahbod 已提交
2082
  {
B
Behdad Esfahbod 已提交
2083
    TRACE_APPLY (this);
2084
    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2085

2086
    unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint);
2087
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
2088

2089 2090
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2091
    struct ChainContextApplyLookupContext lookup_context = {
2092
      {match_coverage},
B
Behdad Esfahbod 已提交
2093
      {this, this, this}
2094
    };
2095 2096 2097 2098 2099
    return TRACE_RETURN (chain_context_apply_lookup (c,
						     backtrack.len, (const USHORT *) backtrack.array,
						     input.len, (const USHORT *) input.array + 1,
						     lookahead.len, (const USHORT *) lookahead.array,
						     lookup.len, lookup.array, lookup_context));
2100 2101
  }

B
Behdad Esfahbod 已提交
2102
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
2103
    TRACE_SANITIZE (this);
2104
    if (!backtrack.sanitize (c, this)) return TRACE_RETURN (false);
2105
    OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2106
    if (!input.sanitize (c, this)) return TRACE_RETURN (false);
2107
    OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2108
    if (!lookahead.sanitize (c, this)) return TRACE_RETURN (false);
2109
    ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2110
    return TRACE_RETURN (lookup.sanitize (c));
B
Behdad Esfahbod 已提交
2111 2112
  }

2113
  protected:
2114
  USHORT	format;			/* Format identifier--format = 3 */
B
Behdad Esfahbod 已提交
2115
  OffsetArrayOf<Coverage>
2116
		backtrack;		/* Array of coverage tables
2117 2118
					 * in backtracking sequence, in  glyph
					 * sequence order */
B
Behdad Esfahbod 已提交
2119
  OffsetArrayOf<Coverage>
2120
		inputX		;	/* Array of coverage
2121 2122
					 * tables in input sequence, in glyph
					 * sequence order */
B
Behdad Esfahbod 已提交
2123
  OffsetArrayOf<Coverage>
2124
		lookaheadX;		/* Array of coverage tables
2125 2126
					 * in lookahead sequence, in glyph
					 * sequence order */
B
Behdad Esfahbod 已提交
2127
  ArrayOf<LookupRecord>
2128
		lookupX;		/* Array of LookupRecords--in
B
Behdad Esfahbod 已提交
2129
					 * design order) */
2130
  public:
B
Behdad Esfahbod 已提交
2131
  DEFINE_SIZE_MIN (10);
2132 2133
};

B
Behdad Esfahbod 已提交
2134 2135
struct ChainContext
{
2136
  template <typename context_t>
2137
  inline typename context_t::return_t dispatch (context_t *c) const
2138
  {
2139
    TRACE_DISPATCH (this);
2140
    switch (u.format) {
2141 2142 2143
    case 1: return TRACE_RETURN (c->dispatch (u.format1));
    case 2: return TRACE_RETURN (c->dispatch (u.format2));
    case 3: return TRACE_RETURN (c->dispatch (u.format3));
B
Behdad Esfahbod 已提交
2144
    default:return TRACE_RETURN (c->default_return_value ());
2145 2146 2147
    }
  }

B
Behdad Esfahbod 已提交
2148
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
2149
    TRACE_SANITIZE (this);
2150
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
2151
    switch (u.format) {
2152 2153 2154 2155
    case 1: return TRACE_RETURN (u.format1.sanitize (c));
    case 2: return TRACE_RETURN (u.format2.sanitize (c));
    case 3: return TRACE_RETURN (u.format3.sanitize (c));
    default:return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
2156 2157 2158
    }
  }

2159
  protected:
2160 2161
  union {
  USHORT		format;	/* Format identifier */
B
Behdad Esfahbod 已提交
2162 2163 2164
  ChainContextFormat1	format1;
  ChainContextFormat2	format2;
  ChainContextFormat3	format3;
2165 2166 2167 2168
  } u;
};


2169 2170 2171
struct ExtensionFormat1
{
  inline unsigned int get_type (void) const { return extensionLookupType; }
B
Behdad Esfahbod 已提交
2172
  inline unsigned int get_offset (void) const { return extensionOffset; }
2173

B
Behdad Esfahbod 已提交
2174
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
2175
    TRACE_SANITIZE (this);
2176
    return TRACE_RETURN (c->check_struct (this));
B
Behdad Esfahbod 已提交
2177 2178
  }

2179
  protected:
2180 2181 2182 2183
  USHORT	format;			/* Format identifier. Set to 1. */
  USHORT	extensionLookupType;	/* Lookup type of subtable referenced
					 * by ExtensionOffset (i.e. the
					 * extension subtable). */
2184 2185
  ULONG		extensionOffset;	/* Offset to the extension subtable,
					 * of lookup type subtable. */
2186 2187
  public:
  DEFINE_SIZE_STATIC (8);
2188 2189
};

B
Behdad Esfahbod 已提交
2190
template <typename T>
2191 2192 2193 2194 2195
struct Extension
{
  inline unsigned int get_type (void) const
  {
    switch (u.format) {
B
Behdad Esfahbod 已提交
2196
    case 1: return u.format1.get_type ();
2197 2198 2199
    default:return 0;
    }
  }
B
Behdad Esfahbod 已提交
2200
  inline unsigned int get_offset (void) const
2201 2202
  {
    switch (u.format) {
B
Behdad Esfahbod 已提交
2203
    case 1: return u.format1.get_offset ();
B
Behdad Esfahbod 已提交
2204
    default:return 0;
2205 2206 2207
    }
  }

2208 2209 2210 2211 2212 2213 2214 2215
  template <typename X>
  inline const X& get_subtable (void) const
  {
    unsigned int offset = get_offset ();
    if (unlikely (!offset)) return Null(typename T::LookupSubTable);
    return StructAtOffset<typename T::LookupSubTable> (this, offset);
  }

B
Behdad Esfahbod 已提交
2216
  template <typename context_t>
2217
  inline typename context_t::return_t dispatch (context_t *c) const
B
Behdad Esfahbod 已提交
2218
  {
2219
    return get_subtable<typename T::LookupSubTable> ().dispatch (c, get_type ());
B
Behdad Esfahbod 已提交
2220 2221
  }

2222
  inline bool sanitize_self (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
2223
    TRACE_SANITIZE (this);
2224
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
2225
    switch (u.format) {
2226 2227
    case 1: return TRACE_RETURN (u.format1.sanitize (c));
    default:return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
2228 2229 2230
    }
  }

2231 2232 2233 2234 2235 2236 2237 2238
  inline bool sanitize (hb_sanitize_context_t *c) {
    TRACE_SANITIZE (this);
    if (!sanitize_self (c)) return TRACE_RETURN (false);
    unsigned int offset = get_offset ();
    if (unlikely (!offset)) return TRACE_RETURN (true);
    return TRACE_RETURN (StructAtOffset<typename T::LookupSubTable> (this, offset).sanitize (c, get_type ()));
  }

2239
  protected:
2240 2241
  union {
  USHORT		format;		/* Format identifier */
2242
  ExtensionFormat1	format1;
2243 2244 2245 2246
  } u;
};


B
Behdad Esfahbod 已提交
2247 2248 2249 2250
/*
 * GSUB/GPOS Common
 */

B
Behdad Esfahbod 已提交
2251 2252
struct GSUBGPOS
{
B
Behdad Esfahbod 已提交
2253 2254
  static const hb_tag_t GSUBTag	= HB_OT_TAG_GSUB;
  static const hb_tag_t GPOSTag	= HB_OT_TAG_GPOS;
B
Behdad Esfahbod 已提交
2255

2256 2257 2258 2259
  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 已提交
2260 2261 2262 2263
  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); }
2264 2265 2266 2267 2268 2269 2270 2271 2272
  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; }
  inline const Tag& get_feature_tag (unsigned int i) const
  { return (this+featureList).get_tag (i); }
B
Behdad Esfahbod 已提交
2273 2274 2275 2276
  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); }
2277 2278 2279 2280 2281 2282 2283 2284 2285
  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 已提交
2286

B
Behdad Esfahbod 已提交
2287
  inline bool sanitize (hb_sanitize_context_t *c) {
B
Behdad Esfahbod 已提交
2288
    TRACE_SANITIZE (this);
2289 2290 2291 2292
    return TRACE_RETURN (version.sanitize (c) && likely (version.major == 1) &&
			 scriptList.sanitize (c, this) &&
			 featureList.sanitize (c, this) &&
			 lookupList.sanitize (c, this));
B
Behdad Esfahbod 已提交
2293 2294
  }

2295
  protected:
B
Behdad Esfahbod 已提交
2296
  FixedVersion	version;	/* Version of the GSUB/GPOS table--initially set
B
Behdad Esfahbod 已提交
2297 2298 2299 2300 2301 2302 2303
				 * to 0x00010000 */
  OffsetTo<ScriptList>
		scriptList;  	/* ScriptList table */
  OffsetTo<FeatureList>
		featureList; 	/* FeatureList table */
  OffsetTo<LookupList>
		lookupList; 	/* LookupList table */
2304 2305
  public:
  DEFINE_SIZE_STATIC (10);
B
Behdad Esfahbod 已提交
2306
};
2307

2308

B
Behdad Esfahbod 已提交
2309
} /* namespace OT */
2310

B
Behdad Esfahbod 已提交
2311

2312
#endif /* HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH */