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

29 30
#ifndef HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH
#define HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH
31

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

35

B
Behdad Esfahbod 已提交
36

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

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


45 46 47 48 49 50 51
/* 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 已提交
52

53 54 55 56

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


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



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

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 已提交
91
#ifndef HB_DEBUG_APPLY
92
#define HB_DEBUG_APPLY (HB_DEBUG+0)
B
Behdad Esfahbod 已提交
93 94
#endif

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

B
Behdad Esfahbod 已提交
98

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

113 114 115 116

  hb_apply_context_t (hb_font_t *font_,
		      hb_face_t *face_,
		      hb_buffer_t *buffer_,
B
Minor  
Behdad Esfahbod 已提交
117
		      hb_mask_t lookup_mask_) :
118 119 120
			font (font_), face (face_), buffer (buffer_),
			direction (buffer_->props.direction),
			lookup_mask (lookup_mask_),
B
Minor  
Behdad Esfahbod 已提交
121
			nesting_level_left (MAX_NESTING_LEVEL),
122
			lookup_props (0), property (0), debug_depth (0),
123 124 125 126
			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)),
			has_glyph_classes (gdef.has_glyph_classes ()) {}
127

B
Behdad Esfahbod 已提交
128
  void set_lookup (const Lookup &l) {
129 130 131
    lookup_props = l.get_props ();
  }

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

    unsigned int idx;
173
    protected:
B
Behdad Esfahbod 已提交
174 175
    hb_apply_context_t *c;
    unsigned int num_items;
176
    hb_mask_t mask;
177
    uint8_t syllable;
B
Behdad Esfahbod 已提交
178 179 180 181 182 183 184
    unsigned int end;
  };

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

    unsigned int idx;
222
    protected:
B
Behdad Esfahbod 已提交
223 224
    hb_apply_context_t *c;
    unsigned int num_items;
225
    hb_mask_t mask;
226
    uint8_t syllable;
B
Behdad Esfahbod 已提交
227 228
  };

229 230 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
  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
271
  {
B
Behdad Esfahbod 已提交
272
    unsigned int property;
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302

    property = info->props_cache();
    *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;

    property = info->props_cache();
    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);
303
  }
B
Behdad Esfahbod 已提交
304

305
  inline void set_class (hb_codepoint_t glyph_index, unsigned int class_guess) const
306
  {
307
    if (likely (has_glyph_classes))
308 309 310
      buffer->cur().props_cache() = gdef.get_glyph_props (glyph_index);
    else if (class_guess)
      buffer->cur().props_cache() = class_guess;
311
  }
B
Behdad Esfahbod 已提交
312

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

333

B
Behdad Esfahbod 已提交
334

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

340 341 342 343 344 345
struct ContextClosureFuncs
{
  intersects_func_t intersects;
  closure_lookup_func_t closure;
};
struct ContextApplyFuncs
B
Behdad Esfahbod 已提交
346
{
347 348
  match_func_t match;
  apply_lookup_func_t apply;
349 350
};

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

378

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

394

395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
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 已提交
410
static inline bool match_input (hb_apply_context_t *c,
B
Behdad Esfahbod 已提交
411 412 413
				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 已提交
414
				const void *match_data,
415
				unsigned int *end_offset = NULL)
B
Behdad Esfahbod 已提交
416
{
B
Behdad Esfahbod 已提交
417 418
  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 已提交
419
    return false;
B
Behdad Esfahbod 已提交
420

B
Minor  
Behdad Esfahbod 已提交
421
  for (unsigned int i = 1; i < count; i++)
B
Behdad Esfahbod 已提交
422
  {
B
Behdad Esfahbod 已提交
423 424
    if (!skippy_iter.next ())
      return false;
B
Behdad Esfahbod 已提交
425

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

430 431
  if (end_offset)
    *end_offset = skippy_iter.idx - c->buffer->idx + 1;
B
Behdad Esfahbod 已提交
432 433 434 435

  return true;
}

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

446
  for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
447
  {
B
Behdad Esfahbod 已提交
448 449
    if (!skippy_iter.prev ())
      return false;
450

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

  return true;
}

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

B
Minor  
Behdad Esfahbod 已提交
469
  for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
470
  {
B
Behdad Esfahbod 已提交
471 472
    if (!skippy_iter.next ())
      return false;
473

B
Behdad Esfahbod 已提交
474
    if (likely (!match_func (c->buffer->info[skippy_iter.idx].codepoint, lookahead[i], match_data)))
475 476 477
      return false;
  }

478 479 480
  return true;
}

B
Behdad Esfahbod 已提交
481

482

B
Behdad Esfahbod 已提交
483 484
struct LookupRecord
{
B
Behdad Esfahbod 已提交
485
  inline bool sanitize (hb_sanitize_context_t *c) {
486
    TRACE_SANITIZE ();
487
    return TRACE_RETURN (c->check_struct (this));
B
Behdad Esfahbod 已提交
488 489
  }

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

B
Behdad Esfahbod 已提交
498

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

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

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

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

B
Behdad Esfahbod 已提交
537
    if (lookupCount && i == lookupRecord->sequenceIndex)
538
    {
539
      unsigned int old_pos = c->buffer->idx;
540 541

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

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

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

  return true;
}
565

B
Behdad Esfahbod 已提交
566

567 568 569

/* Contextual lookups */

570 571 572 573 574 575 576
struct ContextClosureLookupContext
{
  ContextClosureFuncs funcs;
  const void *intersects_data;
};

struct ContextApplyLookupContext
B
Behdad Esfahbod 已提交
577
{
578
  ContextApplyFuncs funcs;
B
Behdad Esfahbod 已提交
579
  const void *match_data;
580 581
};

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


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

B
Behdad Esfahbod 已提交
625 626
struct Rule
{
627 628 629
  friend struct RuleSet;

  private:
630

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

641 642 643 644 645 646 647
  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));
  }

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

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

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

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

688 689 690 691 692 693 694 695 696 697 698 699
  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);
  }

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

B
Behdad Esfahbod 已提交
712
  inline bool sanitize (hb_sanitize_context_t *c) {
713
    TRACE_SANITIZE ();
714
    return TRACE_RETURN (rule.sanitize (c, this));
B
Behdad Esfahbod 已提交
715 716
  }

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


B
Behdad Esfahbod 已提交
726 727
struct ContextFormat1
{
728 729 730
  friend struct Context;

  private:
731

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

    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 已提交
747
	rule_set.closure (c, lookup_context);
748
      }
749 750
  }

751 752 753 754
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
    TRACE_WOULD_APPLY ();

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

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

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

B
Behdad Esfahbod 已提交
778
  inline bool sanitize (hb_sanitize_context_t *c) {
779
    TRACE_SANITIZE ();
780
    return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
781 782
  }

783
  protected:
784 785 786 787 788 789 790
  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 */
791
  public:
792
  DEFINE_SIZE_ARRAY (6, ruleSet);
793 794 795
};


B
Behdad Esfahbod 已提交
796 797
struct ContextFormat2
{
798 799 800
  friend struct Context;

  private:
801

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

    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 已提交
819
	rule_set.closure (c, lookup_context);
820
      }
821 822
  }

823 824 825 826 827
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
    TRACE_WOULD_APPLY ();

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

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

B
Behdad Esfahbod 已提交
853
  inline bool sanitize (hb_sanitize_context_t *c) {
854
    TRACE_SANITIZE ();
855
    return TRACE_RETURN (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
856 857
  }

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


B
Behdad Esfahbod 已提交
874 875
struct ContextFormat3
{
876 877 878
  friend struct Context;

  private:
879

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

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

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

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

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

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

B
Behdad Esfahbod 已提交
949 950
struct Context
{
951
  protected:
952

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

964 965 966 967 968 969 970 971 972 973
  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);
    }
  }

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

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

1006
  protected:
1007
  union {
B
Behdad Esfahbod 已提交
1008
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1009 1010 1011
  ContextFormat1	format1;
  ContextFormat2	format2;
  ContextFormat3	format3;
1012 1013 1014
  } u;
};

1015 1016 1017

/* Chaining Contextual lookups */

1018
struct ChainContextClosureLookupContext
B
Behdad Esfahbod 已提交
1019
{
1020 1021 1022 1023 1024 1025 1026
  ContextClosureFuncs funcs;
  const void *intersects_data[3];
};

struct ChainContextApplyLookupContext
{
  ContextApplyFuncs funcs;
B
Behdad Esfahbod 已提交
1027
  const void *match_data[3];
1028 1029
};

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

1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072
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]);
}

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

B
Behdad Esfahbod 已提交
1102 1103
struct ChainRule
{
1104 1105 1106
  friend struct ChainRuleSet;

  private:
1107

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

1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134
  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));
  }

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

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

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

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

1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198
  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);
  }

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

1207
    return TRACE_RETURN (false);
1208
  }
1209

B
Behdad Esfahbod 已提交
1210
  inline bool sanitize (hb_sanitize_context_t *c) {
1211
    TRACE_SANITIZE ();
1212
    return TRACE_RETURN (rule.sanitize (c, this));
B
Behdad Esfahbod 已提交
1213 1214
  }

1215
  protected:
1216 1217 1218
  OffsetArrayOf<ChainRule>
		rule;			/* Array of ChainRule tables
					 * ordered by preference */
1219
  public:
1220
  DEFINE_SIZE_ARRAY (2, rule);
1221 1222
};

B
Behdad Esfahbod 已提交
1223 1224
struct ChainContextFormat1
{
1225 1226 1227
  friend struct ChainContext;

  private:
1228

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

1247 1248 1249 1250
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
    TRACE_WOULD_APPLY ();

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

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

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

B
Behdad Esfahbod 已提交
1273
  inline bool sanitize (hb_sanitize_context_t *c) {
1274
    TRACE_SANITIZE ();
1275
    return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
1276 1277
  }

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

B
Behdad Esfahbod 已提交
1290 1291
struct ChainContextFormat2
{
1292 1293 1294
  friend struct ChainContext;

  private:
1295

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

    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 已提交
1317
	rule_set.closure (c, lookup_context);
1318
      }
1319 1320
  }

1321 1322 1323 1324 1325 1326
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
    TRACE_WOULD_APPLY ();

    const ClassDef &input_class_def = this+inputClassDef;

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

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

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

B
Behdad Esfahbod 已提交
1357
  inline bool sanitize (hb_sanitize_context_t *c) {
1358
    TRACE_SANITIZE ();
1359 1360 1361
    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 已提交
1362 1363
  }

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

B
Behdad Esfahbod 已提交
1388 1389
struct ChainContextFormat3
{
1390 1391 1392
  friend struct ChainContext;

  private:
1393

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

1416 1417 1418 1419 1420 1421
  inline const Coverage &get_coverage (void) const
  {
    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
    return this+input[0];
  }

1422 1423 1424 1425
  inline bool would_apply (hb_would_apply_context_t *c) const
  {
    TRACE_WOULD_APPLY ();

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

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

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

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

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

B
Behdad Esfahbod 已提交
1494 1495
struct ChainContext
{
1496
  protected:
1497

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

1509 1510 1511 1512 1513 1514 1515 1516 1517 1518
  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);
    }
  }

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

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

1551
  protected:
1552 1553
  union {
  USHORT		format;	/* Format identifier */
B
Behdad Esfahbod 已提交
1554 1555 1556
  ChainContextFormat1	format1;
  ChainContextFormat2	format2;
  ChainContextFormat3	format3;
1557 1558 1559 1560
  } u;
};


1561 1562
struct ExtensionFormat1
{
1563
  friend struct Extension;
1564

B
Behdad Esfahbod 已提交
1565
  protected:
1566
  inline unsigned int get_type (void) const { return extensionLookupType; }
B
Behdad Esfahbod 已提交
1567
  inline unsigned int get_offset (void) const { return extensionOffset; }
1568

B
Behdad Esfahbod 已提交
1569
  inline bool sanitize (hb_sanitize_context_t *c) {
1570
    TRACE_SANITIZE ();
1571
    return TRACE_RETURN (c->check_struct (this));
B
Behdad Esfahbod 已提交
1572 1573
  }

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

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

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

1611
  protected:
1612 1613
  union {
  USHORT		format;		/* Format identifier */
1614
  ExtensionFormat1	format1;
1615 1616 1617 1618
  } u;
};


B
Behdad Esfahbod 已提交
1619 1620 1621 1622
/*
 * GSUB/GPOS Common
 */

B
Behdad Esfahbod 已提交
1623 1624
struct GSUBGPOS
{
B
Behdad Esfahbod 已提交
1625 1626
  static const hb_tag_t GSUBTag	= HB_OT_TAG_GSUB;
  static const hb_tag_t GPOSTag	= HB_OT_TAG_GPOS;
B
Behdad Esfahbod 已提交
1627

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

B
Behdad Esfahbod 已提交
1659
  inline bool sanitize (hb_sanitize_context_t *c) {
1660
    TRACE_SANITIZE ();
1661 1662 1663 1664
    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 已提交
1665 1666
  }

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

1680

B
Behdad Esfahbod 已提交
1681

1682
#endif /* HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH */