hb-ot-layout-gsubgpos-private.hh 51.4 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

B
Behdad Esfahbod 已提交
37

38 39 40 41 42
#ifndef HB_DEBUG_CLOSURE
#define HB_DEBUG_CLOSURE (HB_DEBUG+0)
#endif

#define TRACE_CLOSURE() \
43
	hb_auto_trace_t<HB_DEBUG_CLOSURE> trace (&c->debug_depth, "CLOSURE", this, HB_FUNC, "");
44 45


46 47 48 49 50 51 52
/* 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, "first %u second %u", c->first, c->second);
B
Minor  
Behdad Esfahbod 已提交
53

54 55 56 57

struct hb_closure_context_t
{
  hb_face_t *face;
58
  hb_set_t *glyphs;
59 60 61 62 63
  unsigned int nesting_level_left;
  unsigned int debug_depth;


  hb_closure_context_t (hb_face_t *face_,
64
			hb_set_t *glyphs_,
65
		        unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) :
66 67
			  face (face_),
			  glyphs (glyphs_),
68 69 70 71 72 73
			  nesting_level_left (nesting_level_left_),
			  debug_depth (0) {}
};



74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91

struct hb_would_apply_context_t
{
  hb_face_t *face;
  hb_codepoint_t first;
  hb_codepoint_t second;
  unsigned int len;
  unsigned int debug_depth;

  hb_would_apply_context_t (hb_face_t *face_,
			    hb_codepoint_t first_,
			    hb_codepoint_t second_ = -1) :
			      face (face_),
			      first (first_), second (second_), len (second == (hb_codepoint_t) -1 ? 1 : 2),
			      debug_depth (0) {};
};


B
Behdad Esfahbod 已提交
92
#ifndef HB_DEBUG_APPLY
93
#define HB_DEBUG_APPLY (HB_DEBUG+0)
B
Behdad Esfahbod 已提交
94 95
#endif

B
Behdad Esfahbod 已提交
96
#define TRACE_APPLY() \
97
	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);
98

B
Behdad Esfahbod 已提交
99

100 101
struct hb_apply_context_t
{
102 103
  hb_font_t *font;
  hb_face_t *face;
B
Behdad Esfahbod 已提交
104
  hb_buffer_t *buffer;
105
  hb_direction_t direction;
B
Behdad Esfahbod 已提交
106
  hb_mask_t lookup_mask;
107
  unsigned int nesting_level_left;
108
  unsigned int lookup_props;
109
  unsigned int property; /* propety of first glyph */
110
  unsigned int debug_depth;
111
  const GDEF &gdef;
112
  bool has_glyph_classes;
113
  const hb_set_digest_t *digest;
114

115 116 117 118

  hb_apply_context_t (hb_font_t *font_,
		      hb_face_t *face_,
		      hb_buffer_t *buffer_,
119 120
		      hb_mask_t lookup_mask_,
		      const hb_set_digest_t *digest_) :
121 122 123
			font (font_), face (face_), buffer (buffer_),
			direction (buffer_->props.direction),
			lookup_mask (lookup_mask_),
B
Minor  
Behdad Esfahbod 已提交
124
			nesting_level_left (MAX_NESTING_LEVEL),
125
			lookup_props (0), property (0), debug_depth (0),
126 127 128
			gdef (hb_ot_layout_from_face (face_) &&
			      !HB_SHAPER_DATA_IS_INVALID (hb_ot_layout_from_face (face_)) ?
			      *hb_ot_layout_from_face (face_)->gdef : Null(GDEF)),
129 130
			has_glyph_classes (gdef.has_glyph_classes ()),
			digest (digest_) {}
131

B
Behdad Esfahbod 已提交
132
  void set_lookup (const Lookup &l) {
133 134 135
    lookup_props = l.get_props ();
  }

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

    unsigned int idx;
177
    protected:
B
Behdad Esfahbod 已提交
178 179
    hb_apply_context_t *c;
    unsigned int num_items;
180
    hb_mask_t mask;
181
    uint8_t syllable;
B
Behdad Esfahbod 已提交
182 183 184 185 186 187 188
    unsigned int end;
  };

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

    unsigned int idx;
226
    protected:
B
Behdad Esfahbod 已提交
227 228
    hb_apply_context_t *c;
    unsigned int num_items;
229
    hb_mask_t mask;
230
    uint8_t syllable;
B
Behdad Esfahbod 已提交
231 232
  };

233 234 235 236 237 238 239 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
  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
275
  {
B
Behdad Esfahbod 已提交
276
    unsigned int property;
277

B
Minor  
Behdad Esfahbod 已提交
278
    property = info->glyph_props();
279 280 281 282 283 284 285 286 287 288 289 290
    *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 已提交
291
    property = info->glyph_props();
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306
    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);
307
  }
B
Behdad Esfahbod 已提交
308

309
  inline void set_class (hb_codepoint_t glyph_index, unsigned int class_guess) const
310
  {
311
    if (likely (has_glyph_classes))
B
Minor  
Behdad Esfahbod 已提交
312
      buffer->cur().glyph_props() = gdef.get_glyph_props (glyph_index);
313
    else if (class_guess)
B
Minor  
Behdad Esfahbod 已提交
314
      buffer->cur().glyph_props() = class_guess;
315
  }
B
Behdad Esfahbod 已提交
316

317
  inline void output_glyph (hb_codepoint_t glyph_index,
318
			    unsigned int class_guess = 0) const
319
  {
320
    set_class (glyph_index, class_guess);
321 322
    buffer->output_glyph (glyph_index);
  }
323
  inline void replace_glyph (hb_codepoint_t glyph_index,
324
			     unsigned int class_guess = 0) const
325
  {
326
    set_class (glyph_index, class_guess);
327 328
    buffer->replace_glyph (glyph_index);
  }
B
Behdad Esfahbod 已提交
329
  inline void replace_glyph_inplace (hb_codepoint_t glyph_index,
330
				     unsigned int class_guess = 0) const
B
Behdad Esfahbod 已提交
331
  {
332
    set_class (glyph_index, class_guess);
B
Behdad Esfahbod 已提交
333 334
    buffer->cur().codepoint = glyph_index;
  }
335 336
};

337

B
Behdad Esfahbod 已提交
338

339
typedef bool (*intersects_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data);
B
Behdad Esfahbod 已提交
340
typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data);
B
Behdad Esfahbod 已提交
341
typedef void (*closure_lookup_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
B
Behdad Esfahbod 已提交
342
typedef bool (*apply_lookup_func_t) (hb_apply_context_t *c, unsigned int lookup_index);
343

344 345 346 347 348 349
struct ContextClosureFuncs
{
  intersects_func_t intersects;
  closure_lookup_func_t closure;
};
struct ContextApplyFuncs
B
Behdad Esfahbod 已提交
350
{
351 352
  match_func_t match;
  apply_lookup_func_t apply;
353 354
};

355
static inline bool intersects_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED)
356 357 358
{
  return glyphs->has (value);
}
359
static inline bool intersects_class (hb_set_t *glyphs, const USHORT &value, const void *data)
360 361 362 363
{
  const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
  return class_def.intersects_class (glyphs, value);
}
364
static inline bool intersects_coverage (hb_set_t *glyphs, const USHORT &value, const void *data)
365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381
{
  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;
}

382

B
Behdad Esfahbod 已提交
383
static inline bool match_glyph (hb_codepoint_t glyph_id, const USHORT &value, const void *data HB_UNUSED)
B
Behdad Esfahbod 已提交
384
{
385 386
  return glyph_id == value;
}
B
Behdad Esfahbod 已提交
387
static inline bool match_class (hb_codepoint_t glyph_id, const USHORT &value, const void *data)
B
Behdad Esfahbod 已提交
388
{
B
Behdad Esfahbod 已提交
389
  const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
390 391
  return class_def.get_class (glyph_id) == value;
}
B
Behdad Esfahbod 已提交
392
static inline bool match_coverage (hb_codepoint_t glyph_id, const USHORT &value, const void *data)
B
Behdad Esfahbod 已提交
393
{
394
  const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
395
  return (data+coverage).get_coverage (glyph_id) != NOT_COVERED;
396 397
}

398

399 400 401 402 403 404 405 406 407 408 409 410 411 412 413
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++)
    if (likely (!match_func (c->second, input[i - 1], match_data)))
      return false;

  return true;
}
B
Behdad Esfahbod 已提交
414
static inline bool match_input (hb_apply_context_t *c,
B
Behdad Esfahbod 已提交
415 416 417
				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 已提交
418
				const void *match_data,
419
				unsigned int *end_offset = NULL)
B
Behdad Esfahbod 已提交
420
{
B
Behdad Esfahbod 已提交
421 422
  hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1);
  if (skippy_iter.has_no_chance ())
B
Behdad Esfahbod 已提交
423
    return false;
B
Behdad Esfahbod 已提交
424

B
Minor  
Behdad Esfahbod 已提交
425
  for (unsigned int i = 1; i < count; i++)
B
Behdad Esfahbod 已提交
426
  {
B
Behdad Esfahbod 已提交
427 428
    if (!skippy_iter.next ())
      return false;
B
Behdad Esfahbod 已提交
429

B
Behdad Esfahbod 已提交
430
    if (likely (!match_func (c->buffer->info[skippy_iter.idx].codepoint, input[i - 1], match_data)))
B
Behdad Esfahbod 已提交
431 432 433
      return false;
  }

434 435
  if (end_offset)
    *end_offset = skippy_iter.idx - c->buffer->idx + 1;
B
Behdad Esfahbod 已提交
436 437 438 439

  return true;
}

B
Behdad Esfahbod 已提交
440
static inline bool match_backtrack (hb_apply_context_t *c,
441 442 443
				    unsigned int count,
				    const USHORT backtrack[],
				    match_func_t match_func,
B
Behdad Esfahbod 已提交
444
				    const void *match_data)
445
{
B
Minor  
Behdad Esfahbod 已提交
446
  hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->backtrack_len (), count, true);
B
Behdad Esfahbod 已提交
447 448
  if (skippy_iter.has_no_chance ())
    return false;
449

450
  for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
451
  {
B
Behdad Esfahbod 已提交
452 453
    if (!skippy_iter.prev ())
      return false;
454

B
Behdad Esfahbod 已提交
455
    if (likely (!match_func (c->buffer->out_info[skippy_iter.idx].codepoint, backtrack[i], match_data)))
456 457 458 459 460 461
      return false;
  }

  return true;
}

B
Behdad Esfahbod 已提交
462
static inline bool match_lookahead (hb_apply_context_t *c,
B
Behdad Esfahbod 已提交
463 464 465
				    unsigned int count,
				    const USHORT lookahead[],
				    match_func_t match_func,
B
Behdad Esfahbod 已提交
466
				    const void *match_data,
B
Behdad Esfahbod 已提交
467
				    unsigned int offset)
468
{
B
Minor  
Behdad Esfahbod 已提交
469
  hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx + offset - 1, count, true);
B
Behdad Esfahbod 已提交
470 471
  if (skippy_iter.has_no_chance ())
    return false;
472

B
Minor  
Behdad Esfahbod 已提交
473
  for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
474
  {
B
Behdad Esfahbod 已提交
475 476
    if (!skippy_iter.next ())
      return false;
477

B
Behdad Esfahbod 已提交
478
    if (likely (!match_func (c->buffer->info[skippy_iter.idx].codepoint, lookahead[i], match_data)))
479 480 481
      return false;
  }

482 483 484
  return true;
}

B
Behdad Esfahbod 已提交
485

486

B
Behdad Esfahbod 已提交
487 488
struct LookupRecord
{
B
Behdad Esfahbod 已提交
489
  inline bool sanitize (hb_sanitize_context_t *c) {
490
    TRACE_SANITIZE ();
491
    return TRACE_RETURN (c->check_struct (this));
B
Behdad Esfahbod 已提交
492 493
  }

494 495 496 497
  USHORT	sequenceIndex;		/* Index into current glyph
					 * sequence--first glyph = 0 */
  USHORT	lookupListIndex;	/* Lookup to apply to that
					 * position--zero--based */
B
Behdad Esfahbod 已提交
498 499
  public:
  DEFINE_SIZE_STATIC (4);
500 501
};

B
Behdad Esfahbod 已提交
502

B
Behdad Esfahbod 已提交
503
static inline void closure_lookup (hb_closure_context_t *c,
504 505 506 507 508
				   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 已提交
509
    closure_func (c, lookupRecord->lookupListIndex);
510
}
B
Behdad Esfahbod 已提交
511

B
Behdad Esfahbod 已提交
512
static inline bool apply_lookup (hb_apply_context_t *c,
513 514
				 unsigned int count, /* Including the first glyph */
				 unsigned int lookupCount,
515 516 517
				 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
				 apply_lookup_func_t apply_func)
{
518
  unsigned int end = c->buffer->len;
519
  if (unlikely (count == 0 || c->buffer->idx + count > end))
520
    return false;
521

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

525
  /* Note: If sublookup is reverse, it will underflow after the first loop
B
Behdad Esfahbod 已提交
526 527 528
   * and we jump out of it.  Not entirely disastrous.  So we don't check
   * for reverse lookup here.
   */
B
Behdad Esfahbod 已提交
529
  for (unsigned int i = 0; i < count; /* NOP */)
B
Behdad Esfahbod 已提交
530
  {
531 532
    if (unlikely (c->buffer->idx == end))
      return true;
533
    while (c->should_mark_skip_current_glyph ())
B
Behdad Esfahbod 已提交
534
    {
535
      /* No lookup applied for this index */
B
Behdad Esfahbod 已提交
536
      c->buffer->next_glyph ();
537 538
      if (unlikely (c->buffer->idx == end))
	return true;
539 540
    }

B
Behdad Esfahbod 已提交
541
    if (lookupCount && i == lookupRecord->sequenceIndex)
542
    {
543
      unsigned int old_pos = c->buffer->idx;
544 545

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

B
Behdad Esfahbod 已提交
548 549
      lookupRecord++;
      lookupCount--;
B
Behdad Esfahbod 已提交
550
      /* Err, this is wrong if the lookup jumped over some glyphs */
551 552
      i += c->buffer->idx - old_pos;
      if (unlikely (c->buffer->idx == end))
553
	return true;
554 555 556 557 558 559 560 561

      if (!done)
	goto not_applied;
    }
    else
    {
    not_applied:
      /* No lookup applied for this index */
B
Behdad Esfahbod 已提交
562
      c->buffer->next_glyph ();
563 564 565 566 567 568
      i++;
    }
  }

  return true;
}
569

B
Behdad Esfahbod 已提交
570

571 572 573

/* Contextual lookups */

574 575 576 577 578 579 580
struct ContextClosureLookupContext
{
  ContextClosureFuncs funcs;
  const void *intersects_data;
};

struct ContextApplyLookupContext
B
Behdad Esfahbod 已提交
581
{
582
  ContextApplyFuncs funcs;
B
Behdad Esfahbod 已提交
583
  const void *match_data;
584 585
};

B
Behdad Esfahbod 已提交
586
static inline void context_closure_lookup (hb_closure_context_t *c,
587 588 589 590 591 592
					   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 已提交
593 594 595 596 597 598
  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);
599 600 601
}


602 603 604 605 606 607 608 609 610 611 612
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);
}
613 614 615 616 617 618
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)
619
{
B
Behdad Esfahbod 已提交
620
  return match_input (c,
B
Behdad Esfahbod 已提交
621
		      inputCount, input,
622 623
		      lookup_context.funcs.match, lookup_context.match_data)
      && apply_lookup (c,
B
Behdad Esfahbod 已提交
624 625 626
		       inputCount,
		       lookupCount, lookupRecord,
		       lookup_context.funcs.apply);
627 628
}

B
Behdad Esfahbod 已提交
629 630
struct Rule
{
631 632 633
  friend struct RuleSet;

  private:
634

B
Behdad Esfahbod 已提交
635
  inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
636 637 638
  {
    TRACE_CLOSURE ();
    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
B
Behdad Esfahbod 已提交
639 640 641 642
    context_closure_lookup (c,
			    inputCount, input,
			    lookupCount, lookupRecord,
			    lookup_context);
643 644
  }

645 646 647 648 649 650 651
  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));
  }

652
  inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
B
Behdad Esfahbod 已提交
653
  {
654
    TRACE_APPLY ();
B
Behdad Esfahbod 已提交
655
    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
656
    return TRACE_RETURN (context_apply_lookup (c, inputCount, input, lookupCount, lookupRecord, lookup_context));
657 658
  }

B
Behdad Esfahbod 已提交
659
  public:
B
Behdad Esfahbod 已提交
660
  inline bool sanitize (hb_sanitize_context_t *c) {
661
    TRACE_SANITIZE ();
B
Behdad Esfahbod 已提交
662 663 664
    return inputCount.sanitize (c)
	&& lookupCount.sanitize (c)
	&& c->check_range (input,
665 666
			   input[0].static_size * inputCount
			   + lookupRecordX[0].static_size * lookupCount);
B
Behdad Esfahbod 已提交
667 668
  }

669
  protected:
670
  USHORT	inputCount;		/* Total number of glyphs in input
671
					 * glyph sequence--includes the first
672
					 * glyph */
673
  USHORT	lookupCount;		/* Number of LookupRecords */
B
Behdad Esfahbod 已提交
674
  USHORT	input[VAR];		/* Array of match inputs--start with
675
					 * second glyph */
B
Behdad Esfahbod 已提交
676
  LookupRecord	lookupRecordX[VAR];	/* Array of LookupRecords--in
677
					 * design order */
B
Behdad Esfahbod 已提交
678
  public:
679
  DEFINE_SIZE_ARRAY2 (4, input, lookupRecordX);
680 681
};

B
Behdad Esfahbod 已提交
682 683
struct RuleSet
{
B
Behdad Esfahbod 已提交
684
  inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
685 686 687 688
  {
    TRACE_CLOSURE ();
    unsigned int num_rules = rule.len;
    for (unsigned int i = 0; i < num_rules; i++)
B
Behdad Esfahbod 已提交
689
      (this+rule[i]).closure (c, lookup_context);
690 691
  }

692 693 694 695 696 697 698 699 700 701 702 703
  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);
  }

704
  inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
B
Behdad Esfahbod 已提交
705
  {
706
    TRACE_APPLY ();
707
    unsigned int num_rules = rule.len;
B
Behdad Esfahbod 已提交
708 709
    for (unsigned int i = 0; i < num_rules; i++)
    {
B
Behdad Esfahbod 已提交
710
      if ((this+rule[i]).apply (c, lookup_context))
711
        return TRACE_RETURN (true);
712
    }
713
    return TRACE_RETURN (false);
714 715
  }

B
Behdad Esfahbod 已提交
716
  inline bool sanitize (hb_sanitize_context_t *c) {
717
    TRACE_SANITIZE ();
718
    return TRACE_RETURN (rule.sanitize (c, this));
B
Behdad Esfahbod 已提交
719 720
  }

721
  protected:
722
  OffsetArrayOf<Rule>
723
		rule;			/* Array of Rule tables
724
					 * ordered by preference */
B
Behdad Esfahbod 已提交
725
  public:
726
  DEFINE_SIZE_ARRAY (2, rule);
727 728 729
};


B
Behdad Esfahbod 已提交
730 731
struct ContextFormat1
{
732 733 734
  friend struct Context;

  private:
735

B
Behdad Esfahbod 已提交
736
  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
737 738
  {
    TRACE_CLOSURE ();
739 740 741 742 743 744 745 746 747 748 749 750

    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 已提交
751
	rule_set.closure (c, lookup_context);
752
      }
753 754
  }

755 756 757 758
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
    TRACE_WOULD_APPLY ();

B
Behdad Esfahbod 已提交
759
    const RuleSet &rule_set = this+ruleSet[(this+coverage) (c->first)];
760 761 762 763 764 765 766
    struct ContextApplyLookupContext lookup_context = {
      {match_glyph, NULL},
      NULL
    };
    return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
  }

B
Behdad Esfahbod 已提交
767
  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
B
Behdad Esfahbod 已提交
768
  {
769
    TRACE_APPLY ();
770
    unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
771
    if (likely (index == NOT_COVERED))
772
      return TRACE_RETURN (false);
773

774
    const RuleSet &rule_set = this+ruleSet[index];
775
    struct ContextApplyLookupContext lookup_context = {
776 777
      {match_glyph, apply_func},
      NULL
778
    };
779
    return TRACE_RETURN (rule_set.apply (c, lookup_context));
780 781
  }

B
Behdad Esfahbod 已提交
782
  inline bool sanitize (hb_sanitize_context_t *c) {
783
    TRACE_SANITIZE ();
784
    return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
785 786
  }

787
  protected:
788 789 790 791 792 793 794
  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 */
795
  public:
796
  DEFINE_SIZE_ARRAY (6, ruleSet);
797 798 799
};


B
Behdad Esfahbod 已提交
800 801
struct ContextFormat2
{
802 803 804
  friend struct Context;

  private:
805

B
Behdad Esfahbod 已提交
806
  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
807 808
  {
    TRACE_CLOSURE ();
809
    if (!(this+coverage).intersects (c->glyphs))
B
Behdad Esfahbod 已提交
810
      return;
811 812 813 814 815 816 817 818 819 820 821 822

    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 已提交
823
	rule_set.closure (c, lookup_context);
824
      }
825 826
  }

827 828 829 830 831
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
    TRACE_WOULD_APPLY ();

    const ClassDef &class_def = this+classDef;
B
Behdad Esfahbod 已提交
832
    unsigned int index = class_def (c->first);
833 834 835 836 837 838 839 840
    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 已提交
841
  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
B
Behdad Esfahbod 已提交
842
  {
843
    TRACE_APPLY ();
844
    unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
845
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
846 847

    const ClassDef &class_def = this+classDef;
848
    index = class_def (c->buffer->cur().codepoint);
849
    const RuleSet &rule_set = this+ruleSet[index];
850
    struct ContextApplyLookupContext lookup_context = {
B
Behdad Esfahbod 已提交
851 852
      {match_class, apply_func},
      &class_def
853
    };
854
    return TRACE_RETURN (rule_set.apply (c, lookup_context));
855 856
  }

B
Behdad Esfahbod 已提交
857
  inline bool sanitize (hb_sanitize_context_t *c) {
858
    TRACE_SANITIZE ();
859
    return TRACE_RETURN (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
860 861
  }

862
  protected:
863 864 865 866 867 868 869 870 871 872
  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 */
873
  public:
874
  DEFINE_SIZE_ARRAY (8, ruleSet);
875 876 877
};


B
Behdad Esfahbod 已提交
878 879
struct ContextFormat3
{
880 881 882
  friend struct Context;

  private:
883

B
Behdad Esfahbod 已提交
884
  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
885 886
  {
    TRACE_CLOSURE ();
887
    if (!(this+coverage[0]).intersects (c->glyphs))
B
Behdad Esfahbod 已提交
888
      return;
889 890 891 892 893 894

    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
    struct ContextClosureLookupContext lookup_context = {
      {intersects_coverage, closure_func},
      this
    };
B
Behdad Esfahbod 已提交
895 896 897 898
    context_closure_lookup (c,
			    glyphCount, (const USHORT *) (coverage + 1),
			    lookupCount, lookupRecord,
			    lookup_context);
899 900
  }

901 902 903 904 905 906 907 908 909 910 911 912
  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 已提交
913
  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
B
Behdad Esfahbod 已提交
914
  {
915
    TRACE_APPLY ();
916
    unsigned int index = (this+coverage[0]) (c->buffer->cur().codepoint);
917
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
918

B
Behdad Esfahbod 已提交
919
    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
920
    struct ContextApplyLookupContext lookup_context = {
921
      {match_coverage, apply_func},
B
Behdad Esfahbod 已提交
922
      this
923
    };
924
    return TRACE_RETURN (context_apply_lookup (c, glyphCount, (const USHORT *) (coverage + 1), lookupCount, lookupRecord, lookup_context));
925 926
  }

B
Behdad Esfahbod 已提交
927
  inline bool sanitize (hb_sanitize_context_t *c) {
928
    TRACE_SANITIZE ();
929
    if (!c->check_struct (this)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
930
    unsigned int count = glyphCount;
931
    if (unlikely (!glyphCount)) return TRACE_RETURN (false);
932
    if (!c->check_array (coverage, coverage[0].static_size, count)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
933
    for (unsigned int i = 0; i < count; i++)
934
      if (!coverage[i].sanitize (c, this)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
935
    LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * count);
936
    return TRACE_RETURN (c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount));
B
Behdad Esfahbod 已提交
937 938
  }

939
  protected:
940 941 942
  USHORT	format;			/* Format identifier--format = 3 */
  USHORT	glyphCount;		/* Number of glyphs in the input glyph
					 * sequence */
943
  USHORT	lookupCount;		/* Number of LookupRecords */
944
  OffsetTo<Coverage>
B
Behdad Esfahbod 已提交
945
		coverage[VAR];		/* Array of offsets to Coverage
946
					 * table in glyph sequence order */
B
Behdad Esfahbod 已提交
947
  LookupRecord	lookupRecordX[VAR];	/* Array of LookupRecords--in
948
					 * design order */
B
Behdad Esfahbod 已提交
949
  public:
950
  DEFINE_SIZE_ARRAY2 (6, coverage, lookupRecordX);
951 952
};

B
Behdad Esfahbod 已提交
953 954
struct Context
{
955
  protected:
956

B
Behdad Esfahbod 已提交
957
  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
958 959 960
  {
    TRACE_CLOSURE ();
    switch (u.format) {
B
Behdad Esfahbod 已提交
961 962 963 964
    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;
965 966 967
    }
  }

968 969 970 971 972 973 974 975 976 977
  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);
    }
  }

978 979 980 981 982 983 984 985 986 987
  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 已提交
988
  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
B
Behdad Esfahbod 已提交
989
  {
990
    TRACE_APPLY ();
991
    switch (u.format) {
992 993 994 995
    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);
996 997 998
    }
  }

B
Behdad Esfahbod 已提交
999
  inline bool sanitize (hb_sanitize_context_t *c) {
1000
    TRACE_SANITIZE ();
1001
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1002
    switch (u.format) {
1003 1004 1005 1006
    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 已提交
1007 1008 1009
    }
  }

1010
  protected:
1011
  union {
B
Behdad Esfahbod 已提交
1012
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1013 1014 1015
  ContextFormat1	format1;
  ContextFormat2	format2;
  ContextFormat3	format3;
1016 1017 1018
  } u;
};

1019 1020 1021

/* Chaining Contextual lookups */

1022
struct ChainContextClosureLookupContext
B
Behdad Esfahbod 已提交
1023
{
1024 1025 1026 1027 1028 1029 1030
  ContextClosureFuncs funcs;
  const void *intersects_data[3];
};

struct ChainContextApplyLookupContext
{
  ContextApplyFuncs funcs;
B
Behdad Esfahbod 已提交
1031
  const void *match_data[3];
1032 1033
};

B
Behdad Esfahbod 已提交
1034
static inline void chain_context_closure_lookup (hb_closure_context_t *c,
1035 1036 1037 1038 1039 1040 1041 1042 1043 1044
						 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 已提交
1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056
  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);
1057 1058
}

1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076
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)
{
  return !backtrackCount
      && !lookaheadCount
      && would_match_input (c,
			    inputCount, input,
			    lookup_context.funcs.match, lookup_context.match_data[1]);
}

1077 1078 1079 1080 1081 1082 1083 1084 1085 1086
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)
1087
{
1088
  unsigned int lookahead_offset;
B
Behdad Esfahbod 已提交
1089
  return match_input (c,
B
Behdad Esfahbod 已提交
1090 1091
		      inputCount, input,
		      lookup_context.funcs.match, lookup_context.match_data[1],
1092
		      &lookahead_offset)
B
Behdad Esfahbod 已提交
1093 1094 1095
      && match_backtrack (c,
			  backtrackCount, backtrack,
			  lookup_context.funcs.match, lookup_context.match_data[0])
B
Behdad Esfahbod 已提交
1096
      && match_lookahead (c,
B
Behdad Esfahbod 已提交
1097 1098
			  lookaheadCount, lookahead,
			  lookup_context.funcs.match, lookup_context.match_data[2],
1099 1100
			  lookahead_offset)
      && apply_lookup (c,
B
Behdad Esfahbod 已提交
1101 1102 1103
		       inputCount,
		       lookupCount, lookupRecord,
		       lookup_context.funcs.apply);
1104
}
1105

B
Behdad Esfahbod 已提交
1106 1107
struct ChainRule
{
1108 1109 1110
  friend struct ChainRuleSet;

  private:
1111

B
Behdad Esfahbod 已提交
1112
  inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
1113 1114 1115 1116 1117
  {
    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 已提交
1118 1119 1120 1121 1122 1123
    chain_context_closure_lookup (c,
				  backtrack.len, backtrack.array,
				  input.len, input.array,
				  lookahead.len, lookahead.array,
				  lookup.len, lookup.array,
				  lookup_context);
1124 1125
  }

1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138
  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));
  }

1139
  inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
B
Behdad Esfahbod 已提交
1140
  {
1141
    TRACE_APPLY ();
1142 1143 1144
    const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
    const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1145 1146 1147 1148 1149
    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));
1150 1151
  }

B
Behdad Esfahbod 已提交
1152
  public:
B
Behdad Esfahbod 已提交
1153
  inline bool sanitize (hb_sanitize_context_t *c) {
1154
    TRACE_SANITIZE ();
1155
    if (!backtrack.sanitize (c)) return TRACE_RETURN (false);
1156
    HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
1157
    if (!input.sanitize (c)) return TRACE_RETURN (false);
1158
    ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
1159
    if (!lookahead.sanitize (c)) return TRACE_RETURN (false);
1160
    ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1161
    return TRACE_RETURN (lookup.sanitize (c));
B
Behdad Esfahbod 已提交
1162
  }
1163

1164
  protected:
B
Behdad Esfahbod 已提交
1165 1166
  ArrayOf<USHORT>
		backtrack;		/* Array of backtracking values
1167 1168
					 * (to be matched before the input
					 * sequence) */
B
Behdad Esfahbod 已提交
1169 1170
  HeadlessArrayOf<USHORT>
		inputX;			/* Array of input values (start with
1171
					 * second glyph) */
B
Behdad Esfahbod 已提交
1172 1173
  ArrayOf<USHORT>
		lookaheadX;		/* Array of lookahead values's (to be
1174
					 * matched after the input sequence) */
B
Behdad Esfahbod 已提交
1175
  ArrayOf<LookupRecord>
1176
		lookupX;		/* Array of LookupRecords--in
1177
					 * design order) */
1178
  public:
B
Behdad Esfahbod 已提交
1179
  DEFINE_SIZE_MIN (8);
1180 1181
};

B
Behdad Esfahbod 已提交
1182 1183
struct ChainRuleSet
{
B
Behdad Esfahbod 已提交
1184
  inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
1185 1186 1187 1188
  {
    TRACE_CLOSURE ();
    unsigned int num_rules = rule.len;
    for (unsigned int i = 0; i < num_rules; i++)
B
Behdad Esfahbod 已提交
1189
      (this+rule[i]).closure (c, lookup_context);
1190 1191
  }

1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202
  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);
  }

1203
  inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
B
Behdad Esfahbod 已提交
1204
  {
1205
    TRACE_APPLY ();
1206
    unsigned int num_rules = rule.len;
B
Behdad Esfahbod 已提交
1207
    for (unsigned int i = 0; i < num_rules; i++)
B
Behdad Esfahbod 已提交
1208
      if ((this+rule[i]).apply (c, lookup_context))
1209
        return TRACE_RETURN (true);
1210

1211
    return TRACE_RETURN (false);
1212
  }
1213

B
Behdad Esfahbod 已提交
1214
  inline bool sanitize (hb_sanitize_context_t *c) {
1215
    TRACE_SANITIZE ();
1216
    return TRACE_RETURN (rule.sanitize (c, this));
B
Behdad Esfahbod 已提交
1217 1218
  }

1219
  protected:
1220 1221 1222
  OffsetArrayOf<ChainRule>
		rule;			/* Array of ChainRule tables
					 * ordered by preference */
1223
  public:
1224
  DEFINE_SIZE_ARRAY (2, rule);
1225 1226
};

B
Behdad Esfahbod 已提交
1227 1228
struct ChainContextFormat1
{
1229 1230 1231
  friend struct ChainContext;

  private:
1232

B
Behdad Esfahbod 已提交
1233
  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
1234 1235
  {
    TRACE_CLOSURE ();
1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246
    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 已提交
1247
	rule_set.closure (c, lookup_context);
1248
      }
1249 1250
  }

1251 1252 1253 1254
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
    TRACE_WOULD_APPLY ();

B
Behdad Esfahbod 已提交
1255
    const ChainRuleSet &rule_set = this+ruleSet[(this+coverage) (c->first)];
1256 1257 1258 1259 1260 1261 1262
    struct ChainContextApplyLookupContext lookup_context = {
      {match_glyph, NULL},
      {NULL, NULL, NULL}
    };
    return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
  }

B
Behdad Esfahbod 已提交
1263
  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
B
Behdad Esfahbod 已提交
1264
  {
1265
    TRACE_APPLY ();
1266
    unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
1267
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
1268

1269
    const ChainRuleSet &rule_set = this+ruleSet[index];
1270
    struct ChainContextApplyLookupContext lookup_context = {
1271 1272 1273
      {match_glyph, apply_func},
      {NULL, NULL, NULL}
    };
1274
    return TRACE_RETURN (rule_set.apply (c, lookup_context));
1275
  }
B
Behdad Esfahbod 已提交
1276

B
Behdad Esfahbod 已提交
1277
  inline bool sanitize (hb_sanitize_context_t *c) {
1278
    TRACE_SANITIZE ();
1279
    return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
1280 1281
  }

1282
  protected:
1283
  USHORT	format;			/* Format identifier--format = 1 */
1284 1285
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
1286
					 * beginning of table */
1287 1288 1289
  OffsetArrayOf<ChainRuleSet>
		ruleSet;		/* Array of ChainRuleSet tables
					 * ordered by Coverage Index */
1290
  public:
1291
  DEFINE_SIZE_ARRAY (6, ruleSet);
1292 1293
};

B
Behdad Esfahbod 已提交
1294 1295
struct ChainContextFormat2
{
1296 1297 1298
  friend struct ChainContext;

  private:
1299

B
Behdad Esfahbod 已提交
1300
  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
1301 1302
  {
    TRACE_CLOSURE ();
1303
    if (!(this+coverage).intersects (c->glyphs))
B
Behdad Esfahbod 已提交
1304
      return;
1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320

    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 已提交
1321
	rule_set.closure (c, lookup_context);
1322
      }
1323 1324
  }

1325 1326 1327 1328 1329 1330
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
    TRACE_WOULD_APPLY ();

    const ClassDef &input_class_def = this+inputClassDef;

B
Behdad Esfahbod 已提交
1331
    unsigned int index = input_class_def (c->first);
1332 1333 1334 1335 1336 1337 1338 1339
    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 已提交
1340
  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
B
Behdad Esfahbod 已提交
1341
  {
1342
    TRACE_APPLY ();
1343
    unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
1344
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
1345 1346 1347 1348 1349

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

1350
    index = input_class_def (c->buffer->cur().codepoint);
1351
    const ChainRuleSet &rule_set = this+ruleSet[index];
1352
    struct ChainContextApplyLookupContext lookup_context = {
B
Behdad Esfahbod 已提交
1353 1354 1355 1356
      {match_class, apply_func},
      {&backtrack_class_def,
       &input_class_def,
       &lookahead_class_def}
1357
    };
1358
    return TRACE_RETURN (rule_set.apply (c, lookup_context));
1359 1360
  }

B
Behdad Esfahbod 已提交
1361
  inline bool sanitize (hb_sanitize_context_t *c) {
1362
    TRACE_SANITIZE ();
1363 1364 1365
    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 已提交
1366 1367
  }

1368
  protected:
1369
  USHORT	format;			/* Format identifier--format = 2 */
1370 1371
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
1372
					 * beginning of table */
1373 1374
  OffsetTo<ClassDef>
		backtrackClassDef;	/* Offset to glyph ClassDef table
1375 1376
					 * containing backtrack sequence
					 * data--from beginning of table */
1377 1378
  OffsetTo<ClassDef>
		inputClassDef;		/* Offset to glyph ClassDef
1379 1380
					 * table containing input sequence
					 * data--from beginning of table */
1381 1382
  OffsetTo<ClassDef>
		lookaheadClassDef;	/* Offset to glyph ClassDef table
1383 1384
					 * containing lookahead sequence
					 * data--from beginning of table */
1385 1386 1387
  OffsetArrayOf<ChainRuleSet>
		ruleSet;		/* Array of ChainRuleSet tables
					 * ordered by class */
1388
  public:
1389
  DEFINE_SIZE_ARRAY (12, ruleSet);
1390 1391
};

B
Behdad Esfahbod 已提交
1392 1393
struct ChainContextFormat3
{
1394 1395 1396
  friend struct ChainContext;

  private:
1397

B
Behdad Esfahbod 已提交
1398
  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
1399 1400
  {
    TRACE_CLOSURE ();
B
Behdad Esfahbod 已提交
1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417
    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);
1418 1419
  }

1420 1421 1422 1423 1424 1425
  inline const Coverage &get_coverage (void) const
  {
    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
    return this+input[0];
  }

1426 1427 1428 1429
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
    TRACE_WOULD_APPLY ();

B
Behdad Esfahbod 已提交
1430
    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443
    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 已提交
1444
  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
B
Behdad Esfahbod 已提交
1445
  {
1446
    TRACE_APPLY ();
1447
    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1448

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

1452 1453
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1454
    struct ChainContextApplyLookupContext lookup_context = {
1455
      {match_coverage, apply_func},
B
Behdad Esfahbod 已提交
1456
      {this, this, this}
1457
    };
1458 1459 1460 1461 1462
    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));
1463 1464
  }

B
Behdad Esfahbod 已提交
1465
  inline bool sanitize (hb_sanitize_context_t *c) {
1466
    TRACE_SANITIZE ();
1467
    if (!backtrack.sanitize (c, this)) return TRACE_RETURN (false);
1468
    OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1469
    if (!input.sanitize (c, this)) return TRACE_RETURN (false);
1470
    if (unlikely (!input.len)) return TRACE_RETURN (false);
1471
    OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
1472
    if (!lookahead.sanitize (c, this)) return TRACE_RETURN (false);
1473
    ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1474
    return TRACE_RETURN (lookup.sanitize (c));
B
Behdad Esfahbod 已提交
1475 1476
  }

1477
  protected:
1478
  USHORT	format;			/* Format identifier--format = 3 */
B
Behdad Esfahbod 已提交
1479
  OffsetArrayOf<Coverage>
1480
		backtrack;		/* Array of coverage tables
1481 1482
					 * in backtracking sequence, in  glyph
					 * sequence order */
B
Behdad Esfahbod 已提交
1483
  OffsetArrayOf<Coverage>
1484
		inputX		;	/* Array of coverage
1485 1486
					 * tables in input sequence, in glyph
					 * sequence order */
B
Behdad Esfahbod 已提交
1487
  OffsetArrayOf<Coverage>
1488
		lookaheadX;		/* Array of coverage tables
1489 1490
					 * in lookahead sequence, in glyph
					 * sequence order */
B
Behdad Esfahbod 已提交
1491
  ArrayOf<LookupRecord>
1492
		lookupX;		/* Array of LookupRecords--in
B
Behdad Esfahbod 已提交
1493
					 * design order) */
1494
  public:
B
Behdad Esfahbod 已提交
1495
  DEFINE_SIZE_MIN (10);
1496 1497
};

B
Behdad Esfahbod 已提交
1498 1499
struct ChainContext
{
1500
  protected:
1501

B
Behdad Esfahbod 已提交
1502
  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
1503 1504 1505
  {
    TRACE_CLOSURE ();
    switch (u.format) {
B
Behdad Esfahbod 已提交
1506 1507 1508 1509
    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;
1510 1511 1512
    }
  }

1513 1514 1515 1516 1517 1518 1519 1520 1521 1522
  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);
    }
  }

1523 1524 1525 1526 1527 1528 1529 1530 1531 1532
  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 已提交
1533
  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
B
Behdad Esfahbod 已提交
1534
  {
1535
    TRACE_APPLY ();
1536
    switch (u.format) {
1537 1538 1539 1540
    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);
1541 1542 1543
    }
  }

B
Behdad Esfahbod 已提交
1544
  inline bool sanitize (hb_sanitize_context_t *c) {
1545
    TRACE_SANITIZE ();
1546
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1547
    switch (u.format) {
1548 1549 1550 1551
    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 已提交
1552 1553 1554
    }
  }

1555
  protected:
1556 1557
  union {
  USHORT		format;	/* Format identifier */
B
Behdad Esfahbod 已提交
1558 1559 1560
  ChainContextFormat1	format1;
  ChainContextFormat2	format2;
  ChainContextFormat3	format3;
1561 1562 1563 1564
  } u;
};


1565 1566
struct ExtensionFormat1
{
1567
  friend struct Extension;
1568

B
Behdad Esfahbod 已提交
1569
  protected:
1570
  inline unsigned int get_type (void) const { return extensionLookupType; }
B
Behdad Esfahbod 已提交
1571
  inline unsigned int get_offset (void) const { return extensionOffset; }
1572

B
Behdad Esfahbod 已提交
1573
  inline bool sanitize (hb_sanitize_context_t *c) {
1574
    TRACE_SANITIZE ();
1575
    return TRACE_RETURN (c->check_struct (this));
B
Behdad Esfahbod 已提交
1576 1577
  }

1578
  protected:
1579 1580 1581 1582
  USHORT	format;			/* Format identifier. Set to 1. */
  USHORT	extensionLookupType;	/* Lookup type of subtable referenced
					 * by ExtensionOffset (i.e. the
					 * extension subtable). */
1583 1584
  ULONG		extensionOffset;	/* Offset to the extension subtable,
					 * of lookup type subtable. */
1585 1586
  public:
  DEFINE_SIZE_STATIC (8);
1587 1588 1589 1590 1591 1592 1593
};

struct Extension
{
  inline unsigned int get_type (void) const
  {
    switch (u.format) {
B
Behdad Esfahbod 已提交
1594
    case 1: return u.format1.get_type ();
1595 1596 1597
    default:return 0;
    }
  }
B
Behdad Esfahbod 已提交
1598
  inline unsigned int get_offset (void) const
1599 1600
  {
    switch (u.format) {
B
Behdad Esfahbod 已提交
1601
    case 1: return u.format1.get_offset ();
B
Behdad Esfahbod 已提交
1602
    default:return 0;
1603 1604 1605
    }
  }

B
Behdad Esfahbod 已提交
1606
  inline bool sanitize (hb_sanitize_context_t *c) {
1607
    TRACE_SANITIZE ();
1608
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1609
    switch (u.format) {
1610 1611
    case 1: return TRACE_RETURN (u.format1.sanitize (c));
    default:return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
1612 1613 1614
    }
  }

1615
  protected:
1616 1617
  union {
  USHORT		format;		/* Format identifier */
1618
  ExtensionFormat1	format1;
1619 1620 1621 1622
  } u;
};


B
Behdad Esfahbod 已提交
1623 1624 1625 1626
/*
 * GSUB/GPOS Common
 */

B
Behdad Esfahbod 已提交
1627 1628
struct GSUBGPOS
{
B
Behdad Esfahbod 已提交
1629 1630
  static const hb_tag_t GSUBTag	= HB_OT_TAG_GSUB;
  static const hb_tag_t GPOSTag	= HB_OT_TAG_GPOS;
B
Behdad Esfahbod 已提交
1631

1632 1633 1634 1635
  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 已提交
1636 1637 1638 1639
  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); }
1640 1641 1642 1643 1644 1645 1646 1647 1648
  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 已提交
1649 1650 1651 1652
  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); }
1653 1654 1655 1656 1657 1658 1659 1660 1661
  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 已提交
1662

B
Behdad Esfahbod 已提交
1663
  inline bool sanitize (hb_sanitize_context_t *c) {
1664
    TRACE_SANITIZE ();
1665 1666 1667 1668
    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 已提交
1669 1670
  }

1671
  protected:
B
Behdad Esfahbod 已提交
1672
  FixedVersion	version;	/* Version of the GSUB/GPOS table--initially set
B
Behdad Esfahbod 已提交
1673 1674 1675 1676 1677 1678 1679
				 * to 0x00010000 */
  OffsetTo<ScriptList>
		scriptList;  	/* ScriptList table */
  OffsetTo<FeatureList>
		featureList; 	/* FeatureList table */
  OffsetTo<LookupList>
		lookupList; 	/* LookupList table */
1680 1681
  public:
  DEFINE_SIZE_STATIC (10);
B
Behdad Esfahbod 已提交
1682
};
1683

1684

B
Behdad Esfahbod 已提交
1685

1686
#endif /* HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH */