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

29 30
#ifndef HB_OT_LAYOUT_GSUBGPOS_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 42 43 44
#ifndef HB_DEBUG_CLOSURE
#define HB_DEBUG_CLOSURE (HB_DEBUG+0)
#endif

#define TRACE_CLOSURE() \
45
	hb_auto_trace_t<HB_DEBUG_CLOSURE> trace (&c->debug_depth, "CLOSURE", this, HB_FUNC, "");
46 47 48 49 50


struct hb_closure_context_t
{
  hb_face_t *face;
51
  hb_set_t *glyphs;
52 53 54 55 56
  unsigned int nesting_level_left;
  unsigned int debug_depth;


  hb_closure_context_t (hb_face_t *face_,
57
			hb_set_t *glyphs_,
58
		        unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) :
59 60
			  face (face_),
			  glyphs (glyphs_),
61 62 63 64 65 66
			  nesting_level_left (nesting_level_left_),
			  debug_depth (0) {}
};



67 68 69 70 71 72 73 74
/* TODO Add TRACE_RETURN annotation to gsub. */
#ifndef HB_DEBUG_WOULD_APPLY
#define HB_DEBUG_WOULD_APPLY (HB_DEBUG+0)
#endif

#define TRACE_WOULD_APPLY() \
	hb_auto_trace_t<HB_DEBUG_WOULD_APPLY> trace (&c->debug_depth, "WOULD_APPLY", this, HB_FUNC, "%d glyphs", c->len);

75 76 77 78

struct hb_would_apply_context_t
{
  hb_face_t *face;
79
  const hb_codepoint_t *glyphs;
80
  unsigned int len;
81
  bool zero_context;
B
Minor  
Behdad Esfahbod 已提交
82
  const hb_set_digest_t digest;
83 84 85
  unsigned int debug_depth;

  hb_would_apply_context_t (hb_face_t *face_,
86 87
			    const hb_codepoint_t *glyphs_,
			    unsigned int len_,
88
			    bool zero_context_,
89
			    const hb_set_digest_t &digest_
90
			    ) :
91
			      face (face_),
92 93
			      glyphs (glyphs_),
			      len (len_),
94
			      zero_context (zero_context_),
95
			      digest (digest_),
96 97 98 99
			      debug_depth (0) {};
};


B
Behdad Esfahbod 已提交
100
#ifndef HB_DEBUG_APPLY
101
#define HB_DEBUG_APPLY (HB_DEBUG+0)
B
Behdad Esfahbod 已提交
102 103
#endif

B
Behdad Esfahbod 已提交
104
#define TRACE_APPLY() \
105
	hb_auto_trace_t<HB_DEBUG_APPLY> trace (&c->debug_depth, "APPLY", this, HB_FUNC, "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);
106

B
Behdad Esfahbod 已提交
107

108 109
struct hb_apply_context_t
{
110 111
  hb_font_t *font;
  hb_face_t *face;
B
Behdad Esfahbod 已提交
112
  hb_buffer_t *buffer;
113
  hb_direction_t direction;
B
Behdad Esfahbod 已提交
114
  hb_mask_t lookup_mask;
115
  unsigned int nesting_level_left;
116
  unsigned int lookup_props;
117
  unsigned int property; /* propety of first glyph */
118
  unsigned int debug_depth;
119
  const GDEF &gdef;
120
  bool has_glyph_classes;
B
Minor  
Behdad Esfahbod 已提交
121
  const hb_set_digest_t digest;
122

123 124 125

  hb_apply_context_t (hb_font_t *font_,
		      hb_buffer_t *buffer_,
126
		      hb_mask_t lookup_mask_,
127
		      const hb_set_digest_t &digest_) :
128
			font (font_), face (font->face), buffer (buffer_),
129 130
			direction (buffer_->props.direction),
			lookup_mask (lookup_mask_),
B
Minor  
Behdad Esfahbod 已提交
131
			nesting_level_left (MAX_NESTING_LEVEL),
132
			lookup_props (0), property (0), debug_depth (0),
133
			gdef (*hb_ot_layout_from_face (face)->gdef),
134
			has_glyph_classes (gdef.has_glyph_classes ()),
135
			digest (digest_) {}
136

137 138 139 140
  void set_lookup_props (unsigned int lookup_props_) {
    lookup_props = lookup_props_;
  }

B
Behdad Esfahbod 已提交
141
  void set_lookup (const Lookup &l) {
142 143 144
    lookup_props = l.get_props ();
  }

B
Behdad Esfahbod 已提交
145 146 147 148
  struct mark_skipping_forward_iterator_t
  {
    inline mark_skipping_forward_iterator_t (hb_apply_context_t *c_,
					     unsigned int start_index_,
149
					     unsigned int num_items_,
B
Minor  
Behdad Esfahbod 已提交
150
					     bool context_match = false)
B
Behdad Esfahbod 已提交
151 152 153 154
    {
      c = c_;
      idx = start_index_;
      num_items = num_items_;
B
Minor  
Behdad Esfahbod 已提交
155
      mask = context_match ? -1 : c->lookup_mask;
156
      syllable = context_match ? 0 : c->buffer->cur().syllable ();
157
      end = c->buffer->len;
B
Behdad Esfahbod 已提交
158 159 160 161 162
    }
    inline bool has_no_chance (void) const
    {
      return unlikely (num_items && idx + num_items >= end);
    }
B
Minor  
Behdad Esfahbod 已提交
163
    inline void reject (void)
164 165 166
    {
      num_items++;
    }
B
Behdad Esfahbod 已提交
167
    inline bool next (unsigned int *property_out,
B
Minor  
Behdad Esfahbod 已提交
168
		      unsigned int  lookup_props)
B
Behdad Esfahbod 已提交
169
    {
170
      assert (num_items > 0);
B
Behdad Esfahbod 已提交
171 172 173 174
      do
      {
	if (has_no_chance ())
	  return false;
B
Behdad Esfahbod 已提交
175
	idx++;
176
      } while (c->should_skip_mark (&c->buffer->info[idx], lookup_props, property_out));
B
Behdad Esfahbod 已提交
177
      num_items--;
178
      return (c->buffer->info[idx].mask & mask) && (!syllable || syllable == c->buffer->info[idx].syllable ());
B
Behdad Esfahbod 已提交
179 180 181 182 183 184 185
    }
    inline bool next (unsigned int *property_out = NULL)
    {
      return next (property_out, c->lookup_props);
    }

    unsigned int idx;
186
    protected:
B
Behdad Esfahbod 已提交
187 188
    hb_apply_context_t *c;
    unsigned int num_items;
189
    hb_mask_t mask;
190
    uint8_t syllable;
B
Behdad Esfahbod 已提交
191 192 193 194 195 196 197
    unsigned int end;
  };

  struct mark_skipping_backward_iterator_t
  {
    inline mark_skipping_backward_iterator_t (hb_apply_context_t *c_,
					      unsigned int start_index_,
198
					      unsigned int num_items_,
199
					      hb_mask_t mask_ = 0,
B
Minor  
Behdad Esfahbod 已提交
200
					      bool match_syllable_ = true)
B
Behdad Esfahbod 已提交
201 202 203 204
    {
      c = c_;
      idx = start_index_;
      num_items = num_items_;
205
      mask = mask_ ? mask_ : c->lookup_mask;
206
      syllable = match_syllable_ ? c->buffer->cur().syllable () : 0;
B
Behdad Esfahbod 已提交
207 208 209
    }
    inline bool has_no_chance (void) const
    {
210
      return unlikely (idx < num_items);
B
Behdad Esfahbod 已提交
211
    }
B
Minor  
Behdad Esfahbod 已提交
212
    inline void reject (void)
213 214 215
    {
      num_items++;
    }
B
Behdad Esfahbod 已提交
216
    inline bool prev (unsigned int *property_out,
B
Minor  
Behdad Esfahbod 已提交
217
		      unsigned int  lookup_props)
B
Behdad Esfahbod 已提交
218
    {
219
      assert (num_items > 0);
B
Behdad Esfahbod 已提交
220 221 222 223 224
      do
      {
	if (has_no_chance ())
	  return false;
	idx--;
225
      } while (c->should_skip_mark (&c->buffer->out_info[idx], lookup_props, property_out));
B
Behdad Esfahbod 已提交
226
      num_items--;
227
      return (c->buffer->out_info[idx].mask & mask) && (!syllable || syllable == c->buffer->out_info[idx].syllable ());
B
Behdad Esfahbod 已提交
228 229 230 231 232 233 234
    }
    inline bool prev (unsigned int *property_out = NULL)
    {
      return prev (property_out, c->lookup_props);
    }

    unsigned int idx;
235
    protected:
B
Behdad Esfahbod 已提交
236 237
    hb_apply_context_t *c;
    unsigned int num_items;
238
    hb_mask_t mask;
239
    uint8_t syllable;
B
Behdad Esfahbod 已提交
240 241
  };

242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
  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;

    if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_CLASS_MARK))
      return match_properties_mark (glyph, glyph_props, lookup_props);

    return true;
  }

  inline bool
  check_glyph_property (hb_glyph_info_t *info,
			unsigned int  lookup_props,
			unsigned int *property_out) const
284
  {
B
Behdad Esfahbod 已提交
285
    unsigned int property;
286

B
Minor  
Behdad Esfahbod 已提交
287
    property = info->glyph_props();
288 289 290 291 292 293 294 295 296 297 298 299
    *property_out = property;

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

  inline bool
  should_skip_mark (hb_glyph_info_t *info,
		   unsigned int  lookup_props,
		   unsigned int *property_out) const
  {
    unsigned int property;

B
Minor  
Behdad Esfahbod 已提交
300
    property = info->glyph_props();
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315
    if (property_out)
      *property_out = property;

    /* If it's a mark, skip it if we don't accept it. */
    if (unlikely (property & HB_OT_LAYOUT_GLYPH_CLASS_MARK))
      return !match_properties (info->codepoint, property, lookup_props);

    /* If not a mark, don't skip. */
    return false;
  }


  inline bool should_mark_skip_current_glyph (void) const
  {
    return should_skip_mark (&buffer->cur(), lookup_props, NULL);
316
  }
B
Behdad Esfahbod 已提交
317

318
  inline void set_class (hb_codepoint_t glyph_index, unsigned int class_guess) const
319
  {
320
    if (likely (has_glyph_classes))
B
Minor  
Behdad Esfahbod 已提交
321
      buffer->cur().glyph_props() = gdef.get_glyph_props (glyph_index);
322
    else if (class_guess)
B
Minor  
Behdad Esfahbod 已提交
323
      buffer->cur().glyph_props() = class_guess;
324
  }
B
Behdad Esfahbod 已提交
325

326
  inline void output_glyph (hb_codepoint_t glyph_index,
327
			    unsigned int class_guess = 0) const
328
  {
329
    set_class (glyph_index, class_guess);
330 331
    buffer->output_glyph (glyph_index);
  }
332
  inline void replace_glyph (hb_codepoint_t glyph_index,
333
			     unsigned int class_guess = 0) const
334
  {
335
    set_class (glyph_index, class_guess);
336 337
    buffer->replace_glyph (glyph_index);
  }
B
Behdad Esfahbod 已提交
338
  inline void replace_glyph_inplace (hb_codepoint_t glyph_index,
339
				     unsigned int class_guess = 0) const
B
Behdad Esfahbod 已提交
340
  {
341
    set_class (glyph_index, class_guess);
B
Behdad Esfahbod 已提交
342 343
    buffer->cur().codepoint = glyph_index;
  }
344 345
};

346

B
Behdad Esfahbod 已提交
347

348
typedef bool (*intersects_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data);
B
Behdad Esfahbod 已提交
349
typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data);
B
Behdad Esfahbod 已提交
350
typedef void (*closure_lookup_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
B
Behdad Esfahbod 已提交
351
typedef bool (*apply_lookup_func_t) (hb_apply_context_t *c, unsigned int lookup_index);
352

353 354 355 356 357 358
struct ContextClosureFuncs
{
  intersects_func_t intersects;
  closure_lookup_func_t closure;
};
struct ContextApplyFuncs
B
Behdad Esfahbod 已提交
359
{
360 361
  match_func_t match;
  apply_lookup_func_t apply;
362 363
};

364
static inline bool intersects_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED)
365 366 367
{
  return glyphs->has (value);
}
368
static inline bool intersects_class (hb_set_t *glyphs, const USHORT &value, const void *data)
369 370 371 372
{
  const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
  return class_def.intersects_class (glyphs, value);
}
373
static inline bool intersects_coverage (hb_set_t *glyphs, const USHORT &value, const void *data)
374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390
{
  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;
}

391

B
Behdad Esfahbod 已提交
392
static inline bool match_glyph (hb_codepoint_t glyph_id, const USHORT &value, const void *data HB_UNUSED)
B
Behdad Esfahbod 已提交
393
{
394 395
  return glyph_id == value;
}
B
Behdad Esfahbod 已提交
396
static inline bool match_class (hb_codepoint_t glyph_id, const USHORT &value, const void *data)
B
Behdad Esfahbod 已提交
397
{
B
Behdad Esfahbod 已提交
398
  const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
399 400
  return class_def.get_class (glyph_id) == value;
}
B
Behdad Esfahbod 已提交
401
static inline bool match_coverage (hb_codepoint_t glyph_id, const USHORT &value, const void *data)
B
Behdad Esfahbod 已提交
402
{
403
  const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
404
  return (data+coverage).get_coverage (glyph_id) != NOT_COVERED;
405 406
}

407

408 409 410 411 412 413 414 415 416 417
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++)
418
    if (likely (!match_func (c->glyphs[i], input[i - 1], match_data)))
419 420 421 422
      return false;

  return true;
}
B
Behdad Esfahbod 已提交
423
static inline bool match_input (hb_apply_context_t *c,
B
Behdad Esfahbod 已提交
424 425 426
				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 已提交
427
				const void *match_data,
428 429 430
				unsigned int *end_offset = NULL,
				bool *p_is_mark_ligature = NULL,
				unsigned int *p_total_component_count = NULL)
B
Behdad Esfahbod 已提交
431
{
432 433
  hb_auto_trace_t<HB_DEBUG_APPLY> trace (&c->debug_depth, "APPLY", NULL, HB_FUNC, "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);

B
Behdad Esfahbod 已提交
434
  hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1);
435 436
  if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);

437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454
  /*
   * 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...)
   */

455 456 457 458 459 460 461
  bool is_mark_ligature = !!(c->property & HB_OT_LAYOUT_GLYPH_CLASS_MARK);

  unsigned int total_component_count = 0;
  total_component_count += get_lig_num_comps (c->buffer->cur());

  unsigned int first_lig_id = get_lig_id (c->buffer->cur());
  unsigned int first_lig_comp = get_lig_comp (c->buffer->cur());
B
Behdad Esfahbod 已提交
462

B
Minor  
Behdad Esfahbod 已提交
463
  for (unsigned int i = 1; i < count; i++)
B
Behdad Esfahbod 已提交
464
  {
465
    unsigned int property;
B
Behdad Esfahbod 已提交
466

467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489
    if (!skippy_iter.next (&property)) return TRACE_RETURN (false);

    if (likely (!match_func (c->buffer->info[skippy_iter.idx].codepoint, input[i - 1], match_data))) return false;

    unsigned int this_lig_id = get_lig_id (c->buffer->info[skippy_iter.idx]);
    unsigned int this_lig_comp = get_lig_comp (c->buffer->info[skippy_iter.idx]);

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

    is_mark_ligature = is_mark_ligature && (property & HB_OT_LAYOUT_GLYPH_CLASS_MARK);
    total_component_count += get_lig_num_comps (c->buffer->info[skippy_iter.idx]);
B
Behdad Esfahbod 已提交
490 491
  }

492 493
  if (end_offset)
    *end_offset = skippy_iter.idx - c->buffer->idx + 1;
B
Behdad Esfahbod 已提交
494

495 496 497 498 499 500
  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 已提交
501 502
  return true;
}
503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 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 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581
static inline void ligate_input (hb_apply_context_t *c,
				 unsigned int count, /* Including the first glyph (not matched) */
				 const USHORT input[], /* Array of input values--start with second glyph */
				 hb_codepoint_t lig_glyph,
				 match_func_t match_func,
				 const void *match_data,
				 bool is_mark_ligature,
				 unsigned int total_component_count)
{
  /*
   * - 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
   */

  unsigned int klass = is_mark_ligature ? 0 : HB_OT_LAYOUT_GLYPH_CLASS_LIGATURE;
  unsigned int lig_id = is_mark_ligature ? 0 : allocate_lig_id (c->buffer);
  unsigned int last_lig_id = get_lig_id (c->buffer->cur());
  unsigned int last_num_components = get_lig_num_comps (c->buffer->cur());
  unsigned int components_so_far = last_num_components;

  if (!is_mark_ligature)
    set_lig_props_for_ligature (c->buffer->cur(), lig_id, total_component_count);
  c->replace_glyph (lig_glyph, klass);

  for (unsigned int i = 1; i < count; i++)
  {
    while (c->should_mark_skip_current_glyph ())
    {
      if (!is_mark_ligature) {
	unsigned int new_lig_comp = components_so_far - last_num_components +
				    MIN (MAX (get_lig_comp (c->buffer->cur()), 1u), last_num_components);
	set_lig_props_for_mark (c->buffer->cur(), lig_id, new_lig_comp);
      }
      c->buffer->next_glyph ();
    }

    last_lig_id = get_lig_id (c->buffer->cur());
    last_num_components = get_lig_num_comps (c->buffer->cur());
    components_so_far += last_num_components;

    /* Skip the base glyph */
    c->buffer->idx++;
  }

  if (!is_mark_ligature && last_lig_id) {
    /* Re-adjust components for any marks following. */
    for (unsigned int i = c->buffer->idx; i < c->buffer->len; i++) {
      if (last_lig_id == get_lig_id (c->buffer->info[i])) {
	unsigned int new_lig_comp = components_so_far - last_num_components +
				    MIN (MAX (get_lig_comp (c->buffer->info[i]), 1u), last_num_components);
	set_lig_props_for_mark (c->buffer->info[i], lig_id, new_lig_comp);
      } else
	break;
    }
  }
}
B
Behdad Esfahbod 已提交
582

B
Behdad Esfahbod 已提交
583
static inline bool match_backtrack (hb_apply_context_t *c,
584 585 586
				    unsigned int count,
				    const USHORT backtrack[],
				    match_func_t match_func,
B
Behdad Esfahbod 已提交
587
				    const void *match_data)
588
{
589 590
  hb_auto_trace_t<HB_DEBUG_APPLY> trace (&c->debug_depth, "APPLY", NULL, HB_FUNC, "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);

B
Minor  
Behdad Esfahbod 已提交
591
  hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->backtrack_len (), count, true);
B
Behdad Esfahbod 已提交
592
  if (skippy_iter.has_no_chance ())
593
    return TRACE_RETURN (false);
594

595
  for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
596
  {
B
Behdad Esfahbod 已提交
597
    if (!skippy_iter.prev ())
598
      return TRACE_RETURN (false);
599

B
Behdad Esfahbod 已提交
600
    if (likely (!match_func (c->buffer->out_info[skippy_iter.idx].codepoint, backtrack[i], match_data)))
601
      return TRACE_RETURN (false);
602 603
  }

604
  return TRACE_RETURN (true);
605 606
}

B
Behdad Esfahbod 已提交
607
static inline bool match_lookahead (hb_apply_context_t *c,
B
Behdad Esfahbod 已提交
608 609 610
				    unsigned int count,
				    const USHORT lookahead[],
				    match_func_t match_func,
B
Behdad Esfahbod 已提交
611
				    const void *match_data,
B
Behdad Esfahbod 已提交
612
				    unsigned int offset)
613
{
614 615
  hb_auto_trace_t<HB_DEBUG_APPLY> trace (&c->debug_depth, "APPLY", NULL, HB_FUNC, "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);

B
Minor  
Behdad Esfahbod 已提交
616
  hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx + offset - 1, count, true);
B
Behdad Esfahbod 已提交
617
  if (skippy_iter.has_no_chance ())
618
    return TRACE_RETURN (false);
619

B
Minor  
Behdad Esfahbod 已提交
620
  for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
621
  {
B
Behdad Esfahbod 已提交
622
    if (!skippy_iter.next ())
623
      return TRACE_RETURN (false);
624

B
Behdad Esfahbod 已提交
625
    if (likely (!match_func (c->buffer->info[skippy_iter.idx].codepoint, lookahead[i], match_data)))
626
      return TRACE_RETURN (false);
627 628
  }

629
  return TRACE_RETURN (true);
630 631
}

B
Behdad Esfahbod 已提交
632

633

B
Behdad Esfahbod 已提交
634 635
struct LookupRecord
{
B
Behdad Esfahbod 已提交
636
  inline bool sanitize (hb_sanitize_context_t *c) {
637
    TRACE_SANITIZE ();
638
    return TRACE_RETURN (c->check_struct (this));
B
Behdad Esfahbod 已提交
639 640
  }

641 642 643 644
  USHORT	sequenceIndex;		/* Index into current glyph
					 * sequence--first glyph = 0 */
  USHORT	lookupListIndex;	/* Lookup to apply to that
					 * position--zero--based */
B
Behdad Esfahbod 已提交
645 646
  public:
  DEFINE_SIZE_STATIC (4);
647 648
};

B
Behdad Esfahbod 已提交
649

B
Behdad Esfahbod 已提交
650
static inline void closure_lookup (hb_closure_context_t *c,
651 652 653 654 655
				   unsigned int lookupCount,
				   const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
				   closure_lookup_func_t closure_func)
{
  for (unsigned int i = 0; i < lookupCount; i++)
B
Behdad Esfahbod 已提交
656
    closure_func (c, lookupRecord->lookupListIndex);
657
}
B
Behdad Esfahbod 已提交
658

B
Behdad Esfahbod 已提交
659
static inline bool apply_lookup (hb_apply_context_t *c,
660 661
				 unsigned int count, /* Including the first glyph */
				 unsigned int lookupCount,
662 663 664
				 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
				 apply_lookup_func_t apply_func)
{
665
  unsigned int end = c->buffer->len;
666
  if (unlikely (count == 0 || c->buffer->idx + count > end))
667
    return false;
668

B
Behdad Esfahbod 已提交
669 670
  /* TODO We don't support lookupRecord arrays that are not increasing:
   *      Should be easy for in_place ones at least. */
B
Behdad Esfahbod 已提交
671

672
  /* Note: If sublookup is reverse, it will underflow after the first loop
B
Behdad Esfahbod 已提交
673 674 675
   * and we jump out of it.  Not entirely disastrous.  So we don't check
   * for reverse lookup here.
   */
B
Behdad Esfahbod 已提交
676
  for (unsigned int i = 0; i < count; /* NOP */)
B
Behdad Esfahbod 已提交
677
  {
678 679
    if (unlikely (c->buffer->idx == end))
      return true;
680
    while (c->should_mark_skip_current_glyph ())
B
Behdad Esfahbod 已提交
681
    {
682
      /* No lookup applied for this index */
B
Behdad Esfahbod 已提交
683
      c->buffer->next_glyph ();
684 685
      if (unlikely (c->buffer->idx == end))
	return true;
686 687
    }

B
Behdad Esfahbod 已提交
688
    if (lookupCount && i == lookupRecord->sequenceIndex)
689
    {
690
      unsigned int old_pos = c->buffer->idx;
691 692

      /* Apply a lookup */
B
Behdad Esfahbod 已提交
693
      bool done = apply_func (c, lookupRecord->lookupListIndex);
694

B
Behdad Esfahbod 已提交
695 696
      lookupRecord++;
      lookupCount--;
B
Behdad Esfahbod 已提交
697
      /* Err, this is wrong if the lookup jumped over some glyphs */
698 699
      i += c->buffer->idx - old_pos;
      if (unlikely (c->buffer->idx == end))
700
	return true;
701 702 703 704 705 706 707 708

      if (!done)
	goto not_applied;
    }
    else
    {
    not_applied:
      /* No lookup applied for this index */
B
Behdad Esfahbod 已提交
709
      c->buffer->next_glyph ();
710 711 712 713 714 715
      i++;
    }
  }

  return true;
}
716

B
Behdad Esfahbod 已提交
717

718 719 720

/* Contextual lookups */

721 722 723 724 725 726 727
struct ContextClosureLookupContext
{
  ContextClosureFuncs funcs;
  const void *intersects_data;
};

struct ContextApplyLookupContext
B
Behdad Esfahbod 已提交
728
{
729
  ContextApplyFuncs funcs;
B
Behdad Esfahbod 已提交
730
  const void *match_data;
731 732
};

B
Behdad Esfahbod 已提交
733
static inline void context_closure_lookup (hb_closure_context_t *c,
734 735 736 737 738 739
					   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 已提交
740 741 742 743 744 745
  if (intersects_array (c,
			inputCount ? inputCount - 1 : 0, input,
			lookup_context.funcs.intersects, lookup_context.intersects_data))
    closure_lookup (c,
		    lookupCount, lookupRecord,
		    lookup_context.funcs.closure);
746 747 748
}


749 750 751 752 753 754 755 756 757 758 759
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 */
					       unsigned int lookupCount,
					       const LookupRecord lookupRecord[],
					       ContextApplyLookupContext &lookup_context)
{
  return would_match_input (c,
			    inputCount, input,
			    lookup_context.funcs.match, lookup_context.match_data);
}
760 761 762 763 764 765
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)
766
{
B
Behdad Esfahbod 已提交
767
  return match_input (c,
B
Behdad Esfahbod 已提交
768
		      inputCount, input,
769 770
		      lookup_context.funcs.match, lookup_context.match_data)
      && apply_lookup (c,
B
Behdad Esfahbod 已提交
771 772 773
		       inputCount,
		       lookupCount, lookupRecord,
		       lookup_context.funcs.apply);
774 775
}

B
Behdad Esfahbod 已提交
776 777
struct Rule
{
778 779 780
  friend struct RuleSet;

  private:
781

B
Behdad Esfahbod 已提交
782
  inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
783 784 785
  {
    TRACE_CLOSURE ();
    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
B
Behdad Esfahbod 已提交
786 787 788 789
    context_closure_lookup (c,
			    inputCount, input,
			    lookupCount, lookupRecord,
			    lookup_context);
790 791
  }

792 793 794 795 796 797 798
  inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
  {
    TRACE_WOULD_APPLY ();
    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));
  }

799
  inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
B
Behdad Esfahbod 已提交
800
  {
801
    TRACE_APPLY ();
B
Behdad Esfahbod 已提交
802
    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
803
    return TRACE_RETURN (context_apply_lookup (c, inputCount, input, lookupCount, lookupRecord, lookup_context));
804 805
  }

B
Behdad Esfahbod 已提交
806
  public:
B
Behdad Esfahbod 已提交
807
  inline bool sanitize (hb_sanitize_context_t *c) {
808
    TRACE_SANITIZE ();
B
Behdad Esfahbod 已提交
809 810 811
    return inputCount.sanitize (c)
	&& lookupCount.sanitize (c)
	&& c->check_range (input,
812 813
			   input[0].static_size * inputCount
			   + lookupRecordX[0].static_size * lookupCount);
B
Behdad Esfahbod 已提交
814 815
  }

816
  protected:
817
  USHORT	inputCount;		/* Total number of glyphs in input
818
					 * glyph sequence--includes the first
819
					 * glyph */
820
  USHORT	lookupCount;		/* Number of LookupRecords */
B
Behdad Esfahbod 已提交
821
  USHORT	input[VAR];		/* Array of match inputs--start with
822
					 * second glyph */
B
Behdad Esfahbod 已提交
823
  LookupRecord	lookupRecordX[VAR];	/* Array of LookupRecords--in
824
					 * design order */
B
Behdad Esfahbod 已提交
825
  public:
826
  DEFINE_SIZE_ARRAY2 (4, input, lookupRecordX);
827 828
};

B
Behdad Esfahbod 已提交
829 830
struct RuleSet
{
B
Behdad Esfahbod 已提交
831
  inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
832 833 834 835
  {
    TRACE_CLOSURE ();
    unsigned int num_rules = rule.len;
    for (unsigned int i = 0; i < num_rules; i++)
B
Behdad Esfahbod 已提交
836
      (this+rule[i]).closure (c, lookup_context);
837 838
  }

839 840 841 842 843 844 845 846 847 848 849 850
  inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
  {
    TRACE_WOULD_APPLY ();
    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);
  }

851
  inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
B
Behdad Esfahbod 已提交
852
  {
853
    TRACE_APPLY ();
854
    unsigned int num_rules = rule.len;
B
Behdad Esfahbod 已提交
855 856
    for (unsigned int i = 0; i < num_rules; i++)
    {
B
Behdad Esfahbod 已提交
857
      if ((this+rule[i]).apply (c, lookup_context))
858
        return TRACE_RETURN (true);
859
    }
860
    return TRACE_RETURN (false);
861 862
  }

B
Behdad Esfahbod 已提交
863
  inline bool sanitize (hb_sanitize_context_t *c) {
864
    TRACE_SANITIZE ();
865
    return TRACE_RETURN (rule.sanitize (c, this));
B
Behdad Esfahbod 已提交
866 867
  }

868
  protected:
869
  OffsetArrayOf<Rule>
870
		rule;			/* Array of Rule tables
871
					 * ordered by preference */
B
Behdad Esfahbod 已提交
872
  public:
873
  DEFINE_SIZE_ARRAY (2, rule);
874 875 876
};


B
Behdad Esfahbod 已提交
877 878
struct ContextFormat1
{
879 880 881
  friend struct Context;

  private:
882

B
Behdad Esfahbod 已提交
883
  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
884 885
  {
    TRACE_CLOSURE ();
886 887 888 889 890 891 892 893 894 895 896 897

    const Coverage &cov = (this+coverage);

    struct ContextClosureLookupContext lookup_context = {
      {intersects_glyph, closure_func},
      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 已提交
898
	rule_set.closure (c, lookup_context);
899
      }
900 901
  }

902 903 904 905
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
    TRACE_WOULD_APPLY ();

906
    const RuleSet &rule_set = this+ruleSet[(this+coverage) (c->glyphs[0])];
907 908 909 910 911 912 913
    struct ContextApplyLookupContext lookup_context = {
      {match_glyph, NULL},
      NULL
    };
    return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
  }

B
Behdad Esfahbod 已提交
914
  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
B
Behdad Esfahbod 已提交
915
  {
916
    TRACE_APPLY ();
917
    unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
918
    if (likely (index == NOT_COVERED))
919
      return TRACE_RETURN (false);
920

921
    const RuleSet &rule_set = this+ruleSet[index];
922
    struct ContextApplyLookupContext lookup_context = {
923 924
      {match_glyph, apply_func},
      NULL
925
    };
926
    return TRACE_RETURN (rule_set.apply (c, lookup_context));
927 928
  }

B
Behdad Esfahbod 已提交
929
  inline bool sanitize (hb_sanitize_context_t *c) {
930
    TRACE_SANITIZE ();
931
    return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
932 933
  }

934
  protected:
935 936 937 938 939 940 941
  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 */
942
  public:
943
  DEFINE_SIZE_ARRAY (6, ruleSet);
944 945 946
};


B
Behdad Esfahbod 已提交
947 948
struct ContextFormat2
{
949 950 951
  friend struct Context;

  private:
952

B
Behdad Esfahbod 已提交
953
  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
954 955
  {
    TRACE_CLOSURE ();
956
    if (!(this+coverage).intersects (c->glyphs))
B
Behdad Esfahbod 已提交
957
      return;
958 959 960 961 962 963 964 965 966 967 968 969

    const ClassDef &class_def = this+classDef;

    struct ContextClosureLookupContext lookup_context = {
      {intersects_class, closure_func},
      NULL
    };

    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 已提交
970
	rule_set.closure (c, lookup_context);
971
      }
972 973
  }

974 975 976 977 978
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
    TRACE_WOULD_APPLY ();

    const ClassDef &class_def = this+classDef;
979
    unsigned int index = class_def (c->glyphs[0]);
980 981 982 983 984 985 986 987
    const RuleSet &rule_set = this+ruleSet[index];
    struct ContextApplyLookupContext lookup_context = {
      {match_class, NULL},
      &class_def
    };
    return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
  }

B
Behdad Esfahbod 已提交
988
  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
B
Behdad Esfahbod 已提交
989
  {
990
    TRACE_APPLY ();
991
    unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
992
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
993 994

    const ClassDef &class_def = this+classDef;
995
    index = class_def (c->buffer->cur().codepoint);
996
    const RuleSet &rule_set = this+ruleSet[index];
997
    struct ContextApplyLookupContext lookup_context = {
B
Behdad Esfahbod 已提交
998 999
      {match_class, apply_func},
      &class_def
1000
    };
1001
    return TRACE_RETURN (rule_set.apply (c, lookup_context));
1002 1003
  }

B
Behdad Esfahbod 已提交
1004
  inline bool sanitize (hb_sanitize_context_t *c) {
1005
    TRACE_SANITIZE ();
1006
    return TRACE_RETURN (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
1007 1008
  }

1009
  protected:
1010 1011 1012 1013 1014 1015 1016 1017 1018 1019
  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 */
1020
  public:
1021
  DEFINE_SIZE_ARRAY (8, ruleSet);
1022 1023 1024
};


B
Behdad Esfahbod 已提交
1025 1026
struct ContextFormat3
{
1027 1028 1029
  friend struct Context;

  private:
1030

B
Behdad Esfahbod 已提交
1031
  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
1032 1033
  {
    TRACE_CLOSURE ();
1034
    if (!(this+coverage[0]).intersects (c->glyphs))
B
Behdad Esfahbod 已提交
1035
      return;
1036 1037 1038 1039 1040 1041

    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
    struct ContextClosureLookupContext lookup_context = {
      {intersects_coverage, closure_func},
      this
    };
B
Behdad Esfahbod 已提交
1042 1043 1044 1045
    context_closure_lookup (c,
			    glyphCount, (const USHORT *) (coverage + 1),
			    lookupCount, lookupRecord,
			    lookup_context);
1046 1047
  }

1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
    TRACE_WOULD_APPLY ();

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

B
Behdad Esfahbod 已提交
1060
  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
B
Behdad Esfahbod 已提交
1061
  {
1062
    TRACE_APPLY ();
1063
    unsigned int index = (this+coverage[0]) (c->buffer->cur().codepoint);
1064
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
1065

B
Behdad Esfahbod 已提交
1066
    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
1067
    struct ContextApplyLookupContext lookup_context = {
1068
      {match_coverage, apply_func},
B
Behdad Esfahbod 已提交
1069
      this
1070
    };
1071
    return TRACE_RETURN (context_apply_lookup (c, glyphCount, (const USHORT *) (coverage + 1), lookupCount, lookupRecord, lookup_context));
1072 1073
  }

B
Behdad Esfahbod 已提交
1074
  inline bool sanitize (hb_sanitize_context_t *c) {
1075
    TRACE_SANITIZE ();
1076
    if (!c->check_struct (this)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1077
    unsigned int count = glyphCount;
1078
    if (!c->check_array (coverage, coverage[0].static_size, count)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1079
    for (unsigned int i = 0; i < count; i++)
1080
      if (!coverage[i].sanitize (c, this)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1081
    LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * count);
1082
    return TRACE_RETURN (c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount));
B
Behdad Esfahbod 已提交
1083 1084
  }

1085
  protected:
1086 1087 1088
  USHORT	format;			/* Format identifier--format = 3 */
  USHORT	glyphCount;		/* Number of glyphs in the input glyph
					 * sequence */
1089
  USHORT	lookupCount;		/* Number of LookupRecords */
1090
  OffsetTo<Coverage>
B
Behdad Esfahbod 已提交
1091
		coverage[VAR];		/* Array of offsets to Coverage
1092
					 * table in glyph sequence order */
B
Behdad Esfahbod 已提交
1093
  LookupRecord	lookupRecordX[VAR];	/* Array of LookupRecords--in
1094
					 * design order */
B
Behdad Esfahbod 已提交
1095
  public:
1096
  DEFINE_SIZE_ARRAY2 (6, coverage, lookupRecordX);
1097 1098
};

B
Behdad Esfahbod 已提交
1099 1100
struct Context
{
1101
  protected:
1102

B
Behdad Esfahbod 已提交
1103
  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
1104 1105 1106
  {
    TRACE_CLOSURE ();
    switch (u.format) {
B
Behdad Esfahbod 已提交
1107 1108 1109 1110
    case 1: u.format1.closure (c, closure_func); break;
    case 2: u.format2.closure (c, closure_func); break;
    case 3: u.format3.closure (c, closure_func); break;
    default:                                     break;
1111 1112 1113
    }
  }

1114 1115 1116 1117 1118 1119 1120 1121 1122 1123
  inline const Coverage &get_coverage (void) const
  {
    switch (u.format) {
    case 1: return this + u.format1.coverage;
    case 2: return this + u.format2.coverage;
    case 3: return this + u.format3.coverage[0];
    default:return Null(Coverage);
    }
  }

1124 1125 1126 1127 1128 1129 1130 1131 1132 1133
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
    switch (u.format) {
    case 1: return u.format1.would_apply (c);
    case 2: return u.format2.would_apply (c);
    case 3: return u.format3.would_apply (c);
    default:return false;
    }
  }

B
Behdad Esfahbod 已提交
1134
  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
B
Behdad Esfahbod 已提交
1135
  {
1136
    TRACE_APPLY ();
1137
    switch (u.format) {
1138 1139 1140 1141
    case 1: return TRACE_RETURN (u.format1.apply (c, apply_func));
    case 2: return TRACE_RETURN (u.format2.apply (c, apply_func));
    case 3: return TRACE_RETURN (u.format3.apply (c, apply_func));
    default:return TRACE_RETURN (false);
1142 1143 1144
    }
  }

B
Behdad Esfahbod 已提交
1145
  inline bool sanitize (hb_sanitize_context_t *c) {
1146
    TRACE_SANITIZE ();
1147
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1148
    switch (u.format) {
1149 1150 1151 1152
    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 已提交
1153 1154 1155
    }
  }

1156
  protected:
1157
  union {
B
Behdad Esfahbod 已提交
1158
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1159 1160 1161
  ContextFormat1	format1;
  ContextFormat2	format2;
  ContextFormat3	format3;
1162 1163 1164
  } u;
};

1165 1166 1167

/* Chaining Contextual lookups */

1168
struct ChainContextClosureLookupContext
B
Behdad Esfahbod 已提交
1169
{
1170 1171 1172 1173 1174 1175 1176
  ContextClosureFuncs funcs;
  const void *intersects_data[3];
};

struct ChainContextApplyLookupContext
{
  ContextApplyFuncs funcs;
B
Behdad Esfahbod 已提交
1177
  const void *match_data[3];
1178 1179
};

B
Behdad Esfahbod 已提交
1180
static inline void chain_context_closure_lookup (hb_closure_context_t *c,
1181 1182 1183 1184 1185 1186 1187 1188 1189 1190
						 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 已提交
1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202
  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])
  && intersects_array (c,
		       lookaheadCount, lookahead,
		       lookup_context.funcs.intersects, lookup_context.intersects_data[2]))
    closure_lookup (c,
		    lookupCount, lookupRecord,
		    lookup_context.funcs.closure);
1203 1204
}

1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215
static inline bool chain_context_would_apply_lookup (hb_would_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)
{
1216
  return (c->zero_context ? !backtrackCount && !lookaheadCount : true)
1217
      && would_match_input (c,
1218 1219 1220 1221
			    inputCount, input,
			    lookup_context.funcs.match, lookup_context.match_data[1]);
}

1222 1223 1224 1225 1226 1227 1228 1229 1230 1231
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)
1232
{
1233
  unsigned int lookahead_offset;
B
Behdad Esfahbod 已提交
1234
  return match_input (c,
B
Behdad Esfahbod 已提交
1235 1236
		      inputCount, input,
		      lookup_context.funcs.match, lookup_context.match_data[1],
1237
		      &lookahead_offset)
B
Behdad Esfahbod 已提交
1238 1239 1240
      && match_backtrack (c,
			  backtrackCount, backtrack,
			  lookup_context.funcs.match, lookup_context.match_data[0])
B
Behdad Esfahbod 已提交
1241
      && match_lookahead (c,
B
Behdad Esfahbod 已提交
1242 1243
			  lookaheadCount, lookahead,
			  lookup_context.funcs.match, lookup_context.match_data[2],
1244 1245
			  lookahead_offset)
      && apply_lookup (c,
B
Behdad Esfahbod 已提交
1246 1247 1248
		       inputCount,
		       lookupCount, lookupRecord,
		       lookup_context.funcs.apply);
1249
}
1250

B
Behdad Esfahbod 已提交
1251 1252
struct ChainRule
{
1253 1254 1255
  friend struct ChainRuleSet;

  private:
1256

B
Behdad Esfahbod 已提交
1257
  inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
1258 1259 1260 1261 1262
  {
    TRACE_CLOSURE ();
    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 已提交
1263 1264 1265 1266 1267 1268
    chain_context_closure_lookup (c,
				  backtrack.len, backtrack.array,
				  input.len, input.array,
				  lookahead.len, lookahead.array,
				  lookup.len, lookup.array,
				  lookup_context);
1269 1270
  }

1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283
  inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
  {
    TRACE_WOULD_APPLY ();
    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));
  }

1284
  inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
B
Behdad Esfahbod 已提交
1285
  {
1286
    TRACE_APPLY ();
1287 1288 1289
    const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
    const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1290 1291 1292 1293 1294
    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));
1295 1296
  }

B
Behdad Esfahbod 已提交
1297
  public:
B
Behdad Esfahbod 已提交
1298
  inline bool sanitize (hb_sanitize_context_t *c) {
1299
    TRACE_SANITIZE ();
1300
    if (!backtrack.sanitize (c)) return TRACE_RETURN (false);
1301
    HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
1302
    if (!input.sanitize (c)) return TRACE_RETURN (false);
1303
    ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
1304
    if (!lookahead.sanitize (c)) return TRACE_RETURN (false);
1305
    ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1306
    return TRACE_RETURN (lookup.sanitize (c));
B
Behdad Esfahbod 已提交
1307
  }
1308

1309
  protected:
B
Behdad Esfahbod 已提交
1310 1311
  ArrayOf<USHORT>
		backtrack;		/* Array of backtracking values
1312 1313
					 * (to be matched before the input
					 * sequence) */
B
Behdad Esfahbod 已提交
1314 1315
  HeadlessArrayOf<USHORT>
		inputX;			/* Array of input values (start with
1316
					 * second glyph) */
B
Behdad Esfahbod 已提交
1317 1318
  ArrayOf<USHORT>
		lookaheadX;		/* Array of lookahead values's (to be
1319
					 * matched after the input sequence) */
B
Behdad Esfahbod 已提交
1320
  ArrayOf<LookupRecord>
1321
		lookupX;		/* Array of LookupRecords--in
1322
					 * design order) */
1323
  public:
B
Behdad Esfahbod 已提交
1324
  DEFINE_SIZE_MIN (8);
1325 1326
};

B
Behdad Esfahbod 已提交
1327 1328
struct ChainRuleSet
{
B
Behdad Esfahbod 已提交
1329
  inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
1330 1331 1332 1333
  {
    TRACE_CLOSURE ();
    unsigned int num_rules = rule.len;
    for (unsigned int i = 0; i < num_rules; i++)
B
Behdad Esfahbod 已提交
1334
      (this+rule[i]).closure (c, lookup_context);
1335 1336
  }

1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347
  inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
  {
    TRACE_WOULD_APPLY ();
    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);
  }

1348
  inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
B
Behdad Esfahbod 已提交
1349
  {
1350
    TRACE_APPLY ();
1351
    unsigned int num_rules = rule.len;
B
Behdad Esfahbod 已提交
1352
    for (unsigned int i = 0; i < num_rules; i++)
B
Behdad Esfahbod 已提交
1353
      if ((this+rule[i]).apply (c, lookup_context))
1354
        return TRACE_RETURN (true);
1355

1356
    return TRACE_RETURN (false);
1357
  }
1358

B
Behdad Esfahbod 已提交
1359
  inline bool sanitize (hb_sanitize_context_t *c) {
1360
    TRACE_SANITIZE ();
1361
    return TRACE_RETURN (rule.sanitize (c, this));
B
Behdad Esfahbod 已提交
1362 1363
  }

1364
  protected:
1365 1366 1367
  OffsetArrayOf<ChainRule>
		rule;			/* Array of ChainRule tables
					 * ordered by preference */
1368
  public:
1369
  DEFINE_SIZE_ARRAY (2, rule);
1370 1371
};

B
Behdad Esfahbod 已提交
1372 1373
struct ChainContextFormat1
{
1374 1375 1376
  friend struct ChainContext;

  private:
1377

B
Behdad Esfahbod 已提交
1378
  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
1379 1380
  {
    TRACE_CLOSURE ();
1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391
    const Coverage &cov = (this+coverage);

    struct ChainContextClosureLookupContext lookup_context = {
      {intersects_glyph, closure_func},
      {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 已提交
1392
	rule_set.closure (c, lookup_context);
1393
      }
1394 1395
  }

1396 1397 1398 1399
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
    TRACE_WOULD_APPLY ();

1400
    const ChainRuleSet &rule_set = this+ruleSet[(this+coverage) (c->glyphs[0])];
1401 1402 1403 1404 1405 1406 1407
    struct ChainContextApplyLookupContext lookup_context = {
      {match_glyph, NULL},
      {NULL, NULL, NULL}
    };
    return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
  }

B
Behdad Esfahbod 已提交
1408
  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
B
Behdad Esfahbod 已提交
1409
  {
1410
    TRACE_APPLY ();
1411
    unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
1412
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
1413

1414
    const ChainRuleSet &rule_set = this+ruleSet[index];
1415
    struct ChainContextApplyLookupContext lookup_context = {
1416 1417 1418
      {match_glyph, apply_func},
      {NULL, NULL, NULL}
    };
1419
    return TRACE_RETURN (rule_set.apply (c, lookup_context));
1420
  }
B
Behdad Esfahbod 已提交
1421

B
Behdad Esfahbod 已提交
1422
  inline bool sanitize (hb_sanitize_context_t *c) {
1423
    TRACE_SANITIZE ();
1424
    return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
1425 1426
  }

1427
  protected:
1428
  USHORT	format;			/* Format identifier--format = 1 */
1429 1430
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
1431
					 * beginning of table */
1432 1433 1434
  OffsetArrayOf<ChainRuleSet>
		ruleSet;		/* Array of ChainRuleSet tables
					 * ordered by Coverage Index */
1435
  public:
1436
  DEFINE_SIZE_ARRAY (6, ruleSet);
1437 1438
};

B
Behdad Esfahbod 已提交
1439 1440
struct ChainContextFormat2
{
1441 1442 1443
  friend struct ChainContext;

  private:
1444

B
Behdad Esfahbod 已提交
1445
  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
1446 1447
  {
    TRACE_CLOSURE ();
1448
    if (!(this+coverage).intersects (c->glyphs))
B
Behdad Esfahbod 已提交
1449
      return;
1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465

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

    struct ChainContextClosureLookupContext lookup_context = {
      {intersects_class, closure_func},
      {&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 已提交
1466
	rule_set.closure (c, lookup_context);
1467
      }
1468 1469
  }

1470 1471 1472 1473 1474 1475
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
    TRACE_WOULD_APPLY ();

    const ClassDef &input_class_def = this+inputClassDef;

1476
    unsigned int index = input_class_def (c->glyphs[0]);
1477 1478 1479 1480 1481 1482 1483 1484
    const ChainRuleSet &rule_set = this+ruleSet[index];
    struct ChainContextApplyLookupContext lookup_context = {
      {match_class, NULL},
      {NULL, &input_class_def, NULL}
    };
    return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
  }

B
Behdad Esfahbod 已提交
1485
  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
B
Behdad Esfahbod 已提交
1486
  {
1487
    TRACE_APPLY ();
1488
    unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
1489
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
1490 1491 1492 1493 1494

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

1495
    index = input_class_def (c->buffer->cur().codepoint);
1496
    const ChainRuleSet &rule_set = this+ruleSet[index];
1497
    struct ChainContextApplyLookupContext lookup_context = {
B
Behdad Esfahbod 已提交
1498 1499 1500 1501
      {match_class, apply_func},
      {&backtrack_class_def,
       &input_class_def,
       &lookahead_class_def}
1502
    };
1503
    return TRACE_RETURN (rule_set.apply (c, lookup_context));
1504 1505
  }

B
Behdad Esfahbod 已提交
1506
  inline bool sanitize (hb_sanitize_context_t *c) {
1507
    TRACE_SANITIZE ();
1508 1509 1510
    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 已提交
1511 1512
  }

1513
  protected:
1514
  USHORT	format;			/* Format identifier--format = 2 */
1515 1516
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
1517
					 * beginning of table */
1518 1519
  OffsetTo<ClassDef>
		backtrackClassDef;	/* Offset to glyph ClassDef table
1520 1521
					 * containing backtrack sequence
					 * data--from beginning of table */
1522 1523
  OffsetTo<ClassDef>
		inputClassDef;		/* Offset to glyph ClassDef
1524 1525
					 * table containing input sequence
					 * data--from beginning of table */
1526 1527
  OffsetTo<ClassDef>
		lookaheadClassDef;	/* Offset to glyph ClassDef table
1528 1529
					 * containing lookahead sequence
					 * data--from beginning of table */
1530 1531 1532
  OffsetArrayOf<ChainRuleSet>
		ruleSet;		/* Array of ChainRuleSet tables
					 * ordered by class */
1533
  public:
1534
  DEFINE_SIZE_ARRAY (12, ruleSet);
1535 1536
};

B
Behdad Esfahbod 已提交
1537 1538
struct ChainContextFormat3
{
1539 1540 1541
  friend struct ChainContext;

  private:
1542

B
Behdad Esfahbod 已提交
1543
  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
1544 1545
  {
    TRACE_CLOSURE ();
B
Behdad Esfahbod 已提交
1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562
    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 = {
      {intersects_coverage, closure_func},
      {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);
1563 1564
  }

1565 1566 1567 1568 1569 1570
  inline const Coverage &get_coverage (void) const
  {
    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
    return this+input[0];
  }

1571 1572 1573 1574
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
    TRACE_WOULD_APPLY ();

B
Behdad Esfahbod 已提交
1575
    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
    struct ChainContextApplyLookupContext lookup_context = {
      {match_coverage, NULL},
      {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));
  }

B
Behdad Esfahbod 已提交
1589
  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
B
Behdad Esfahbod 已提交
1590
  {
1591
    TRACE_APPLY ();
1592
    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1593

1594
    unsigned int index = (this+input[0]) (c->buffer->cur().codepoint);
1595
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
1596

1597 1598
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1599
    struct ChainContextApplyLookupContext lookup_context = {
1600
      {match_coverage, apply_func},
B
Behdad Esfahbod 已提交
1601
      {this, this, this}
1602
    };
1603 1604 1605 1606 1607
    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));
1608 1609
  }

B
Behdad Esfahbod 已提交
1610
  inline bool sanitize (hb_sanitize_context_t *c) {
1611
    TRACE_SANITIZE ();
1612
    if (!backtrack.sanitize (c, this)) return TRACE_RETURN (false);
1613
    OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1614
    if (!input.sanitize (c, this)) return TRACE_RETURN (false);
1615
    OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
1616
    if (!lookahead.sanitize (c, this)) return TRACE_RETURN (false);
1617
    ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1618
    return TRACE_RETURN (lookup.sanitize (c));
B
Behdad Esfahbod 已提交
1619 1620
  }

1621
  protected:
1622
  USHORT	format;			/* Format identifier--format = 3 */
B
Behdad Esfahbod 已提交
1623
  OffsetArrayOf<Coverage>
1624
		backtrack;		/* Array of coverage tables
1625 1626
					 * in backtracking sequence, in  glyph
					 * sequence order */
B
Behdad Esfahbod 已提交
1627
  OffsetArrayOf<Coverage>
1628
		inputX		;	/* Array of coverage
1629 1630
					 * tables in input sequence, in glyph
					 * sequence order */
B
Behdad Esfahbod 已提交
1631
  OffsetArrayOf<Coverage>
1632
		lookaheadX;		/* Array of coverage tables
1633 1634
					 * in lookahead sequence, in glyph
					 * sequence order */
B
Behdad Esfahbod 已提交
1635
  ArrayOf<LookupRecord>
1636
		lookupX;		/* Array of LookupRecords--in
B
Behdad Esfahbod 已提交
1637
					 * design order) */
1638
  public:
B
Behdad Esfahbod 已提交
1639
  DEFINE_SIZE_MIN (10);
1640 1641
};

B
Behdad Esfahbod 已提交
1642 1643
struct ChainContext
{
1644
  protected:
1645

B
Behdad Esfahbod 已提交
1646
  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
1647 1648 1649
  {
    TRACE_CLOSURE ();
    switch (u.format) {
B
Behdad Esfahbod 已提交
1650 1651 1652 1653
    case 1: u.format1.closure (c, closure_func); break;
    case 2: u.format2.closure (c, closure_func); break;
    case 3: u.format3.closure (c, closure_func); break;
    default:                                     break;
1654 1655 1656
    }
  }

1657 1658 1659 1660 1661 1662 1663 1664 1665 1666
  inline const Coverage &get_coverage (void) const
  {
    switch (u.format) {
    case 1: return this + u.format1.coverage;
    case 2: return this + u.format2.coverage;
    case 3: return u.format3.get_coverage ();
    default:return Null(Coverage);
    }
  }

1667 1668 1669 1670 1671 1672 1673 1674 1675 1676
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
    switch (u.format) {
    case 1: return u.format1.would_apply (c);
    case 2: return u.format2.would_apply (c);
    case 3: return u.format3.would_apply (c);
    default:return false;
    }
  }

B
Behdad Esfahbod 已提交
1677
  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
B
Behdad Esfahbod 已提交
1678
  {
1679
    TRACE_APPLY ();
1680
    switch (u.format) {
1681 1682 1683 1684
    case 1: return TRACE_RETURN (u.format1.apply (c, apply_func));
    case 2: return TRACE_RETURN (u.format2.apply (c, apply_func));
    case 3: return TRACE_RETURN (u.format3.apply (c, apply_func));
    default:return TRACE_RETURN (false);
1685 1686 1687
    }
  }

B
Behdad Esfahbod 已提交
1688
  inline bool sanitize (hb_sanitize_context_t *c) {
1689
    TRACE_SANITIZE ();
1690
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1691
    switch (u.format) {
1692 1693 1694 1695
    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 已提交
1696 1697 1698
    }
  }

1699
  protected:
1700 1701
  union {
  USHORT		format;	/* Format identifier */
B
Behdad Esfahbod 已提交
1702 1703 1704
  ChainContextFormat1	format1;
  ChainContextFormat2	format2;
  ChainContextFormat3	format3;
1705 1706 1707 1708
  } u;
};


1709 1710
struct ExtensionFormat1
{
1711
  friend struct Extension;
1712

B
Behdad Esfahbod 已提交
1713
  protected:
1714
  inline unsigned int get_type (void) const { return extensionLookupType; }
B
Behdad Esfahbod 已提交
1715
  inline unsigned int get_offset (void) const { return extensionOffset; }
1716

B
Behdad Esfahbod 已提交
1717
  inline bool sanitize (hb_sanitize_context_t *c) {
1718
    TRACE_SANITIZE ();
1719
    return TRACE_RETURN (c->check_struct (this));
B
Behdad Esfahbod 已提交
1720 1721
  }

1722
  protected:
1723 1724 1725 1726
  USHORT	format;			/* Format identifier. Set to 1. */
  USHORT	extensionLookupType;	/* Lookup type of subtable referenced
					 * by ExtensionOffset (i.e. the
					 * extension subtable). */
1727 1728
  ULONG		extensionOffset;	/* Offset to the extension subtable,
					 * of lookup type subtable. */
1729 1730
  public:
  DEFINE_SIZE_STATIC (8);
1731 1732 1733 1734 1735 1736 1737
};

struct Extension
{
  inline unsigned int get_type (void) const
  {
    switch (u.format) {
B
Behdad Esfahbod 已提交
1738
    case 1: return u.format1.get_type ();
1739 1740 1741
    default:return 0;
    }
  }
B
Behdad Esfahbod 已提交
1742
  inline unsigned int get_offset (void) const
1743 1744
  {
    switch (u.format) {
B
Behdad Esfahbod 已提交
1745
    case 1: return u.format1.get_offset ();
B
Behdad Esfahbod 已提交
1746
    default:return 0;
1747 1748 1749
    }
  }

B
Behdad Esfahbod 已提交
1750
  inline bool sanitize (hb_sanitize_context_t *c) {
1751
    TRACE_SANITIZE ();
1752
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1753
    switch (u.format) {
1754 1755
    case 1: return TRACE_RETURN (u.format1.sanitize (c));
    default:return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
1756 1757 1758
    }
  }

1759
  protected:
1760 1761
  union {
  USHORT		format;		/* Format identifier */
1762
  ExtensionFormat1	format1;
1763 1764 1765 1766
  } u;
};


B
Behdad Esfahbod 已提交
1767 1768 1769 1770
/*
 * GSUB/GPOS Common
 */

B
Behdad Esfahbod 已提交
1771 1772
struct GSUBGPOS
{
B
Behdad Esfahbod 已提交
1773 1774
  static const hb_tag_t GSUBTag	= HB_OT_TAG_GSUB;
  static const hb_tag_t GPOSTag	= HB_OT_TAG_GPOS;
B
Behdad Esfahbod 已提交
1775

1776 1777 1778 1779
  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 已提交
1780 1781 1782 1783
  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); }
1784 1785 1786 1787 1788 1789 1790 1791 1792
  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 已提交
1793 1794 1795 1796
  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); }
1797 1798 1799 1800 1801 1802 1803 1804 1805
  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 已提交
1806

B
Behdad Esfahbod 已提交
1807
  inline bool sanitize (hb_sanitize_context_t *c) {
1808
    TRACE_SANITIZE ();
1809 1810 1811 1812
    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 已提交
1813 1814
  }

1815
  protected:
B
Behdad Esfahbod 已提交
1816
  FixedVersion	version;	/* Version of the GSUB/GPOS table--initially set
B
Behdad Esfahbod 已提交
1817 1818 1819 1820 1821 1822 1823
				 * to 0x00010000 */
  OffsetTo<ScriptList>
		scriptList;  	/* ScriptList table */
  OffsetTo<FeatureList>
		featureList; 	/* FeatureList table */
  OffsetTo<LookupList>
		lookupList; 	/* LookupList table */
1824 1825
  public:
  DEFINE_SIZE_STATIC (10);
B
Behdad Esfahbod 已提交
1826
};
1827

1828

1829 1830
} // namespace OT

B
Behdad Esfahbod 已提交
1831

1832
#endif /* HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH */