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

29 30
#ifndef HB_OT_LAYOUT_GSUBGPOS_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

B
Behdad Esfahbod 已提交
37
/* buffer var allocations */
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
#define lig_props() var2.u8[3]

/* unique ligature id */
/* component number in the ligature (0 = base) */
static inline void
set_lig_props (hb_glyph_info_t &info, unsigned int lig_id, unsigned int lig_comp)
{
  info.lig_props() = (lig_id << 4) | (lig_comp & 0x0F);
}
static inline unsigned int
get_lig_id (hb_glyph_info_t &info)
{
  return info.lig_props() >> 4;
}
static inline unsigned int
get_lig_comp (hb_glyph_info_t &info)
{
  return info.lig_props() & 0x0F;
}
B
Behdad Esfahbod 已提交
57

58
static inline uint8_t allocate_lig_id (hb_buffer_t *buffer) {
59 60 61
  uint8_t lig_id = buffer->next_serial () & 0x0F;
  if (unlikely (!lig_id))
    lig_id = allocate_lig_id (buffer); /* in case of overflow */
B
Minor  
Behdad Esfahbod 已提交
62 63 64 65
  return lig_id;
}


B
Behdad Esfahbod 已提交
66

67 68 69 70 71
#ifndef HB_DEBUG_CLOSURE
#define HB_DEBUG_CLOSURE (HB_DEBUG+0)
#endif

#define TRACE_CLOSURE() \
72
	hb_auto_trace_t<HB_DEBUG_CLOSURE> trace (&c->debug_depth, "CLOSURE", this, HB_FUNC, "");
73 74 75 76 77 78



struct hb_closure_context_t
{
  hb_face_t *face;
79
  hb_set_t *glyphs;
80 81 82 83 84
  unsigned int nesting_level_left;
  unsigned int debug_depth;


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



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

B
Behdad Esfahbod 已提交
98
#define TRACE_APPLY() \
99
	hb_auto_trace_t<HB_DEBUG_APPLY> trace (&c->debug_depth, "APPLY", this, HB_FUNC, "");
100

B
Behdad Esfahbod 已提交
101

B
Behdad Esfahbod 已提交
102

103 104
struct hb_apply_context_t
{
105 106
  hb_font_t *font;
  hb_face_t *face;
B
Behdad Esfahbod 已提交
107
  hb_buffer_t *buffer;
108
  hb_direction_t direction;
B
Behdad Esfahbod 已提交
109
  hb_mask_t lookup_mask;
110
  unsigned int context_length;
111
  unsigned int nesting_level_left;
112
  unsigned int lookup_props;
113
  unsigned int property; /* propety of first glyph */
114
  unsigned int debug_depth;
115

116 117 118 119 120 121 122 123 124 125 126 127

  hb_apply_context_t (hb_font_t *font_,
		      hb_face_t *face_,
		      hb_buffer_t *buffer_,
		      hb_mask_t lookup_mask_,
		      unsigned int context_length_ = NO_CONTEXT,
		      unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) :
			font (font_), face (face_), buffer (buffer_),
			direction (buffer_->props.direction),
			lookup_mask (lookup_mask_),
			context_length (context_length_),
			nesting_level_left (nesting_level_left_),
B
Behdad Esfahbod 已提交
128
			lookup_props (0), property (0), debug_depth (0) {}
129

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

B
Behdad Esfahbod 已提交
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151
  struct mark_skipping_forward_iterator_t
  {
    inline mark_skipping_forward_iterator_t (hb_apply_context_t *c_,
					     unsigned int start_index_,
					     unsigned int num_items_)
    {
      c = c_;
      idx = start_index_;
      num_items = num_items_;
      end = MIN (c->buffer->len, c->buffer->idx + c->context_length);
    }
    inline bool has_no_chance (void) const
    {
      return unlikely (num_items && idx + num_items >= end);
    }
    inline bool next (unsigned int *property_out,
		      unsigned int lookup_props)
    {
152
      assert (num_items > 0);
B
Behdad Esfahbod 已提交
153 154 155 156
      do
      {
	if (has_no_chance ())
	  return false;
B
Behdad Esfahbod 已提交
157
	idx++;
B
Behdad Esfahbod 已提交
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
      } while (_hb_ot_layout_skip_mark (c->face, &c->buffer->info[idx], lookup_props, property_out));
      num_items--;
      return true;
    }
    inline bool next (unsigned int *property_out = NULL)
    {
      return next (property_out, c->lookup_props);
    }

    unsigned int idx;
    private:
    hb_apply_context_t *c;
    unsigned int num_items;
    unsigned int end;
  };

  struct mark_skipping_backward_iterator_t
  {
    inline mark_skipping_backward_iterator_t (hb_apply_context_t *c_,
					      unsigned int start_index_,
					      unsigned int num_items_)
    {
      c = c_;
      idx = start_index_;
      num_items = num_items_;
    }
    inline bool has_no_chance (void) const
    {
186
      return unlikely (idx < num_items);
B
Behdad Esfahbod 已提交
187 188 189 190
    }
    inline bool prev (unsigned int *property_out,
		      unsigned int lookup_props)
    {
191
      assert (num_items > 0);
B
Behdad Esfahbod 已提交
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
      do
      {
	if (has_no_chance ())
	  return false;
	idx--;
      } while (_hb_ot_layout_skip_mark (c->face, &c->buffer->out_info[idx], lookup_props, property_out));
      num_items--;
      return true;
    }
    inline bool prev (unsigned int *property_out = NULL)
    {
      return prev (property_out, c->lookup_props);
    }

    unsigned int idx;
    private:
    hb_apply_context_t *c;
    unsigned int num_items;
  };

212 213 214 215
  inline bool should_mark_skip_current_glyph (void) const
  {
    return _hb_ot_layout_skip_mark (face, &buffer->info[buffer->idx], lookup_props, NULL);
  }
B
Behdad Esfahbod 已提交
216 217 218



219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
  inline void replace_glyph (hb_codepoint_t glyph_index) const
  {
    clear_property ();
    buffer->replace_glyph (glyph_index);
  }
  inline void replace_glyphs_be16 (unsigned int num_in,
				   unsigned int num_out,
				   const uint16_t *glyph_data_be) const
  {
    clear_property ();
    buffer->replace_glyphs_be16 (num_in, num_out, glyph_data_be);
  }

  inline void guess_glyph_class (unsigned int klass)
  {
B
Behdad Esfahbod 已提交
234
    /* XXX if ! has gdef */
235
    buffer->info[buffer->idx].props_cache() = klass;
236 237 238 239 240
  }

  private:
  inline void clear_property (void) const
  {
B
Behdad Esfahbod 已提交
241
    /* XXX if has gdef */
242
    buffer->info[buffer->idx].props_cache() = 0;
243
  }
244 245
};

246

B
Behdad Esfahbod 已提交
247

248
typedef bool (*intersects_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data);
B
Behdad Esfahbod 已提交
249
typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data);
B
Behdad Esfahbod 已提交
250
typedef void (*closure_lookup_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
B
Behdad Esfahbod 已提交
251
typedef bool (*apply_lookup_func_t) (hb_apply_context_t *c, unsigned int lookup_index);
252

253 254 255 256 257 258
struct ContextClosureFuncs
{
  intersects_func_t intersects;
  closure_lookup_func_t closure;
};
struct ContextApplyFuncs
B
Behdad Esfahbod 已提交
259
{
260 261
  match_func_t match;
  apply_lookup_func_t apply;
262 263
};

264
static inline bool intersects_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED)
265 266 267
{
  return glyphs->has (value);
}
268
static inline bool intersects_class (hb_set_t *glyphs, const USHORT &value, const void *data)
269 270 271 272
{
  const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
  return class_def.intersects_class (glyphs, value);
}
273
static inline bool intersects_coverage (hb_set_t *glyphs, const USHORT &value, const void *data)
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290
{
  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;
}

291

B
Behdad Esfahbod 已提交
292
static inline bool match_glyph (hb_codepoint_t glyph_id, const USHORT &value, const void *data HB_UNUSED)
B
Behdad Esfahbod 已提交
293
{
294 295
  return glyph_id == value;
}
B
Behdad Esfahbod 已提交
296
static inline bool match_class (hb_codepoint_t glyph_id, const USHORT &value, const void *data)
B
Behdad Esfahbod 已提交
297
{
B
Behdad Esfahbod 已提交
298
  const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
299 300
  return class_def.get_class (glyph_id) == value;
}
B
Behdad Esfahbod 已提交
301
static inline bool match_coverage (hb_codepoint_t glyph_id, const USHORT &value, const void *data)
B
Behdad Esfahbod 已提交
302
{
303
  const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
304
  return (data+coverage).get_coverage (glyph_id) != NOT_COVERED;
305 306
}

307

B
Behdad Esfahbod 已提交
308
static inline bool match_input (hb_apply_context_t *c,
B
Behdad Esfahbod 已提交
309 310 311
				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 已提交
312
				const void *match_data,
B
Behdad Esfahbod 已提交
313 314
				unsigned int *context_length_out)
{
B
Behdad Esfahbod 已提交
315 316
  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 已提交
317
    return false;
B
Behdad Esfahbod 已提交
318

B
Minor  
Behdad Esfahbod 已提交
319
  for (unsigned int i = 1; i < count; i++)
B
Behdad Esfahbod 已提交
320
  {
B
Behdad Esfahbod 已提交
321 322
    if (!skippy_iter.next ())
      return false;
B
Behdad Esfahbod 已提交
323

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

B
Behdad Esfahbod 已提交
328
  *context_length_out = skippy_iter.idx - c->buffer->idx + 1;
B
Behdad Esfahbod 已提交
329 330 331 332

  return true;
}

B
Behdad Esfahbod 已提交
333
static inline bool match_backtrack (hb_apply_context_t *c,
334 335 336
				    unsigned int count,
				    const USHORT backtrack[],
				    match_func_t match_func,
B
Behdad Esfahbod 已提交
337
				    const void *match_data)
338
{
B
Behdad Esfahbod 已提交
339 340 341
  hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->backtrack_len (), count);
  if (skippy_iter.has_no_chance ())
    return false;
342

343
  for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
344
  {
B
Behdad Esfahbod 已提交
345 346
    if (!skippy_iter.prev ())
      return false;
347

B
Behdad Esfahbod 已提交
348
    if (likely (!match_func (c->buffer->out_info[skippy_iter.idx].codepoint, backtrack[i], match_data)))
349 350 351 352 353 354
      return false;
  }

  return true;
}

B
Behdad Esfahbod 已提交
355
static inline bool match_lookahead (hb_apply_context_t *c,
B
Behdad Esfahbod 已提交
356 357 358
				    unsigned int count,
				    const USHORT lookahead[],
				    match_func_t match_func,
B
Behdad Esfahbod 已提交
359
				    const void *match_data,
B
Behdad Esfahbod 已提交
360
				    unsigned int offset)
361
{
B
Behdad Esfahbod 已提交
362 363 364
  hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx + offset - 1, count);
  if (skippy_iter.has_no_chance ())
    return false;
365

B
Minor  
Behdad Esfahbod 已提交
366
  for (unsigned int i = 0; i < count; i++)
B
Behdad Esfahbod 已提交
367
  {
B
Behdad Esfahbod 已提交
368 369
    if (!skippy_iter.next ())
      return false;
370

B
Behdad Esfahbod 已提交
371
    if (likely (!match_func (c->buffer->info[skippy_iter.idx].codepoint, lookahead[i], match_data)))
372 373 374
      return false;
  }

375 376 377
  return true;
}

B
Behdad Esfahbod 已提交
378

379

B
Behdad Esfahbod 已提交
380 381
struct LookupRecord
{
B
Behdad Esfahbod 已提交
382
  inline bool sanitize (hb_sanitize_context_t *c) {
383
    TRACE_SANITIZE ();
384
    return TRACE_RETURN (c->check_struct (this));
B
Behdad Esfahbod 已提交
385 386
  }

387 388 389 390
  USHORT	sequenceIndex;		/* Index into current glyph
					 * sequence--first glyph = 0 */
  USHORT	lookupListIndex;	/* Lookup to apply to that
					 * position--zero--based */
B
Behdad Esfahbod 已提交
391 392
  public:
  DEFINE_SIZE_STATIC (4);
393 394
};

B
Behdad Esfahbod 已提交
395

B
Behdad Esfahbod 已提交
396
static inline void closure_lookup (hb_closure_context_t *c,
397 398 399 400 401
				   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 已提交
402
    closure_func (c, lookupRecord->lookupListIndex);
403
}
B
Behdad Esfahbod 已提交
404

B
Behdad Esfahbod 已提交
405
static inline bool apply_lookup (hb_apply_context_t *c,
406 407
				 unsigned int count, /* Including the first glyph */
				 unsigned int lookupCount,
408 409 410
				 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
				 apply_lookup_func_t apply_func)
{
411 412
  unsigned int end = MIN (c->buffer->len, c->buffer->idx + c->context_length);
  if (unlikely (count == 0 || c->buffer->idx + count > end))
413
    return false;
414

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

418
  /* Note: If sublookup is reverse, it will underflow after the first loop
B
Behdad Esfahbod 已提交
419 420 421
   * and we jump out of it.  Not entirely disastrous.  So we don't check
   * for reverse lookup here.
   */
B
Behdad Esfahbod 已提交
422
  for (unsigned int i = 0; i < count; /* NOP */)
B
Behdad Esfahbod 已提交
423
  {
424 425
    if (unlikely (c->buffer->idx == end))
      return true;
426
    while (c->should_mark_skip_current_glyph ())
B
Behdad Esfahbod 已提交
427
    {
428
      /* No lookup applied for this index */
B
Behdad Esfahbod 已提交
429
      c->buffer->next_glyph ();
430 431
      if (unlikely (c->buffer->idx == end))
	return true;
432 433
    }

B
Behdad Esfahbod 已提交
434
    if (lookupCount && i == lookupRecord->sequenceIndex)
435
    {
436
      unsigned int old_pos = c->buffer->idx;
437 438

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

B
Behdad Esfahbod 已提交
441 442
      lookupRecord++;
      lookupCount--;
B
Behdad Esfahbod 已提交
443
      /* Err, this is wrong if the lookup jumped over some glyphs */
444 445
      i += c->buffer->idx - old_pos;
      if (unlikely (c->buffer->idx == end))
446
	return true;
447 448 449 450 451 452 453 454

      if (!done)
	goto not_applied;
    }
    else
    {
    not_applied:
      /* No lookup applied for this index */
B
Behdad Esfahbod 已提交
455
      c->buffer->next_glyph ();
456 457 458 459 460 461
      i++;
    }
  }

  return true;
}
462

B
Behdad Esfahbod 已提交
463

464 465 466

/* Contextual lookups */

467 468 469 470 471 472 473
struct ContextClosureLookupContext
{
  ContextClosureFuncs funcs;
  const void *intersects_data;
};

struct ContextApplyLookupContext
B
Behdad Esfahbod 已提交
474
{
475
  ContextApplyFuncs funcs;
B
Behdad Esfahbod 已提交
476
  const void *match_data;
477 478
};

B
Behdad Esfahbod 已提交
479
static inline void context_closure_lookup (hb_closure_context_t *c,
480 481 482 483 484 485
					   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 已提交
486 487 488 489 490 491
  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);
492 493 494 495 496 497 498 499 500
}


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)
501
{
B
Behdad Esfahbod 已提交
502 503
  hb_apply_context_t new_context = *c;
  return match_input (c,
B
Behdad Esfahbod 已提交
504 505 506 507 508 509 510
		      inputCount, input,
		      lookup_context.funcs.match, lookup_context.match_data,
		      &new_context.context_length)
      && apply_lookup (&new_context,
		       inputCount,
		       lookupCount, lookupRecord,
		       lookup_context.funcs.apply);
511 512
}

B
Behdad Esfahbod 已提交
513 514
struct Rule
{
515 516 517
  friend struct RuleSet;

  private:
518

B
Behdad Esfahbod 已提交
519
  inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
520 521 522
  {
    TRACE_CLOSURE ();
    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
B
Behdad Esfahbod 已提交
523 524 525 526
    context_closure_lookup (c,
			    inputCount, input,
			    lookupCount, lookupRecord,
			    lookup_context);
527 528 529
  }

  inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
B
Behdad Esfahbod 已提交
530
  {
531
    TRACE_APPLY ();
B
Behdad Esfahbod 已提交
532
    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
533
    return TRACE_RETURN (context_apply_lookup (c, inputCount, input, lookupCount, lookupRecord, lookup_context));
534 535
  }

B
Behdad Esfahbod 已提交
536
  public:
B
Behdad Esfahbod 已提交
537
  inline bool sanitize (hb_sanitize_context_t *c) {
538
    TRACE_SANITIZE ();
B
Behdad Esfahbod 已提交
539 540 541
    return inputCount.sanitize (c)
	&& lookupCount.sanitize (c)
	&& c->check_range (input,
542 543
			   input[0].static_size * inputCount
			   + lookupRecordX[0].static_size * lookupCount);
B
Behdad Esfahbod 已提交
544 545
  }

546
  private:
547
  USHORT	inputCount;		/* Total number of glyphs in input
548
					 * glyph sequence--includes the first
549
					 * glyph */
550
  USHORT	lookupCount;		/* Number of LookupRecords */
B
Behdad Esfahbod 已提交
551
  USHORT	input[VAR];		/* Array of match inputs--start with
552
					 * second glyph */
B
Behdad Esfahbod 已提交
553
  LookupRecord	lookupRecordX[VAR];	/* Array of LookupRecords--in
554
					 * design order */
B
Behdad Esfahbod 已提交
555
  public:
556
  DEFINE_SIZE_ARRAY2 (4, input, lookupRecordX);
557 558
};

B
Behdad Esfahbod 已提交
559 560
struct RuleSet
{
B
Behdad Esfahbod 已提交
561
  inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
562 563 564 565
  {
    TRACE_CLOSURE ();
    unsigned int num_rules = rule.len;
    for (unsigned int i = 0; i < num_rules; i++)
B
Behdad Esfahbod 已提交
566
      (this+rule[i]).closure (c, lookup_context);
567 568 569
  }

  inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
B
Behdad Esfahbod 已提交
570
  {
571
    TRACE_APPLY ();
572
    unsigned int num_rules = rule.len;
B
Behdad Esfahbod 已提交
573 574
    for (unsigned int i = 0; i < num_rules; i++)
    {
B
Behdad Esfahbod 已提交
575
      if ((this+rule[i]).apply (c, lookup_context))
576
        return TRACE_RETURN (true);
577
    }
578
    return TRACE_RETURN (false);
579 580
  }

B
Behdad Esfahbod 已提交
581
  inline bool sanitize (hb_sanitize_context_t *c) {
582
    TRACE_SANITIZE ();
583
    return TRACE_RETURN (rule.sanitize (c, this));
B
Behdad Esfahbod 已提交
584 585
  }

586 587
  private:
  OffsetArrayOf<Rule>
588
		rule;			/* Array of Rule tables
589
					 * ordered by preference */
B
Behdad Esfahbod 已提交
590
  public:
591
  DEFINE_SIZE_ARRAY (2, rule);
592 593 594
};


B
Behdad Esfahbod 已提交
595 596
struct ContextFormat1
{
597 598 599
  friend struct Context;

  private:
600

B
Behdad Esfahbod 已提交
601
  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
602 603
  {
    TRACE_CLOSURE ();
604 605 606 607 608 609 610 611 612 613 614 615

    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 已提交
616
	rule_set.closure (c, lookup_context);
617
      }
618 619
  }

B
Behdad Esfahbod 已提交
620
  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
B
Behdad Esfahbod 已提交
621
  {
622
    TRACE_APPLY ();
623
    unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint);
624
    if (likely (index == NOT_COVERED))
625
      return TRACE_RETURN (false);
626

627
    const RuleSet &rule_set = this+ruleSet[index];
628
    struct ContextApplyLookupContext lookup_context = {
629 630
      {match_glyph, apply_func},
      NULL
631
    };
632
    return TRACE_RETURN (rule_set.apply (c, lookup_context));
633 634
  }

B
Behdad Esfahbod 已提交
635
  inline bool sanitize (hb_sanitize_context_t *c) {
636
    TRACE_SANITIZE ();
637
    return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
638 639
  }

640 641 642 643 644 645 646 647
  private:
  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 */
648
  public:
649
  DEFINE_SIZE_ARRAY (6, ruleSet);
650 651 652
};


B
Behdad Esfahbod 已提交
653 654
struct ContextFormat2
{
655 656 657
  friend struct Context;

  private:
658

B
Behdad Esfahbod 已提交
659
  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
660 661
  {
    TRACE_CLOSURE ();
662
    if (!(this+coverage).intersects (c->glyphs))
B
Behdad Esfahbod 已提交
663
      return;
664 665 666 667 668 669 670 671 672 673 674 675

    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 已提交
676
	rule_set.closure (c, lookup_context);
677
      }
678 679
  }

B
Behdad Esfahbod 已提交
680
  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
B
Behdad Esfahbod 已提交
681
  {
682
    TRACE_APPLY ();
683
    unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint);
684
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
685 686

    const ClassDef &class_def = this+classDef;
687
    index = class_def (c->buffer->info[c->buffer->idx].codepoint);
688
    const RuleSet &rule_set = this+ruleSet[index];
689
    struct ContextApplyLookupContext lookup_context = {
B
Behdad Esfahbod 已提交
690 691
      {match_class, apply_func},
      &class_def
692
    };
693
    return TRACE_RETURN (rule_set.apply (c, lookup_context));
694 695
  }

B
Behdad Esfahbod 已提交
696
  inline bool sanitize (hb_sanitize_context_t *c) {
697
    TRACE_SANITIZE ();
698
    return TRACE_RETURN (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
699 700
  }

701 702 703 704 705 706 707 708 709 710 711
  private:
  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 */
712
  public:
713
  DEFINE_SIZE_ARRAY (8, ruleSet);
714 715 716
};


B
Behdad Esfahbod 已提交
717 718
struct ContextFormat3
{
719 720 721
  friend struct Context;

  private:
722

B
Behdad Esfahbod 已提交
723
  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
724 725
  {
    TRACE_CLOSURE ();
726
    if (!(this+coverage[0]).intersects (c->glyphs))
B
Behdad Esfahbod 已提交
727
      return;
728 729 730 731 732 733

    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
    struct ContextClosureLookupContext lookup_context = {
      {intersects_coverage, closure_func},
      this
    };
B
Behdad Esfahbod 已提交
734 735 736 737
    context_closure_lookup (c,
			    glyphCount, (const USHORT *) (coverage + 1),
			    lookupCount, lookupRecord,
			    lookup_context);
738 739
  }

B
Behdad Esfahbod 已提交
740
  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
B
Behdad Esfahbod 已提交
741
  {
742
    TRACE_APPLY ();
743
    unsigned int index = (this+coverage[0]) (c->buffer->info[c->buffer->idx].codepoint);
744
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
745

B
Behdad Esfahbod 已提交
746
    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
747
    struct ContextApplyLookupContext lookup_context = {
748
      {match_coverage, apply_func},
B
Behdad Esfahbod 已提交
749
      this
750
    };
751
    return TRACE_RETURN (context_apply_lookup (c, glyphCount, (const USHORT *) (coverage + 1), lookupCount, lookupRecord, lookup_context));
752 753
  }

B
Behdad Esfahbod 已提交
754
  inline bool sanitize (hb_sanitize_context_t *c) {
755
    TRACE_SANITIZE ();
756
    if (!c->check_struct (this)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
757
    unsigned int count = glyphCount;
758
    if (!c->check_array (coverage, coverage[0].static_size, count)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
759
    for (unsigned int i = 0; i < count; i++)
760
      if (!coverage[i].sanitize (c, this)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
761
    LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * count);
762
    return TRACE_RETURN (c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount));
B
Behdad Esfahbod 已提交
763 764
  }

765 766 767 768
  private:
  USHORT	format;			/* Format identifier--format = 3 */
  USHORT	glyphCount;		/* Number of glyphs in the input glyph
					 * sequence */
769
  USHORT	lookupCount;		/* Number of LookupRecords */
770
  OffsetTo<Coverage>
B
Behdad Esfahbod 已提交
771
		coverage[VAR];		/* Array of offsets to Coverage
772
					 * table in glyph sequence order */
B
Behdad Esfahbod 已提交
773
  LookupRecord	lookupRecordX[VAR];	/* Array of LookupRecords--in
774
					 * design order */
B
Behdad Esfahbod 已提交
775
  public:
776
  DEFINE_SIZE_ARRAY2 (6, coverage, lookupRecordX);
777 778
};

B
Behdad Esfahbod 已提交
779 780
struct Context
{
781
  protected:
782

B
Behdad Esfahbod 已提交
783
  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
784 785 786
  {
    TRACE_CLOSURE ();
    switch (u.format) {
B
Behdad Esfahbod 已提交
787 788 789 790
    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;
791 792 793
    }
  }

B
Behdad Esfahbod 已提交
794
  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
B
Behdad Esfahbod 已提交
795
  {
796
    TRACE_APPLY ();
797
    switch (u.format) {
798 799 800 801
    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);
802 803 804
    }
  }

B
Behdad Esfahbod 已提交
805
  inline bool sanitize (hb_sanitize_context_t *c) {
806
    TRACE_SANITIZE ();
807
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
808
    switch (u.format) {
809 810 811 812
    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 已提交
813 814 815
    }
  }

816 817
  private:
  union {
B
Behdad Esfahbod 已提交
818
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
819 820 821
  ContextFormat1	format1;
  ContextFormat2	format2;
  ContextFormat3	format3;
822 823 824
  } u;
};

825 826 827

/* Chaining Contextual lookups */

828
struct ChainContextClosureLookupContext
B
Behdad Esfahbod 已提交
829
{
830 831 832 833 834 835 836
  ContextClosureFuncs funcs;
  const void *intersects_data[3];
};

struct ChainContextApplyLookupContext
{
  ContextApplyFuncs funcs;
B
Behdad Esfahbod 已提交
837
  const void *match_data[3];
838 839
};

B
Behdad Esfahbod 已提交
840
static inline void chain_context_closure_lookup (hb_closure_context_t *c,
841 842 843 844 845 846 847 848 849 850
						 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 已提交
851 852 853 854 855 856 857 858 859 860 861 862
  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);
863 864 865 866 867 868 869 870 871 872 873 874
}

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)
875
{
876
  /* First guess */
877
  if (unlikely (c->buffer->backtrack_len () < backtrackCount ||
878
		c->buffer->idx + inputCount + lookaheadCount > c->buffer->len ||
B
Behdad Esfahbod 已提交
879
		inputCount + lookaheadCount > c->context_length))
880 881
    return false;

B
Behdad Esfahbod 已提交
882 883
  hb_apply_context_t new_context = *c;
  return match_backtrack (c,
B
Behdad Esfahbod 已提交
884 885
			  backtrackCount, backtrack,
			  lookup_context.funcs.match, lookup_context.match_data[0])
B
Behdad Esfahbod 已提交
886
      && match_input (c,
B
Behdad Esfahbod 已提交
887 888 889
		      inputCount, input,
		      lookup_context.funcs.match, lookup_context.match_data[1],
		      &new_context.context_length)
B
Behdad Esfahbod 已提交
890
      && match_lookahead (c,
B
Behdad Esfahbod 已提交
891 892 893 894 895 896 897
			  lookaheadCount, lookahead,
			  lookup_context.funcs.match, lookup_context.match_data[2],
			  new_context.context_length)
      && apply_lookup (&new_context,
		       inputCount,
		       lookupCount, lookupRecord,
		       lookup_context.funcs.apply);
898
}
899

B
Behdad Esfahbod 已提交
900 901
struct ChainRule
{
902 903 904
  friend struct ChainRuleSet;

  private:
905

B
Behdad Esfahbod 已提交
906
  inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
907 908 909 910 911
  {
    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 已提交
912 913 914 915 916 917
    chain_context_closure_lookup (c,
				  backtrack.len, backtrack.array,
				  input.len, input.array,
				  lookahead.len, lookahead.array,
				  lookup.len, lookup.array,
				  lookup_context);
918 919 920
  }

  inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
B
Behdad Esfahbod 已提交
921
  {
922
    TRACE_APPLY ();
923 924 925
    const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
    const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
926 927 928 929 930
    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));
931 932
  }

B
Behdad Esfahbod 已提交
933
  public:
B
Behdad Esfahbod 已提交
934
  inline bool sanitize (hb_sanitize_context_t *c) {
935
    TRACE_SANITIZE ();
936
    if (!backtrack.sanitize (c)) return TRACE_RETURN (false);
937
    HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
938
    if (!input.sanitize (c)) return TRACE_RETURN (false);
939
    ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
940
    if (!lookahead.sanitize (c)) return TRACE_RETURN (false);
941
    ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
942
    return TRACE_RETURN (lookup.sanitize (c));
B
Behdad Esfahbod 已提交
943
  }
944 945

  private:
B
Behdad Esfahbod 已提交
946 947
  ArrayOf<USHORT>
		backtrack;		/* Array of backtracking values
948 949
					 * (to be matched before the input
					 * sequence) */
B
Behdad Esfahbod 已提交
950 951
  HeadlessArrayOf<USHORT>
		inputX;			/* Array of input values (start with
952
					 * second glyph) */
B
Behdad Esfahbod 已提交
953 954
  ArrayOf<USHORT>
		lookaheadX;		/* Array of lookahead values's (to be
955
					 * matched after the input sequence) */
B
Behdad Esfahbod 已提交
956
  ArrayOf<LookupRecord>
957
		lookupX;		/* Array of LookupRecords--in
958
					 * design order) */
959
  public:
B
Behdad Esfahbod 已提交
960
  DEFINE_SIZE_MIN (8);
961 962
};

B
Behdad Esfahbod 已提交
963 964
struct ChainRuleSet
{
B
Behdad Esfahbod 已提交
965
  inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
966 967 968 969
  {
    TRACE_CLOSURE ();
    unsigned int num_rules = rule.len;
    for (unsigned int i = 0; i < num_rules; i++)
B
Behdad Esfahbod 已提交
970
      (this+rule[i]).closure (c, lookup_context);
971 972 973
  }

  inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
B
Behdad Esfahbod 已提交
974
  {
975
    TRACE_APPLY ();
976
    unsigned int num_rules = rule.len;
B
Behdad Esfahbod 已提交
977
    for (unsigned int i = 0; i < num_rules; i++)
B
Behdad Esfahbod 已提交
978
      if ((this+rule[i]).apply (c, lookup_context))
979
        return TRACE_RETURN (true);
980

981
    return TRACE_RETURN (false);
982
  }
983

B
Behdad Esfahbod 已提交
984
  inline bool sanitize (hb_sanitize_context_t *c) {
985
    TRACE_SANITIZE ();
986
    return TRACE_RETURN (rule.sanitize (c, this));
B
Behdad Esfahbod 已提交
987 988
  }

989
  private:
990 991 992
  OffsetArrayOf<ChainRule>
		rule;			/* Array of ChainRule tables
					 * ordered by preference */
993
  public:
994
  DEFINE_SIZE_ARRAY (2, rule);
995 996
};

B
Behdad Esfahbod 已提交
997 998
struct ChainContextFormat1
{
999 1000 1001
  friend struct ChainContext;

  private:
1002

B
Behdad Esfahbod 已提交
1003
  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
1004 1005
  {
    TRACE_CLOSURE ();
1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016
    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 已提交
1017
	rule_set.closure (c, lookup_context);
1018
      }
1019 1020
  }

B
Behdad Esfahbod 已提交
1021
  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
B
Behdad Esfahbod 已提交
1022
  {
1023
    TRACE_APPLY ();
1024
    unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint);
1025
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
1026

1027
    const ChainRuleSet &rule_set = this+ruleSet[index];
1028
    struct ChainContextApplyLookupContext lookup_context = {
1029 1030 1031
      {match_glyph, apply_func},
      {NULL, NULL, NULL}
    };
1032
    return TRACE_RETURN (rule_set.apply (c, lookup_context));
1033
  }
B
Behdad Esfahbod 已提交
1034

B
Behdad Esfahbod 已提交
1035
  inline bool sanitize (hb_sanitize_context_t *c) {
1036
    TRACE_SANITIZE ();
1037
    return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
B
Behdad Esfahbod 已提交
1038 1039
  }

1040 1041
  private:
  USHORT	format;			/* Format identifier--format = 1 */
1042 1043
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
1044
					 * beginning of table */
1045 1046 1047
  OffsetArrayOf<ChainRuleSet>
		ruleSet;		/* Array of ChainRuleSet tables
					 * ordered by Coverage Index */
1048
  public:
1049
  DEFINE_SIZE_ARRAY (6, ruleSet);
1050 1051
};

B
Behdad Esfahbod 已提交
1052 1053
struct ChainContextFormat2
{
1054 1055 1056
  friend struct ChainContext;

  private:
1057

B
Behdad Esfahbod 已提交
1058
  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
1059 1060
  {
    TRACE_CLOSURE ();
1061
    if (!(this+coverage).intersects (c->glyphs))
B
Behdad Esfahbod 已提交
1062
      return;
1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078

    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 已提交
1079
	rule_set.closure (c, lookup_context);
1080
      }
1081 1082
  }

B
Behdad Esfahbod 已提交
1083
  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
B
Behdad Esfahbod 已提交
1084
  {
1085
    TRACE_APPLY ();
1086
    unsigned int index = (this+coverage) (c->buffer->info[c->buffer->idx].codepoint);
1087
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
1088 1089 1090 1091 1092

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

1093
    index = input_class_def (c->buffer->info[c->buffer->idx].codepoint);
1094
    const ChainRuleSet &rule_set = this+ruleSet[index];
1095
    struct ChainContextApplyLookupContext lookup_context = {
B
Behdad Esfahbod 已提交
1096 1097 1098 1099
      {match_class, apply_func},
      {&backtrack_class_def,
       &input_class_def,
       &lookahead_class_def}
1100
    };
1101
    return TRACE_RETURN (rule_set.apply (c, lookup_context));
1102 1103
  }

B
Behdad Esfahbod 已提交
1104
  inline bool sanitize (hb_sanitize_context_t *c) {
1105
    TRACE_SANITIZE ();
1106 1107 1108
    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 已提交
1109 1110
  }

1111 1112
  private:
  USHORT	format;			/* Format identifier--format = 2 */
1113 1114
  OffsetTo<Coverage>
		coverage;		/* Offset to Coverage table--from
1115
					 * beginning of table */
1116 1117
  OffsetTo<ClassDef>
		backtrackClassDef;	/* Offset to glyph ClassDef table
1118 1119
					 * containing backtrack sequence
					 * data--from beginning of table */
1120 1121
  OffsetTo<ClassDef>
		inputClassDef;		/* Offset to glyph ClassDef
1122 1123
					 * table containing input sequence
					 * data--from beginning of table */
1124 1125
  OffsetTo<ClassDef>
		lookaheadClassDef;	/* Offset to glyph ClassDef table
1126 1127
					 * containing lookahead sequence
					 * data--from beginning of table */
1128 1129 1130
  OffsetArrayOf<ChainRuleSet>
		ruleSet;		/* Array of ChainRuleSet tables
					 * ordered by class */
1131
  public:
1132
  DEFINE_SIZE_ARRAY (12, ruleSet);
1133 1134
};

B
Behdad Esfahbod 已提交
1135 1136
struct ChainContextFormat3
{
1137 1138 1139
  friend struct ChainContext;

  private:
1140

B
Behdad Esfahbod 已提交
1141
  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
1142 1143
  {
    TRACE_CLOSURE ();
B
Behdad Esfahbod 已提交
1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160
    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);
1161 1162
  }

B
Behdad Esfahbod 已提交
1163
  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
B
Behdad Esfahbod 已提交
1164
  {
1165
    TRACE_APPLY ();
1166
    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1167

1168
    unsigned int index = (this+input[0]) (c->buffer->info[c->buffer->idx].codepoint);
1169
    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
1170

1171 1172
    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1173
    struct ChainContextApplyLookupContext lookup_context = {
1174
      {match_coverage, apply_func},
B
Behdad Esfahbod 已提交
1175
      {this, this, this}
1176
    };
1177 1178 1179 1180 1181
    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));
1182 1183
  }

B
Behdad Esfahbod 已提交
1184
  inline bool sanitize (hb_sanitize_context_t *c) {
1185
    TRACE_SANITIZE ();
1186
    if (!backtrack.sanitize (c, this)) return TRACE_RETURN (false);
1187
    OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1188
    if (!input.sanitize (c, this)) return TRACE_RETURN (false);
1189
    OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
1190
    if (!lookahead.sanitize (c, this)) return TRACE_RETURN (false);
1191
    ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1192
    return TRACE_RETURN (lookup.sanitize (c));
B
Behdad Esfahbod 已提交
1193 1194
  }

1195 1196
  private:
  USHORT	format;			/* Format identifier--format = 3 */
B
Behdad Esfahbod 已提交
1197
  OffsetArrayOf<Coverage>
1198
		backtrack;		/* Array of coverage tables
1199 1200
					 * in backtracking sequence, in  glyph
					 * sequence order */
B
Behdad Esfahbod 已提交
1201
  OffsetArrayOf<Coverage>
1202
		inputX		;	/* Array of coverage
1203 1204
					 * tables in input sequence, in glyph
					 * sequence order */
B
Behdad Esfahbod 已提交
1205
  OffsetArrayOf<Coverage>
1206
		lookaheadX;		/* Array of coverage tables
1207 1208
					 * in lookahead sequence, in glyph
					 * sequence order */
B
Behdad Esfahbod 已提交
1209
  ArrayOf<LookupRecord>
1210
		lookupX;		/* Array of LookupRecords--in
B
Behdad Esfahbod 已提交
1211
					 * design order) */
1212
  public:
B
Behdad Esfahbod 已提交
1213
  DEFINE_SIZE_MIN (10);
1214 1215
};

B
Behdad Esfahbod 已提交
1216 1217
struct ChainContext
{
1218
  protected:
1219

B
Behdad Esfahbod 已提交
1220
  inline void closure (hb_closure_context_t *c, closure_lookup_func_t closure_func) const
1221 1222 1223
  {
    TRACE_CLOSURE ();
    switch (u.format) {
B
Behdad Esfahbod 已提交
1224 1225 1226 1227
    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;
1228 1229 1230
    }
  }

B
Behdad Esfahbod 已提交
1231
  inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) const
B
Behdad Esfahbod 已提交
1232
  {
1233
    TRACE_APPLY ();
1234
    switch (u.format) {
1235 1236 1237 1238
    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);
1239 1240 1241
    }
  }

B
Behdad Esfahbod 已提交
1242
  inline bool sanitize (hb_sanitize_context_t *c) {
1243
    TRACE_SANITIZE ();
1244
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1245
    switch (u.format) {
1246 1247 1248 1249
    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 已提交
1250 1251 1252
    }
  }

1253 1254 1255
  private:
  union {
  USHORT		format;	/* Format identifier */
B
Behdad Esfahbod 已提交
1256 1257 1258
  ChainContextFormat1	format1;
  ChainContextFormat2	format2;
  ChainContextFormat3	format3;
1259 1260 1261 1262
  } u;
};


1263 1264 1265 1266
struct ExtensionFormat1
{
  friend struct Extension;

B
Behdad Esfahbod 已提交
1267
  protected:
1268
  inline unsigned int get_type (void) const { return extensionLookupType; }
B
Behdad Esfahbod 已提交
1269
  inline unsigned int get_offset (void) const { return extensionOffset; }
1270

B
Behdad Esfahbod 已提交
1271
  inline bool sanitize (hb_sanitize_context_t *c) {
1272
    TRACE_SANITIZE ();
1273
    return TRACE_RETURN (c->check_struct (this));
B
Behdad Esfahbod 已提交
1274 1275
  }

1276 1277 1278 1279 1280
  private:
  USHORT	format;			/* Format identifier. Set to 1. */
  USHORT	extensionLookupType;	/* Lookup type of subtable referenced
					 * by ExtensionOffset (i.e. the
					 * extension subtable). */
1281 1282
  ULONG		extensionOffset;	/* Offset to the extension subtable,
					 * of lookup type subtable. */
1283 1284
  public:
  DEFINE_SIZE_STATIC (8);
1285 1286 1287 1288 1289 1290 1291
};

struct Extension
{
  inline unsigned int get_type (void) const
  {
    switch (u.format) {
B
Behdad Esfahbod 已提交
1292
    case 1: return u.format1.get_type ();
1293 1294 1295
    default:return 0;
    }
  }
B
Behdad Esfahbod 已提交
1296
  inline unsigned int get_offset (void) const
1297 1298
  {
    switch (u.format) {
B
Behdad Esfahbod 已提交
1299
    case 1: return u.format1.get_offset ();
B
Behdad Esfahbod 已提交
1300
    default:return 0;
1301 1302 1303
    }
  }

B
Behdad Esfahbod 已提交
1304
  inline bool sanitize (hb_sanitize_context_t *c) {
1305
    TRACE_SANITIZE ();
1306
    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
B
Behdad Esfahbod 已提交
1307
    switch (u.format) {
1308 1309
    case 1: return TRACE_RETURN (u.format1.sanitize (c));
    default:return TRACE_RETURN (true);
B
Behdad Esfahbod 已提交
1310 1311 1312
    }
  }

1313 1314 1315
  private:
  union {
  USHORT		format;		/* Format identifier */
B
Behdad Esfahbod 已提交
1316
  ExtensionFormat1	format1;
1317 1318 1319 1320
  } u;
};


B
Behdad Esfahbod 已提交
1321 1322 1323 1324
/*
 * GSUB/GPOS Common
 */

B
Behdad Esfahbod 已提交
1325 1326
struct GSUBGPOS
{
B
Behdad Esfahbod 已提交
1327 1328
  static const hb_tag_t GSUBTag	= HB_OT_TAG_GSUB;
  static const hb_tag_t GPOSTag	= HB_OT_TAG_GPOS;
B
Behdad Esfahbod 已提交
1329

1330 1331 1332 1333
  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 已提交
1334 1335 1336 1337
  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); }
1338 1339 1340 1341 1342 1343 1344 1345 1346
  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 已提交
1347 1348 1349 1350
  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); }
1351 1352 1353 1354 1355 1356 1357 1358 1359
  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 已提交
1360

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

1369
  protected:
B
Behdad Esfahbod 已提交
1370
  FixedVersion	version;	/* Version of the GSUB/GPOS table--initially set
B
Behdad Esfahbod 已提交
1371 1372 1373 1374 1375 1376 1377
				 * to 0x00010000 */
  OffsetTo<ScriptList>
		scriptList;  	/* ScriptList table */
  OffsetTo<FeatureList>
		featureList; 	/* FeatureList table */
  OffsetTo<LookupList>
		lookupList; 	/* LookupList table */
1378 1379
  public:
  DEFINE_SIZE_STATIC (10);
B
Behdad Esfahbod 已提交
1380
};
1381

1382

B
Behdad Esfahbod 已提交
1383

1384
#endif /* HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH */