hb-ot-layout-gsubgpos-private.hh 41.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 42 43 44 45 46 47 48 49 50 51 52 53
/* 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 已提交
54

55
static inline uint8_t allocate_lig_id (hb_buffer_t *buffer) {
56 57 58
  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 已提交
59 60 61 62
  return lig_id;
}


B
Behdad Esfahbod 已提交
63

64 65 66 67 68
#ifndef HB_DEBUG_CLOSURE
#define HB_DEBUG_CLOSURE (HB_DEBUG+0)
#endif

#define TRACE_CLOSURE() \
69
	hb_auto_trace_t<HB_DEBUG_CLOSURE> trace (&c->debug_depth, "CLOSURE", this, HB_FUNC, "");
70 71


B
Minor  
Behdad Esfahbod 已提交
72 73
/* TODO Add TRACE_RETURN annotation for would_apply */

74 75 76 77

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


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



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

B
Behdad Esfahbod 已提交
97
#define TRACE_APPLY() \
98
	hb_auto_trace_t<HB_DEBUG_APPLY> trace (&c->debug_depth, "APPLY", this, HB_FUNC, "idx %d codepoint %u", c->buffer->idx, c->buffer->info[c->buffer->idx].codepoint);
99

B
Behdad Esfahbod 已提交
100

B
Behdad Esfahbod 已提交
101

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

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

  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 已提交
127
			lookup_props (0), property (0), debug_depth (0) {}
128

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

B
Behdad Esfahbod 已提交
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
  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)
    {
151
      assert (num_items > 0);
B
Behdad Esfahbod 已提交
152 153 154 155
      do
      {
	if (has_no_chance ())
	  return false;
B
Behdad Esfahbod 已提交
156
	idx++;
B
Behdad Esfahbod 已提交
157 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
      } 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
    {
185
      return unlikely (idx < num_items);
B
Behdad Esfahbod 已提交
186 187 188 189
    }
    inline bool prev (unsigned int *property_out,
		      unsigned int lookup_props)
    {
190
      assert (num_items > 0);
B
Behdad Esfahbod 已提交
191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210
      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;
  };

211 212 213 214
  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 已提交
215 216 217



218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
  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 已提交
233
    /* XXX if ! has gdef */
234
    buffer->info[buffer->idx].props_cache() = klass;
235 236 237 238 239
  }

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

245

B
Behdad Esfahbod 已提交
246

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

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

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

290

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

306

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

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

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

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

  return true;
}

B
Behdad Esfahbod 已提交
332
static inline bool match_backtrack (hb_apply_context_t *c,
333 334 335
				    unsigned int count,
				    const USHORT backtrack[],
				    match_func_t match_func,
B
Behdad Esfahbod 已提交
336
				    const void *match_data)
337
{
B
Behdad Esfahbod 已提交
338 339 340
  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;
341

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

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

  return true;
}

B
Behdad Esfahbod 已提交
354
static inline bool match_lookahead (hb_apply_context_t *c,
B
Behdad Esfahbod 已提交
355 356 357
				    unsigned int count,
				    const USHORT lookahead[],
				    match_func_t match_func,
B
Behdad Esfahbod 已提交
358
				    const void *match_data,
B
Behdad Esfahbod 已提交
359
				    unsigned int offset)
360
{
B
Behdad Esfahbod 已提交
361 362 363
  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;
364

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

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

374 375 376
  return true;
}

B
Behdad Esfahbod 已提交
377

378

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

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

B
Behdad Esfahbod 已提交
394

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

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

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

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

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

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

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

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

  return true;
}
461

B
Behdad Esfahbod 已提交
462

463 464 465

/* Contextual lookups */

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

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

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


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)
500
{
B
Behdad Esfahbod 已提交
501 502
  hb_apply_context_t new_context = *c;
  return match_input (c,
B
Behdad Esfahbod 已提交
503 504 505 506 507 508 509
		      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);
510 511
}

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

  private:
517

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

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

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

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

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

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

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

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


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

  private:
599

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

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

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

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

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

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


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

  private:
657

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

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

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

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

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

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


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

  private:
721

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

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

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

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

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

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

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

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

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

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

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

824 825 826

/* Chaining Contextual lookups */

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

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

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

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

B
Behdad Esfahbod 已提交
881 882
  hb_apply_context_t new_context = *c;
  return match_backtrack (c,
B
Behdad Esfahbod 已提交
883 884
			  backtrackCount, backtrack,
			  lookup_context.funcs.match, lookup_context.match_data[0])
B
Behdad Esfahbod 已提交
885
      && match_input (c,
B
Behdad Esfahbod 已提交
886 887 888
		      inputCount, input,
		      lookup_context.funcs.match, lookup_context.match_data[1],
		      &new_context.context_length)
B
Behdad Esfahbod 已提交
889
      && match_lookahead (c,
B
Behdad Esfahbod 已提交
890 891 892 893 894 895 896
			  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);
897
}
898

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

  private:
904

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

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

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

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

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

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

980
    return TRACE_RETURN (false);
981
  }
982

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

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

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

  private:
1001

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

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

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

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

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

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

  private:
1056

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

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

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

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

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

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

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

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

  private:
1139

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

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

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

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

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

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

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

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

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

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

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


1262 1263 1264 1265
struct ExtensionFormat1
{
  friend struct Extension;

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

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

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

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

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

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


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

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

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

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

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

1381

B
Behdad Esfahbod 已提交
1382

1383
#endif /* HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH */