hb-ot-layout-gsubgpos-private.hh revision 902cc8aca0b3ff25eeee50b3a84d729e31731ef3
1/*
2 * Copyright © 2007,2008,2009,2010  Red Hat, Inc.
3 * Copyright © 2010,2012  Google, Inc.
4 *
5 *  This is part of HarfBuzz, a text shaping library.
6 *
7 * Permission is hereby granted, without written agreement and without
8 * license or royalty fees, to use, copy, modify, and distribute this
9 * software and its documentation for any purpose, provided that the
10 * above copyright notice and the following two paragraphs appear in
11 * all copies of this software.
12 *
13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
17 * DAMAGE.
18 *
19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21 * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24 *
25 * Red Hat Author(s): Behdad Esfahbod
26 * Google Author(s): Behdad Esfahbod
27 */
28
29#ifndef HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH
30#define HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH
31
32#include "hb-buffer-private.hh"
33#include "hb-ot-layout-gdef-table.hh"
34#include "hb-set-private.hh"
35
36
37namespace OT {
38
39
40
41#ifndef HB_DEBUG_CLOSURE
42#define HB_DEBUG_CLOSURE (HB_DEBUG+0)
43#endif
44
45#define TRACE_CLOSURE() \
46	hb_auto_trace_t<HB_DEBUG_CLOSURE, void_t> trace \
47	(&c->debug_depth, "CLOSURE", this, HB_FUNC, \
48	 "");
49
50struct hb_closure_context_t
51{
52  typedef void_t return_t;
53  typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
54  template <typename T>
55  inline return_t process (const T &obj) { obj.closure (this); return void_t (); }
56  static return_t default_return_value (void) { return return_t (); }
57  bool stop_sublookup_iteration (const return_t r) const { return false; }
58  return_t recurse (unsigned int lookup_index)
59  {
60    if (unlikely (nesting_level_left == 0))
61      return default_return_value ();
62
63    nesting_level_left--;
64    recurse_func (this, lookup_index);
65    nesting_level_left++;
66    return default_return_value ();
67  }
68
69  hb_face_t *face;
70  hb_set_t *glyphs;
71  recurse_func_t recurse_func;
72  unsigned int nesting_level_left;
73  unsigned int debug_depth;
74
75  hb_closure_context_t (hb_face_t *face_,
76			hb_set_t *glyphs_,
77			recurse_func_t recurse_func_,
78		        unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) :
79			  face (face_),
80			  glyphs (glyphs_),
81			  recurse_func (recurse_func_),
82			  nesting_level_left (nesting_level_left_),
83			  debug_depth (0) {}
84};
85
86
87
88#ifndef HB_DEBUG_WOULD_APPLY
89#define HB_DEBUG_WOULD_APPLY (HB_DEBUG+0)
90#endif
91
92#define TRACE_WOULD_APPLY() \
93	hb_auto_trace_t<HB_DEBUG_WOULD_APPLY, bool> trace \
94	(&c->debug_depth, "WOULD_APPLY", this, HB_FUNC, \
95	 "%d glyphs", c->len);
96
97struct hb_would_apply_context_t
98{
99  typedef bool return_t;
100  template <typename T>
101  inline return_t process (const T &obj) { return obj.would_apply (this); }
102  static return_t default_return_value (void) { return false; }
103  bool stop_sublookup_iteration (const return_t r) const { return r; }
104  return_t recurse (unsigned int lookup_index) { return true; }
105
106  hb_face_t *face;
107  const hb_codepoint_t *glyphs;
108  unsigned int len;
109  bool zero_context;
110  unsigned int debug_depth;
111
112  hb_would_apply_context_t (hb_face_t *face_,
113			    const hb_codepoint_t *glyphs_,
114			    unsigned int len_,
115			    bool zero_context_) :
116			      face (face_),
117			      glyphs (glyphs_),
118			      len (len_),
119			      zero_context (zero_context_),
120			      debug_depth (0) {};
121};
122
123
124
125#ifndef HB_DEBUG_COLLECT_GLYPHS
126#define HB_DEBUG_COLLECT_GLYPHS (HB_DEBUG+0)
127#endif
128
129#define TRACE_COLLECT_GLYPHS() \
130	hb_auto_trace_t<HB_DEBUG_COLLECT_GLYPHS, void_t> trace \
131	(&c->debug_depth, "COLLECT_GLYPHS", this, HB_FUNC, \
132	 "");
133
134struct hb_collect_glyphs_context_t
135{
136  typedef void_t return_t;
137  template <typename T>
138  inline return_t process (const T &obj) { obj.collect_glyphs (this); return void_t (); }
139  static return_t default_return_value (void) { return return_t (); }
140  bool stop_iteration (const return_t r) const { return false; }
141  return_t recurse (unsigned int lookup_index)
142  {
143#if 0
144    /* XXX */
145#endif
146    return default_return_value ();
147  }
148
149  hb_face_t *face;
150  hb_set_t &before;
151  hb_set_t &input;
152  hb_set_t &after;
153  hb_set_t &output;
154  unsigned int debug_depth;
155
156  hb_collect_glyphs_context_t (hb_face_t *face_,
157			       hb_set_t  *glyphs_before, /* OUT. May be NULL */
158			       hb_set_t  *glyphs_input,  /* OUT. May be NULL */
159			       hb_set_t  *glyphs_after,  /* OUT. May be NULL */
160			       hb_set_t  *glyphs_output  /* OUT. May be NULL */) :
161			      face (face_),
162			      before (glyphs_before ? *glyphs_before : *hb_set_get_empty ()),
163			      input  (glyphs_input  ? *glyphs_input  : *hb_set_get_empty ()),
164			      after  (glyphs_after  ? *glyphs_after  : *hb_set_get_empty ()),
165			      output (glyphs_output ? *glyphs_output : *hb_set_get_empty ()),
166			      debug_depth (0) {};
167};
168
169
170
171struct hb_get_coverage_context_t
172{
173  typedef const Coverage &return_t;
174  template <typename T>
175  inline return_t process (const T &obj) { return obj.get_coverage (); }
176  static const return_t default_return_value (void) { return Null(Coverage); }
177  bool stop_sublookup_iteration (const return_t r) const { return true; /* Unused */ }
178  return_t recurse (unsigned int lookup_index)
179  { return default_return_value (); }
180
181  hb_get_coverage_context_t (void) {}
182};
183
184
185
186#ifndef HB_DEBUG_APPLY
187#define HB_DEBUG_APPLY (HB_DEBUG+0)
188#endif
189
190#define TRACE_APPLY() \
191	hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace \
192	(&c->debug_depth, "APPLY", this, HB_FUNC, \
193	 "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);
194
195struct hb_apply_context_t
196{
197  typedef bool return_t;
198  typedef return_t (*recurse_func_t) (hb_apply_context_t *c, unsigned int lookup_index);
199  template <typename T>
200  inline return_t process (const T &obj) { return obj.apply (this); }
201  static return_t default_return_value (void) { return false; }
202  bool stop_sublookup_iteration (const return_t r) const { return r; }
203  return_t recurse (unsigned int lookup_index)
204  {
205    if (unlikely (nesting_level_left == 0 || !recurse_func))
206      return default_return_value ();
207
208    hb_apply_context_t new_c (*this);
209    new_c.nesting_level_left--;
210    return recurse_func (&new_c, lookup_index);
211  }
212
213  hb_font_t *font;
214  hb_face_t *face;
215  hb_buffer_t *buffer;
216  hb_direction_t direction;
217  hb_mask_t lookup_mask;
218  recurse_func_t recurse_func;
219  unsigned int nesting_level_left;
220  unsigned int lookup_props;
221  unsigned int property; /* propety of first glyph */
222  unsigned int debug_depth;
223  const GDEF &gdef;
224  bool has_glyph_classes;
225
226
227  hb_apply_context_t (hb_font_t *font_,
228		      hb_buffer_t *buffer_,
229		      hb_mask_t lookup_mask_) :
230			font (font_), face (font->face), buffer (buffer_),
231			direction (buffer_->props.direction),
232			lookup_mask (lookup_mask_),
233			recurse_func (NULL),
234			nesting_level_left (MAX_NESTING_LEVEL),
235			lookup_props (0), property (0), debug_depth (0),
236			gdef (*hb_ot_layout_from_face (face)->gdef),
237			has_glyph_classes (gdef.has_glyph_classes ()) {}
238
239  void set_recurse_func (recurse_func_t func) { recurse_func = func; }
240  void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
241  void set_lookup (const Lookup &l) { lookup_props = l.get_props (); }
242
243  struct mark_skipping_forward_iterator_t
244  {
245    inline mark_skipping_forward_iterator_t (hb_apply_context_t *c_,
246					     unsigned int start_index_,
247					     unsigned int num_items_,
248					     bool context_match = false)
249    {
250      c = c_;
251      idx = start_index_;
252      num_items = num_items_;
253      mask = context_match ? -1 : c->lookup_mask;
254      syllable = context_match ? 0 : c->buffer->cur().syllable ();
255      end = c->buffer->len;
256    }
257    inline bool has_no_chance (void) const
258    {
259      return unlikely (num_items && idx + num_items >= end);
260    }
261    inline void reject (void)
262    {
263      num_items++;
264    }
265    inline bool next (unsigned int *property_out,
266		      unsigned int  lookup_props)
267    {
268      assert (num_items > 0);
269      do
270      {
271	if (has_no_chance ())
272	  return false;
273	idx++;
274      } while (c->should_skip_mark (&c->buffer->info[idx], lookup_props, property_out));
275      num_items--;
276      return (c->buffer->info[idx].mask & mask) && (!syllable || syllable == c->buffer->info[idx].syllable ());
277    }
278    inline bool next (unsigned int *property_out = NULL)
279    {
280      return next (property_out, c->lookup_props);
281    }
282
283    unsigned int idx;
284    protected:
285    hb_apply_context_t *c;
286    unsigned int num_items;
287    hb_mask_t mask;
288    uint8_t syllable;
289    unsigned int end;
290  };
291
292  struct mark_skipping_backward_iterator_t
293  {
294    inline mark_skipping_backward_iterator_t (hb_apply_context_t *c_,
295					      unsigned int start_index_,
296					      unsigned int num_items_,
297					      hb_mask_t mask_ = 0,
298					      bool match_syllable_ = true)
299    {
300      c = c_;
301      idx = start_index_;
302      num_items = num_items_;
303      mask = mask_ ? mask_ : c->lookup_mask;
304      syllable = match_syllable_ ? c->buffer->cur().syllable () : 0;
305    }
306    inline bool has_no_chance (void) const
307    {
308      return unlikely (idx < num_items);
309    }
310    inline void reject (void)
311    {
312      num_items++;
313    }
314    inline bool prev (unsigned int *property_out,
315		      unsigned int  lookup_props)
316    {
317      assert (num_items > 0);
318      do
319      {
320	if (has_no_chance ())
321	  return false;
322	idx--;
323      } while (c->should_skip_mark (&c->buffer->out_info[idx], lookup_props, property_out));
324      num_items--;
325      return (c->buffer->out_info[idx].mask & mask) && (!syllable || syllable == c->buffer->out_info[idx].syllable ());
326    }
327    inline bool prev (unsigned int *property_out = NULL)
328    {
329      return prev (property_out, c->lookup_props);
330    }
331
332    unsigned int idx;
333    protected:
334    hb_apply_context_t *c;
335    unsigned int num_items;
336    hb_mask_t mask;
337    uint8_t syllable;
338  };
339
340  inline bool
341  match_properties_mark (hb_codepoint_t  glyph,
342			 unsigned int    glyph_props,
343			 unsigned int    lookup_props) const
344  {
345    /* If using mark filtering sets, the high short of
346     * lookup_props has the set index.
347     */
348    if (lookup_props & LookupFlag::UseMarkFilteringSet)
349      return gdef.mark_set_covers (lookup_props >> 16, glyph);
350
351    /* The second byte of lookup_props has the meaning
352     * "ignore marks of attachment type different than
353     * the attachment type specified."
354     */
355    if (lookup_props & LookupFlag::MarkAttachmentType)
356      return (lookup_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);
357
358    return true;
359  }
360
361  inline bool
362  match_properties (hb_codepoint_t  glyph,
363		    unsigned int    glyph_props,
364		    unsigned int    lookup_props) const
365  {
366    /* Not covered, if, for example, glyph class is ligature and
367     * lookup_props includes LookupFlags::IgnoreLigatures
368     */
369    if (glyph_props & lookup_props & LookupFlag::IgnoreFlags)
370      return false;
371
372    if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK))
373      return match_properties_mark (glyph, glyph_props, lookup_props);
374
375    return true;
376  }
377
378  inline bool
379  check_glyph_property (hb_glyph_info_t *info,
380			unsigned int  lookup_props,
381			unsigned int *property_out) const
382  {
383    unsigned int property;
384
385    property = info->glyph_props();
386    *property_out = property;
387
388    return match_properties (info->codepoint, property, lookup_props);
389  }
390
391  inline bool
392  should_skip_mark (hb_glyph_info_t *info,
393		   unsigned int  lookup_props,
394		   unsigned int *property_out) const
395  {
396    unsigned int property;
397
398    property = info->glyph_props();
399    if (property_out)
400      *property_out = property;
401
402    /* If it's a mark, skip it if we don't accept it. */
403    if (unlikely (property & HB_OT_LAYOUT_GLYPH_PROPS_MARK))
404      return !match_properties (info->codepoint, property, lookup_props);
405
406    /* If not a mark, don't skip. */
407    return false;
408  }
409
410
411  inline bool should_mark_skip_current_glyph (void) const
412  {
413    return should_skip_mark (&buffer->cur(), lookup_props, NULL);
414  }
415
416  inline void set_class (hb_codepoint_t glyph_index, unsigned int class_guess) const
417  {
418    if (likely (has_glyph_classes))
419      buffer->cur().glyph_props() = gdef.get_glyph_props (glyph_index);
420    else if (class_guess)
421      buffer->cur().glyph_props() = class_guess;
422  }
423
424  inline void output_glyph (hb_codepoint_t glyph_index,
425			    unsigned int class_guess = 0) const
426  {
427    set_class (glyph_index, class_guess);
428    buffer->output_glyph (glyph_index);
429  }
430  inline void replace_glyph (hb_codepoint_t glyph_index,
431			     unsigned int class_guess = 0) const
432  {
433    set_class (glyph_index, class_guess);
434    buffer->replace_glyph (glyph_index);
435  }
436  inline void replace_glyph_inplace (hb_codepoint_t glyph_index,
437				     unsigned int class_guess = 0) const
438  {
439    set_class (glyph_index, class_guess);
440    buffer->cur().codepoint = glyph_index;
441  }
442};
443
444
445
446typedef bool (*intersects_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data);
447typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data);
448
449struct ContextClosureFuncs
450{
451  intersects_func_t intersects;
452};
453struct ContextApplyFuncs
454{
455  match_func_t match;
456};
457
458static inline bool intersects_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED)
459{
460  return glyphs->has (value);
461}
462static inline bool intersects_class (hb_set_t *glyphs, const USHORT &value, const void *data)
463{
464  const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
465  return class_def.intersects_class (glyphs, value);
466}
467static inline bool intersects_coverage (hb_set_t *glyphs, const USHORT &value, const void *data)
468{
469  const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
470  return (data+coverage).intersects (glyphs);
471}
472
473static inline bool intersects_array (hb_closure_context_t *c,
474				     unsigned int count,
475				     const USHORT values[],
476				     intersects_func_t intersects_func,
477				     const void *intersects_data)
478{
479  for (unsigned int i = 0; i < count; i++)
480    if (likely (!intersects_func (c->glyphs, values[i], intersects_data)))
481      return false;
482  return true;
483}
484
485
486static inline bool match_glyph (hb_codepoint_t glyph_id, const USHORT &value, const void *data HB_UNUSED)
487{
488  return glyph_id == value;
489}
490static inline bool match_class (hb_codepoint_t glyph_id, const USHORT &value, const void *data)
491{
492  const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
493  return class_def.get_class (glyph_id) == value;
494}
495static inline bool match_coverage (hb_codepoint_t glyph_id, const USHORT &value, const void *data)
496{
497  const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
498  return (data+coverage).get_coverage (glyph_id) != NOT_COVERED;
499}
500
501
502static inline bool would_match_input (hb_would_apply_context_t *c,
503				      unsigned int count, /* Including the first glyph (not matched) */
504				      const USHORT input[], /* Array of input values--start with second glyph */
505				      match_func_t match_func,
506				      const void *match_data)
507{
508  if (count != c->len)
509    return false;
510
511  for (unsigned int i = 1; i < count; i++)
512    if (likely (!match_func (c->glyphs[i], input[i - 1], match_data)))
513      return false;
514
515  return true;
516}
517static inline bool match_input (hb_apply_context_t *c,
518				unsigned int count, /* Including the first glyph (not matched) */
519				const USHORT input[], /* Array of input values--start with second glyph */
520				match_func_t match_func,
521				const void *match_data,
522				unsigned int *end_offset = NULL,
523				bool *p_is_mark_ligature = NULL,
524				unsigned int *p_total_component_count = NULL)
525{
526  hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace
527    (&c->debug_depth, "APPLY", NULL, HB_FUNC,
528     "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);
529
530  hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1);
531  if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
532
533  /*
534   * This is perhaps the trickiest part of OpenType...  Remarks:
535   *
536   * - If all components of the ligature were marks, we call this a mark ligature.
537   *
538   * - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize
539   *   it as a ligature glyph.
540   *
541   * - Ligatures cannot be formed across glyphs attached to different components
542   *   of previous ligatures.  Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and
543   *   LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother.
544   *   However, it would be wrong to ligate that SHADDA,FATHA sequence.o
545   *   There is an exception to this: If a ligature tries ligating with marks that
546   *   belong to it itself, go ahead, assuming that the font designer knows what
547   *   they are doing (otherwise it can break Indic stuff when a matra wants to
548   *   ligate with a conjunct...)
549   */
550
551  bool is_mark_ligature = !!(c->property & HB_OT_LAYOUT_GLYPH_PROPS_MARK);
552
553  unsigned int total_component_count = 0;
554  total_component_count += get_lig_num_comps (c->buffer->cur());
555
556  unsigned int first_lig_id = get_lig_id (c->buffer->cur());
557  unsigned int first_lig_comp = get_lig_comp (c->buffer->cur());
558
559  for (unsigned int i = 1; i < count; i++)
560  {
561    unsigned int property;
562
563    if (!skippy_iter.next (&property)) return TRACE_RETURN (false);
564
565    if (likely (!match_func (c->buffer->info[skippy_iter.idx].codepoint, input[i - 1], match_data))) return TRACE_RETURN (false);
566
567    unsigned int this_lig_id = get_lig_id (c->buffer->info[skippy_iter.idx]);
568    unsigned int this_lig_comp = get_lig_comp (c->buffer->info[skippy_iter.idx]);
569
570    if (first_lig_id && first_lig_comp) {
571      /* If first component was attached to a previous ligature component,
572       * all subsequent components should be attached to the same ligature
573       * component, otherwise we shouldn't ligate them. */
574      if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
575	return TRACE_RETURN (false);
576    } else {
577      /* If first component was NOT attached to a previous ligature component,
578       * all subsequent components should also NOT be attached to any ligature
579       * component, unless they are attached to the first component itself! */
580      if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id))
581	return TRACE_RETURN (false);
582    }
583
584    is_mark_ligature = is_mark_ligature && (property & HB_OT_LAYOUT_GLYPH_PROPS_MARK);
585    total_component_count += get_lig_num_comps (c->buffer->info[skippy_iter.idx]);
586  }
587
588  if (end_offset)
589    *end_offset = skippy_iter.idx - c->buffer->idx + 1;
590
591  if (p_is_mark_ligature)
592    *p_is_mark_ligature = is_mark_ligature;
593
594  if (p_total_component_count)
595    *p_total_component_count = total_component_count;
596
597  return TRACE_RETURN (true);
598}
599static inline void ligate_input (hb_apply_context_t *c,
600				 unsigned int count, /* Including the first glyph (not matched) */
601				 const USHORT input[], /* Array of input values--start with second glyph */
602				 hb_codepoint_t lig_glyph,
603				 match_func_t match_func,
604				 const void *match_data,
605				 bool is_mark_ligature,
606				 unsigned int total_component_count)
607{
608  /*
609   * - If it *is* a mark ligature, we don't allocate a new ligature id, and leave
610   *   the ligature to keep its old ligature id.  This will allow it to attach to
611   *   a base ligature in GPOS.  Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH,
612   *   and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA wit a
613   *   ligature id and component value of 2.  Then if SHADDA,FATHA form a ligature
614   *   later, we don't want them to lose their ligature id/component, otherwise
615   *   GPOS will fail to correctly position the mark ligature on top of the
616   *   LAM,LAM,HEH ligature.  See:
617   *     https://bugzilla.gnome.org/show_bug.cgi?id=676343
618   *
619   * - If a ligature is formed of components that some of which are also ligatures
620   *   themselves, and those ligature components had marks attached to *their*
621   *   components, we have to attach the marks to the new ligature component
622   *   positions!  Now *that*'s tricky!  And these marks may be following the
623   *   last component of the whole sequence, so we should loop forward looking
624   *   for them and update them.
625   *
626   *   Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a
627   *   'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature
628   *   id and component == 1.  Now, during 'liga', the LAM and the LAM-HEH ligature
629   *   form a LAM-LAM-HEH ligature.  We need to reassign the SHADDA and FATHA to
630   *   the new ligature with a component value of 2.
631   *
632   *   This in fact happened to a font...  See:
633   *   https://bugzilla.gnome.org/show_bug.cgi?id=437633
634   */
635
636  unsigned int klass = is_mark_ligature ? 0 : HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
637  unsigned int lig_id = is_mark_ligature ? 0 : allocate_lig_id (c->buffer);
638  unsigned int last_lig_id = get_lig_id (c->buffer->cur());
639  unsigned int last_num_components = get_lig_num_comps (c->buffer->cur());
640  unsigned int components_so_far = last_num_components;
641
642  if (!is_mark_ligature)
643    set_lig_props_for_ligature (c->buffer->cur(), lig_id, total_component_count);
644  c->replace_glyph (lig_glyph, klass);
645
646  for (unsigned int i = 1; i < count; i++)
647  {
648    while (c->should_mark_skip_current_glyph ())
649    {
650      if (!is_mark_ligature) {
651	unsigned int new_lig_comp = components_so_far - last_num_components +
652				    MIN (MAX (get_lig_comp (c->buffer->cur()), 1u), last_num_components);
653	set_lig_props_for_mark (c->buffer->cur(), lig_id, new_lig_comp);
654      }
655      c->buffer->next_glyph ();
656    }
657
658    last_lig_id = get_lig_id (c->buffer->cur());
659    last_num_components = get_lig_num_comps (c->buffer->cur());
660    components_so_far += last_num_components;
661
662    /* Skip the base glyph */
663    c->buffer->idx++;
664  }
665
666  if (!is_mark_ligature && last_lig_id) {
667    /* Re-adjust components for any marks following. */
668    for (unsigned int i = c->buffer->idx; i < c->buffer->len; i++) {
669      if (last_lig_id == get_lig_id (c->buffer->info[i])) {
670	unsigned int new_lig_comp = components_so_far - last_num_components +
671				    MIN (MAX (get_lig_comp (c->buffer->info[i]), 1u), last_num_components);
672	set_lig_props_for_mark (c->buffer->info[i], lig_id, new_lig_comp);
673      } else
674	break;
675    }
676  }
677}
678
679static inline bool match_backtrack (hb_apply_context_t *c,
680				    unsigned int count,
681				    const USHORT backtrack[],
682				    match_func_t match_func,
683				    const void *match_data)
684{
685  hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace
686    (&c->debug_depth, "APPLY", NULL, HB_FUNC,
687     "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);
688
689  hb_apply_context_t::mark_skipping_backward_iterator_t skippy_iter (c, c->buffer->backtrack_len (), count, true);
690  if (skippy_iter.has_no_chance ())
691    return TRACE_RETURN (false);
692
693  for (unsigned int i = 0; i < count; i++)
694  {
695    if (!skippy_iter.prev ())
696      return TRACE_RETURN (false);
697
698    if (likely (!match_func (c->buffer->out_info[skippy_iter.idx].codepoint, backtrack[i], match_data)))
699      return TRACE_RETURN (false);
700  }
701
702  return TRACE_RETURN (true);
703}
704
705static inline bool match_lookahead (hb_apply_context_t *c,
706				    unsigned int count,
707				    const USHORT lookahead[],
708				    match_func_t match_func,
709				    const void *match_data,
710				    unsigned int offset)
711{
712  hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace
713    (&c->debug_depth, "APPLY", NULL, HB_FUNC,
714     "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);
715
716  hb_apply_context_t::mark_skipping_forward_iterator_t skippy_iter (c, c->buffer->idx + offset - 1, count, true);
717  if (skippy_iter.has_no_chance ())
718    return TRACE_RETURN (false);
719
720  for (unsigned int i = 0; i < count; i++)
721  {
722    if (!skippy_iter.next ())
723      return TRACE_RETURN (false);
724
725    if (likely (!match_func (c->buffer->info[skippy_iter.idx].codepoint, lookahead[i], match_data)))
726      return TRACE_RETURN (false);
727  }
728
729  return TRACE_RETURN (true);
730}
731
732
733
734struct LookupRecord
735{
736  inline bool sanitize (hb_sanitize_context_t *c) {
737    TRACE_SANITIZE ();
738    return TRACE_RETURN (c->check_struct (this));
739  }
740
741  USHORT	sequenceIndex;		/* Index into current glyph
742					 * sequence--first glyph = 0 */
743  USHORT	lookupListIndex;	/* Lookup to apply to that
744					 * position--zero--based */
745  public:
746  DEFINE_SIZE_STATIC (4);
747};
748
749
750static inline void closure_lookup (hb_closure_context_t *c,
751				   unsigned int lookupCount,
752				   const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
753{
754  for (unsigned int i = 0; i < lookupCount; i++)
755    c->recurse (lookupRecord->lookupListIndex);
756}
757
758static inline bool apply_lookup (hb_apply_context_t *c,
759				 unsigned int count, /* Including the first glyph */
760				 unsigned int lookupCount,
761				 const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
762{
763  hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace
764    (&c->debug_depth, "APPLY", NULL, HB_FUNC,
765     "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);
766
767  unsigned int end = c->buffer->len;
768  if (unlikely (count == 0 || c->buffer->idx + count > end))
769    return TRACE_RETURN (false);
770
771  /* TODO We don't support lookupRecord arrays that are not increasing:
772   *      Should be easy for in_place ones at least. */
773
774  /* Note: If sublookup is reverse, it will underflow after the first loop
775   * and we jump out of it.  Not entirely disastrous.  So we don't check
776   * for reverse lookup here.
777   */
778  for (unsigned int i = 0; i < count; /* NOP */)
779  {
780    if (unlikely (c->buffer->idx == end))
781      return TRACE_RETURN (true);
782    while (c->should_mark_skip_current_glyph ())
783    {
784      /* No lookup applied for this index */
785      c->buffer->next_glyph ();
786      if (unlikely (c->buffer->idx == end))
787	return TRACE_RETURN (true);
788    }
789
790    if (lookupCount && i == lookupRecord->sequenceIndex)
791    {
792      unsigned int old_pos = c->buffer->idx;
793
794      /* Apply a lookup */
795      bool done = c->recurse (lookupRecord->lookupListIndex);
796
797      lookupRecord++;
798      lookupCount--;
799      /* Err, this is wrong if the lookup jumped over some glyphs */
800      i += c->buffer->idx - old_pos;
801      if (unlikely (c->buffer->idx == end))
802	return TRACE_RETURN (true);
803
804      if (!done)
805	goto not_applied;
806    }
807    else
808    {
809    not_applied:
810      /* No lookup applied for this index */
811      c->buffer->next_glyph ();
812      i++;
813    }
814  }
815
816  return TRACE_RETURN (true);
817}
818
819
820
821/* Contextual lookups */
822
823struct ContextClosureLookupContext
824{
825  ContextClosureFuncs funcs;
826  const void *intersects_data;
827};
828
829struct ContextApplyLookupContext
830{
831  ContextApplyFuncs funcs;
832  const void *match_data;
833};
834
835static inline void context_closure_lookup (hb_closure_context_t *c,
836					   unsigned int inputCount, /* Including the first glyph (not matched) */
837					   const USHORT input[], /* Array of input values--start with second glyph */
838					   unsigned int lookupCount,
839					   const LookupRecord lookupRecord[],
840					   ContextClosureLookupContext &lookup_context)
841{
842  if (intersects_array (c,
843			inputCount ? inputCount - 1 : 0, input,
844			lookup_context.funcs.intersects, lookup_context.intersects_data))
845    closure_lookup (c,
846		    lookupCount, lookupRecord);
847}
848
849
850static inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
851					       unsigned int inputCount, /* Including the first glyph (not matched) */
852					       const USHORT input[], /* Array of input values--start with second glyph */
853					       unsigned int lookupCount,
854					       const LookupRecord lookupRecord[],
855					       ContextApplyLookupContext &lookup_context)
856{
857  return would_match_input (c,
858			    inputCount, input,
859			    lookup_context.funcs.match, lookup_context.match_data);
860}
861static inline bool context_apply_lookup (hb_apply_context_t *c,
862					 unsigned int inputCount, /* Including the first glyph (not matched) */
863					 const USHORT input[], /* Array of input values--start with second glyph */
864					 unsigned int lookupCount,
865					 const LookupRecord lookupRecord[],
866					 ContextApplyLookupContext &lookup_context)
867{
868  return match_input (c,
869		      inputCount, input,
870		      lookup_context.funcs.match, lookup_context.match_data)
871      && apply_lookup (c,
872		       inputCount,
873		       lookupCount, lookupRecord);
874}
875
876struct Rule
877{
878  inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
879  {
880    TRACE_CLOSURE ();
881    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
882    context_closure_lookup (c,
883			    inputCount, input,
884			    lookupCount, lookupRecord,
885			    lookup_context);
886  }
887
888  inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
889  {
890    TRACE_WOULD_APPLY ();
891    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
892    return TRACE_RETURN (context_would_apply_lookup (c, inputCount, input, lookupCount, lookupRecord, lookup_context));
893  }
894
895  inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
896  {
897    TRACE_APPLY ();
898    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
899    return TRACE_RETURN (context_apply_lookup (c, inputCount, input, lookupCount, lookupRecord, lookup_context));
900  }
901
902  public:
903  inline bool sanitize (hb_sanitize_context_t *c) {
904    TRACE_SANITIZE ();
905    return inputCount.sanitize (c)
906	&& lookupCount.sanitize (c)
907	&& c->check_range (input,
908			   input[0].static_size * inputCount
909			   + lookupRecordX[0].static_size * lookupCount);
910  }
911
912  protected:
913  USHORT	inputCount;		/* Total number of glyphs in input
914					 * glyph sequence--includes the first
915					 * glyph */
916  USHORT	lookupCount;		/* Number of LookupRecords */
917  USHORT	input[VAR];		/* Array of match inputs--start with
918					 * second glyph */
919  LookupRecord	lookupRecordX[VAR];	/* Array of LookupRecords--in
920					 * design order */
921  public:
922  DEFINE_SIZE_ARRAY2 (4, input, lookupRecordX);
923};
924
925struct RuleSet
926{
927  inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
928  {
929    TRACE_CLOSURE ();
930    unsigned int num_rules = rule.len;
931    for (unsigned int i = 0; i < num_rules; i++)
932      (this+rule[i]).closure (c, lookup_context);
933  }
934
935  inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
936  {
937    TRACE_WOULD_APPLY ();
938    unsigned int num_rules = rule.len;
939    for (unsigned int i = 0; i < num_rules; i++)
940    {
941      if ((this+rule[i]).would_apply (c, lookup_context))
942        return TRACE_RETURN (true);
943    }
944    return TRACE_RETURN (false);
945  }
946
947  inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
948  {
949    TRACE_APPLY ();
950    unsigned int num_rules = rule.len;
951    for (unsigned int i = 0; i < num_rules; i++)
952    {
953      if ((this+rule[i]).apply (c, lookup_context))
954        return TRACE_RETURN (true);
955    }
956    return TRACE_RETURN (false);
957  }
958
959  inline bool sanitize (hb_sanitize_context_t *c) {
960    TRACE_SANITIZE ();
961    return TRACE_RETURN (rule.sanitize (c, this));
962  }
963
964  protected:
965  OffsetArrayOf<Rule>
966		rule;			/* Array of Rule tables
967					 * ordered by preference */
968  public:
969  DEFINE_SIZE_ARRAY (2, rule);
970};
971
972
973struct ContextFormat1
974{
975  inline void closure (hb_closure_context_t *c) const
976  {
977    TRACE_CLOSURE ();
978
979    const Coverage &cov = (this+coverage);
980
981    struct ContextClosureLookupContext lookup_context = {
982      {intersects_glyph},
983      NULL
984    };
985
986    unsigned int count = ruleSet.len;
987    for (unsigned int i = 0; i < count; i++)
988      if (cov.intersects_coverage (c->glyphs, i)) {
989	const RuleSet &rule_set = this+ruleSet[i];
990	rule_set.closure (c, lookup_context);
991      }
992  }
993
994  inline bool would_apply (hb_would_apply_context_t *c) const
995  {
996    TRACE_WOULD_APPLY ();
997
998    const RuleSet &rule_set = this+ruleSet[(this+coverage) (c->glyphs[0])];
999    struct ContextApplyLookupContext lookup_context = {
1000      {match_glyph},
1001      NULL
1002    };
1003    return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
1004  }
1005
1006  inline const Coverage &get_coverage (void) const
1007  {
1008    return this+coverage;
1009  }
1010
1011  inline bool apply (hb_apply_context_t *c) const
1012  {
1013    TRACE_APPLY ();
1014    unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
1015    if (likely (index == NOT_COVERED))
1016      return TRACE_RETURN (false);
1017
1018    const RuleSet &rule_set = this+ruleSet[index];
1019    struct ContextApplyLookupContext lookup_context = {
1020      {match_glyph},
1021      NULL
1022    };
1023    return TRACE_RETURN (rule_set.apply (c, lookup_context));
1024  }
1025
1026  inline bool sanitize (hb_sanitize_context_t *c) {
1027    TRACE_SANITIZE ();
1028    return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
1029  }
1030
1031  protected:
1032  USHORT	format;			/* Format identifier--format = 1 */
1033  OffsetTo<Coverage>
1034		coverage;		/* Offset to Coverage table--from
1035					 * beginning of table */
1036  OffsetArrayOf<RuleSet>
1037		ruleSet;		/* Array of RuleSet tables
1038					 * ordered by Coverage Index */
1039  public:
1040  DEFINE_SIZE_ARRAY (6, ruleSet);
1041};
1042
1043
1044struct ContextFormat2
1045{
1046  inline void closure (hb_closure_context_t *c) const
1047  {
1048    TRACE_CLOSURE ();
1049    if (!(this+coverage).intersects (c->glyphs))
1050      return;
1051
1052    const ClassDef &class_def = this+classDef;
1053
1054    struct ContextClosureLookupContext lookup_context = {
1055      {intersects_class},
1056      NULL
1057    };
1058
1059    unsigned int count = ruleSet.len;
1060    for (unsigned int i = 0; i < count; i++)
1061      if (class_def.intersects_class (c->glyphs, i)) {
1062	const RuleSet &rule_set = this+ruleSet[i];
1063	rule_set.closure (c, lookup_context);
1064      }
1065  }
1066
1067  inline bool would_apply (hb_would_apply_context_t *c) const
1068  {
1069    TRACE_WOULD_APPLY ();
1070
1071    const ClassDef &class_def = this+classDef;
1072    unsigned int index = class_def (c->glyphs[0]);
1073    const RuleSet &rule_set = this+ruleSet[index];
1074    struct ContextApplyLookupContext lookup_context = {
1075      {match_class},
1076      &class_def
1077    };
1078    return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
1079  }
1080
1081  inline const Coverage &get_coverage (void) const
1082  {
1083    return this+coverage;
1084  }
1085
1086  inline bool apply (hb_apply_context_t *c) const
1087  {
1088    TRACE_APPLY ();
1089    unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
1090    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
1091
1092    const ClassDef &class_def = this+classDef;
1093    index = class_def (c->buffer->cur().codepoint);
1094    const RuleSet &rule_set = this+ruleSet[index];
1095    struct ContextApplyLookupContext lookup_context = {
1096      {match_class},
1097      &class_def
1098    };
1099    return TRACE_RETURN (rule_set.apply (c, lookup_context));
1100  }
1101
1102  inline bool sanitize (hb_sanitize_context_t *c) {
1103    TRACE_SANITIZE ();
1104    return TRACE_RETURN (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
1105  }
1106
1107  protected:
1108  USHORT	format;			/* Format identifier--format = 2 */
1109  OffsetTo<Coverage>
1110		coverage;		/* Offset to Coverage table--from
1111					 * beginning of table */
1112  OffsetTo<ClassDef>
1113		classDef;		/* Offset to glyph ClassDef table--from
1114					 * beginning of table */
1115  OffsetArrayOf<RuleSet>
1116		ruleSet;		/* Array of RuleSet tables
1117					 * ordered by class */
1118  public:
1119  DEFINE_SIZE_ARRAY (8, ruleSet);
1120};
1121
1122
1123struct ContextFormat3
1124{
1125  inline void closure (hb_closure_context_t *c) const
1126  {
1127    TRACE_CLOSURE ();
1128    if (!(this+coverage[0]).intersects (c->glyphs))
1129      return;
1130
1131    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
1132    struct ContextClosureLookupContext lookup_context = {
1133      {intersects_coverage},
1134      this
1135    };
1136    context_closure_lookup (c,
1137			    glyphCount, (const USHORT *) (coverage + 1),
1138			    lookupCount, lookupRecord,
1139			    lookup_context);
1140  }
1141
1142  inline bool would_apply (hb_would_apply_context_t *c) const
1143  {
1144    TRACE_WOULD_APPLY ();
1145
1146    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
1147    struct ContextApplyLookupContext lookup_context = {
1148      {match_coverage},
1149      this
1150    };
1151    return TRACE_RETURN (context_would_apply_lookup (c, glyphCount, (const USHORT *) (coverage + 1), lookupCount, lookupRecord, lookup_context));
1152  }
1153
1154  inline const Coverage &get_coverage (void) const
1155  {
1156    return this+coverage[0];
1157  }
1158
1159  inline bool apply (hb_apply_context_t *c) const
1160  {
1161    TRACE_APPLY ();
1162    unsigned int index = (this+coverage[0]) (c->buffer->cur().codepoint);
1163    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
1164
1165    const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
1166    struct ContextApplyLookupContext lookup_context = {
1167      {match_coverage},
1168      this
1169    };
1170    return TRACE_RETURN (context_apply_lookup (c, glyphCount, (const USHORT *) (coverage + 1), lookupCount, lookupRecord, lookup_context));
1171  }
1172
1173  inline bool sanitize (hb_sanitize_context_t *c) {
1174    TRACE_SANITIZE ();
1175    if (!c->check_struct (this)) return TRACE_RETURN (false);
1176    unsigned int count = glyphCount;
1177    if (!c->check_array (coverage, coverage[0].static_size, count)) return TRACE_RETURN (false);
1178    for (unsigned int i = 0; i < count; i++)
1179      if (!coverage[i].sanitize (c, this)) return TRACE_RETURN (false);
1180    LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * count);
1181    return TRACE_RETURN (c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount));
1182  }
1183
1184  protected:
1185  USHORT	format;			/* Format identifier--format = 3 */
1186  USHORT	glyphCount;		/* Number of glyphs in the input glyph
1187					 * sequence */
1188  USHORT	lookupCount;		/* Number of LookupRecords */
1189  OffsetTo<Coverage>
1190		coverage[VAR];		/* Array of offsets to Coverage
1191					 * table in glyph sequence order */
1192  LookupRecord	lookupRecordX[VAR];	/* Array of LookupRecords--in
1193					 * design order */
1194  public:
1195  DEFINE_SIZE_ARRAY2 (6, coverage, lookupRecordX);
1196};
1197
1198struct Context
1199{
1200  template <typename context_t>
1201  inline typename context_t::return_t process (context_t *c) const
1202  {
1203    switch (u.format) {
1204    case 1: return c->process (u.format1);
1205    case 2: return c->process (u.format2);
1206    case 3: return c->process (u.format3);
1207    default:return c->default_return_value ();
1208    }
1209  }
1210
1211  inline bool sanitize (hb_sanitize_context_t *c) {
1212    TRACE_SANITIZE ();
1213    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
1214    switch (u.format) {
1215    case 1: return TRACE_RETURN (u.format1.sanitize (c));
1216    case 2: return TRACE_RETURN (u.format2.sanitize (c));
1217    case 3: return TRACE_RETURN (u.format3.sanitize (c));
1218    default:return TRACE_RETURN (true);
1219    }
1220  }
1221
1222  protected:
1223  union {
1224  USHORT		format;		/* Format identifier */
1225  ContextFormat1	format1;
1226  ContextFormat2	format2;
1227  ContextFormat3	format3;
1228  } u;
1229};
1230
1231
1232/* Chaining Contextual lookups */
1233
1234struct ChainContextClosureLookupContext
1235{
1236  ContextClosureFuncs funcs;
1237  const void *intersects_data[3];
1238};
1239
1240struct ChainContextApplyLookupContext
1241{
1242  ContextApplyFuncs funcs;
1243  const void *match_data[3];
1244};
1245
1246static inline void chain_context_closure_lookup (hb_closure_context_t *c,
1247						 unsigned int backtrackCount,
1248						 const USHORT backtrack[],
1249						 unsigned int inputCount, /* Including the first glyph (not matched) */
1250						 const USHORT input[], /* Array of input values--start with second glyph */
1251						 unsigned int lookaheadCount,
1252						 const USHORT lookahead[],
1253						 unsigned int lookupCount,
1254						 const LookupRecord lookupRecord[],
1255						 ChainContextClosureLookupContext &lookup_context)
1256{
1257  if (intersects_array (c,
1258			backtrackCount, backtrack,
1259			lookup_context.funcs.intersects, lookup_context.intersects_data[0])
1260   && intersects_array (c,
1261			inputCount ? inputCount - 1 : 0, input,
1262			lookup_context.funcs.intersects, lookup_context.intersects_data[1])
1263  && intersects_array (c,
1264		       lookaheadCount, lookahead,
1265		       lookup_context.funcs.intersects, lookup_context.intersects_data[2]))
1266    closure_lookup (c,
1267		    lookupCount, lookupRecord);
1268}
1269
1270static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c,
1271						     unsigned int backtrackCount,
1272						     const USHORT backtrack[],
1273						     unsigned int inputCount, /* Including the first glyph (not matched) */
1274						     const USHORT input[], /* Array of input values--start with second glyph */
1275						     unsigned int lookaheadCount,
1276						     const USHORT lookahead[],
1277						     unsigned int lookupCount,
1278						     const LookupRecord lookupRecord[],
1279						     ChainContextApplyLookupContext &lookup_context)
1280{
1281  return (c->zero_context ? !backtrackCount && !lookaheadCount : true)
1282      && would_match_input (c,
1283			    inputCount, input,
1284			    lookup_context.funcs.match, lookup_context.match_data[1]);
1285}
1286
1287static inline bool chain_context_apply_lookup (hb_apply_context_t *c,
1288					       unsigned int backtrackCount,
1289					       const USHORT backtrack[],
1290					       unsigned int inputCount, /* Including the first glyph (not matched) */
1291					       const USHORT input[], /* Array of input values--start with second glyph */
1292					       unsigned int lookaheadCount,
1293					       const USHORT lookahead[],
1294					       unsigned int lookupCount,
1295					       const LookupRecord lookupRecord[],
1296					       ChainContextApplyLookupContext &lookup_context)
1297{
1298  unsigned int lookahead_offset = 0;
1299  return match_input (c,
1300		      inputCount, input,
1301		      lookup_context.funcs.match, lookup_context.match_data[1],
1302		      &lookahead_offset)
1303      && match_backtrack (c,
1304			  backtrackCount, backtrack,
1305			  lookup_context.funcs.match, lookup_context.match_data[0])
1306      && match_lookahead (c,
1307			  lookaheadCount, lookahead,
1308			  lookup_context.funcs.match, lookup_context.match_data[2],
1309			  lookahead_offset)
1310      && apply_lookup (c,
1311		       inputCount,
1312		       lookupCount, lookupRecord);
1313}
1314
1315struct ChainRule
1316{
1317  inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
1318  {
1319    TRACE_CLOSURE ();
1320    const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
1321    const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
1322    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1323    chain_context_closure_lookup (c,
1324				  backtrack.len, backtrack.array,
1325				  input.len, input.array,
1326				  lookahead.len, lookahead.array,
1327				  lookup.len, lookup.array,
1328				  lookup_context);
1329  }
1330
1331  inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
1332  {
1333    TRACE_WOULD_APPLY ();
1334    const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
1335    const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
1336    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1337    return TRACE_RETURN (chain_context_would_apply_lookup (c,
1338							   backtrack.len, backtrack.array,
1339							   input.len, input.array,
1340							   lookahead.len, lookahead.array, lookup.len,
1341							   lookup.array, lookup_context));
1342  }
1343
1344  inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
1345  {
1346    TRACE_APPLY ();
1347    const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
1348    const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
1349    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1350    return TRACE_RETURN (chain_context_apply_lookup (c,
1351						     backtrack.len, backtrack.array,
1352						     input.len, input.array,
1353						     lookahead.len, lookahead.array, lookup.len,
1354						     lookup.array, lookup_context));
1355  }
1356
1357  inline bool sanitize (hb_sanitize_context_t *c) {
1358    TRACE_SANITIZE ();
1359    if (!backtrack.sanitize (c)) return TRACE_RETURN (false);
1360    HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
1361    if (!input.sanitize (c)) return TRACE_RETURN (false);
1362    ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
1363    if (!lookahead.sanitize (c)) return TRACE_RETURN (false);
1364    ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1365    return TRACE_RETURN (lookup.sanitize (c));
1366  }
1367
1368  protected:
1369  ArrayOf<USHORT>
1370		backtrack;		/* Array of backtracking values
1371					 * (to be matched before the input
1372					 * sequence) */
1373  HeadlessArrayOf<USHORT>
1374		inputX;			/* Array of input values (start with
1375					 * second glyph) */
1376  ArrayOf<USHORT>
1377		lookaheadX;		/* Array of lookahead values's (to be
1378					 * matched after the input sequence) */
1379  ArrayOf<LookupRecord>
1380		lookupX;		/* Array of LookupRecords--in
1381					 * design order) */
1382  public:
1383  DEFINE_SIZE_MIN (8);
1384};
1385
1386struct ChainRuleSet
1387{
1388  inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
1389  {
1390    TRACE_CLOSURE ();
1391    unsigned int num_rules = rule.len;
1392    for (unsigned int i = 0; i < num_rules; i++)
1393      (this+rule[i]).closure (c, lookup_context);
1394  }
1395
1396  inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
1397  {
1398    TRACE_WOULD_APPLY ();
1399    unsigned int num_rules = rule.len;
1400    for (unsigned int i = 0; i < num_rules; i++)
1401      if ((this+rule[i]).would_apply (c, lookup_context))
1402        return TRACE_RETURN (true);
1403
1404    return TRACE_RETURN (false);
1405  }
1406
1407  inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
1408  {
1409    TRACE_APPLY ();
1410    unsigned int num_rules = rule.len;
1411    for (unsigned int i = 0; i < num_rules; i++)
1412      if ((this+rule[i]).apply (c, lookup_context))
1413        return TRACE_RETURN (true);
1414
1415    return TRACE_RETURN (false);
1416  }
1417
1418  inline bool sanitize (hb_sanitize_context_t *c) {
1419    TRACE_SANITIZE ();
1420    return TRACE_RETURN (rule.sanitize (c, this));
1421  }
1422
1423  protected:
1424  OffsetArrayOf<ChainRule>
1425		rule;			/* Array of ChainRule tables
1426					 * ordered by preference */
1427  public:
1428  DEFINE_SIZE_ARRAY (2, rule);
1429};
1430
1431struct ChainContextFormat1
1432{
1433  inline void closure (hb_closure_context_t *c) const
1434  {
1435    TRACE_CLOSURE ();
1436    const Coverage &cov = (this+coverage);
1437
1438    struct ChainContextClosureLookupContext lookup_context = {
1439      {intersects_glyph},
1440      {NULL, NULL, NULL}
1441    };
1442
1443    unsigned int count = ruleSet.len;
1444    for (unsigned int i = 0; i < count; i++)
1445      if (cov.intersects_coverage (c->glyphs, i)) {
1446	const ChainRuleSet &rule_set = this+ruleSet[i];
1447	rule_set.closure (c, lookup_context);
1448      }
1449  }
1450
1451  inline bool would_apply (hb_would_apply_context_t *c) const
1452  {
1453    TRACE_WOULD_APPLY ();
1454
1455    const ChainRuleSet &rule_set = this+ruleSet[(this+coverage) (c->glyphs[0])];
1456    struct ChainContextApplyLookupContext lookup_context = {
1457      {match_glyph},
1458      {NULL, NULL, NULL}
1459    };
1460    return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
1461  }
1462
1463  inline const Coverage &get_coverage (void) const
1464  {
1465    return this+coverage;
1466  }
1467
1468  inline bool apply (hb_apply_context_t *c) const
1469  {
1470    TRACE_APPLY ();
1471    unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
1472    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
1473
1474    const ChainRuleSet &rule_set = this+ruleSet[index];
1475    struct ChainContextApplyLookupContext lookup_context = {
1476      {match_glyph},
1477      {NULL, NULL, NULL}
1478    };
1479    return TRACE_RETURN (rule_set.apply (c, lookup_context));
1480  }
1481
1482  inline bool sanitize (hb_sanitize_context_t *c) {
1483    TRACE_SANITIZE ();
1484    return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
1485  }
1486
1487  protected:
1488  USHORT	format;			/* Format identifier--format = 1 */
1489  OffsetTo<Coverage>
1490		coverage;		/* Offset to Coverage table--from
1491					 * beginning of table */
1492  OffsetArrayOf<ChainRuleSet>
1493		ruleSet;		/* Array of ChainRuleSet tables
1494					 * ordered by Coverage Index */
1495  public:
1496  DEFINE_SIZE_ARRAY (6, ruleSet);
1497};
1498
1499struct ChainContextFormat2
1500{
1501  inline void closure (hb_closure_context_t *c) const
1502  {
1503    TRACE_CLOSURE ();
1504    if (!(this+coverage).intersects (c->glyphs))
1505      return;
1506
1507    const ClassDef &backtrack_class_def = this+backtrackClassDef;
1508    const ClassDef &input_class_def = this+inputClassDef;
1509    const ClassDef &lookahead_class_def = this+lookaheadClassDef;
1510
1511    struct ChainContextClosureLookupContext lookup_context = {
1512      {intersects_class},
1513      {&backtrack_class_def,
1514       &input_class_def,
1515       &lookahead_class_def}
1516    };
1517
1518    unsigned int count = ruleSet.len;
1519    for (unsigned int i = 0; i < count; i++)
1520      if (input_class_def.intersects_class (c->glyphs, i)) {
1521	const ChainRuleSet &rule_set = this+ruleSet[i];
1522	rule_set.closure (c, lookup_context);
1523      }
1524  }
1525
1526  inline bool would_apply (hb_would_apply_context_t *c) const
1527  {
1528    TRACE_WOULD_APPLY ();
1529
1530    const ClassDef &input_class_def = this+inputClassDef;
1531
1532    unsigned int index = input_class_def (c->glyphs[0]);
1533    const ChainRuleSet &rule_set = this+ruleSet[index];
1534    struct ChainContextApplyLookupContext lookup_context = {
1535      {match_class},
1536      {NULL, &input_class_def, NULL}
1537    };
1538    return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
1539  }
1540
1541  inline const Coverage &get_coverage (void) const
1542  {
1543    return this+coverage;
1544  }
1545
1546  inline bool apply (hb_apply_context_t *c) const
1547  {
1548    TRACE_APPLY ();
1549    unsigned int index = (this+coverage) (c->buffer->cur().codepoint);
1550    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
1551
1552    const ClassDef &backtrack_class_def = this+backtrackClassDef;
1553    const ClassDef &input_class_def = this+inputClassDef;
1554    const ClassDef &lookahead_class_def = this+lookaheadClassDef;
1555
1556    index = input_class_def (c->buffer->cur().codepoint);
1557    const ChainRuleSet &rule_set = this+ruleSet[index];
1558    struct ChainContextApplyLookupContext lookup_context = {
1559      {match_class},
1560      {&backtrack_class_def,
1561       &input_class_def,
1562       &lookahead_class_def}
1563    };
1564    return TRACE_RETURN (rule_set.apply (c, lookup_context));
1565  }
1566
1567  inline bool sanitize (hb_sanitize_context_t *c) {
1568    TRACE_SANITIZE ();
1569    return TRACE_RETURN (coverage.sanitize (c, this) && backtrackClassDef.sanitize (c, this) &&
1570			 inputClassDef.sanitize (c, this) && lookaheadClassDef.sanitize (c, this) &&
1571			 ruleSet.sanitize (c, this));
1572  }
1573
1574  protected:
1575  USHORT	format;			/* Format identifier--format = 2 */
1576  OffsetTo<Coverage>
1577		coverage;		/* Offset to Coverage table--from
1578					 * beginning of table */
1579  OffsetTo<ClassDef>
1580		backtrackClassDef;	/* Offset to glyph ClassDef table
1581					 * containing backtrack sequence
1582					 * data--from beginning of table */
1583  OffsetTo<ClassDef>
1584		inputClassDef;		/* Offset to glyph ClassDef
1585					 * table containing input sequence
1586					 * data--from beginning of table */
1587  OffsetTo<ClassDef>
1588		lookaheadClassDef;	/* Offset to glyph ClassDef table
1589					 * containing lookahead sequence
1590					 * data--from beginning of table */
1591  OffsetArrayOf<ChainRuleSet>
1592		ruleSet;		/* Array of ChainRuleSet tables
1593					 * ordered by class */
1594  public:
1595  DEFINE_SIZE_ARRAY (12, ruleSet);
1596};
1597
1598struct ChainContextFormat3
1599{
1600  inline void closure (hb_closure_context_t *c) const
1601  {
1602    TRACE_CLOSURE ();
1603    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1604
1605    if (!(this+input[0]).intersects (c->glyphs))
1606      return;
1607
1608    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
1609    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1610    struct ChainContextClosureLookupContext lookup_context = {
1611      {intersects_coverage},
1612      {this, this, this}
1613    };
1614    chain_context_closure_lookup (c,
1615				  backtrack.len, (const USHORT *) backtrack.array,
1616				  input.len, (const USHORT *) input.array + 1,
1617				  lookahead.len, (const USHORT *) lookahead.array,
1618				  lookup.len, lookup.array,
1619				  lookup_context);
1620  }
1621
1622  inline bool would_apply (hb_would_apply_context_t *c) const
1623  {
1624    TRACE_WOULD_APPLY ();
1625
1626    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1627    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
1628    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1629    struct ChainContextApplyLookupContext lookup_context = {
1630      {match_coverage},
1631      {this, this, this}
1632    };
1633    return TRACE_RETURN (chain_context_would_apply_lookup (c,
1634							   backtrack.len, (const USHORT *) backtrack.array,
1635							   input.len, (const USHORT *) input.array + 1,
1636							   lookahead.len, (const USHORT *) lookahead.array,
1637							   lookup.len, lookup.array, lookup_context));
1638  }
1639
1640  inline const Coverage &get_coverage (void) const
1641  {
1642    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1643    return this+input[0];
1644  }
1645
1646  inline bool apply (hb_apply_context_t *c) const
1647  {
1648    TRACE_APPLY ();
1649    const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1650
1651    unsigned int index = (this+input[0]) (c->buffer->cur().codepoint);
1652    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
1653
1654    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
1655    const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1656    struct ChainContextApplyLookupContext lookup_context = {
1657      {match_coverage},
1658      {this, this, this}
1659    };
1660    return TRACE_RETURN (chain_context_apply_lookup (c,
1661						     backtrack.len, (const USHORT *) backtrack.array,
1662						     input.len, (const USHORT *) input.array + 1,
1663						     lookahead.len, (const USHORT *) lookahead.array,
1664						     lookup.len, lookup.array, lookup_context));
1665  }
1666
1667  inline bool sanitize (hb_sanitize_context_t *c) {
1668    TRACE_SANITIZE ();
1669    if (!backtrack.sanitize (c, this)) return TRACE_RETURN (false);
1670    OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1671    if (!input.sanitize (c, this)) return TRACE_RETURN (false);
1672    OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
1673    if (!lookahead.sanitize (c, this)) return TRACE_RETURN (false);
1674    ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1675    return TRACE_RETURN (lookup.sanitize (c));
1676  }
1677
1678  protected:
1679  USHORT	format;			/* Format identifier--format = 3 */
1680  OffsetArrayOf<Coverage>
1681		backtrack;		/* Array of coverage tables
1682					 * in backtracking sequence, in  glyph
1683					 * sequence order */
1684  OffsetArrayOf<Coverage>
1685		inputX		;	/* Array of coverage
1686					 * tables in input sequence, in glyph
1687					 * sequence order */
1688  OffsetArrayOf<Coverage>
1689		lookaheadX;		/* Array of coverage tables
1690					 * in lookahead sequence, in glyph
1691					 * sequence order */
1692  ArrayOf<LookupRecord>
1693		lookupX;		/* Array of LookupRecords--in
1694					 * design order) */
1695  public:
1696  DEFINE_SIZE_MIN (10);
1697};
1698
1699struct ChainContext
1700{
1701  template <typename context_t>
1702  inline typename context_t::return_t process (context_t *c) const
1703  {
1704    switch (u.format) {
1705    case 1: return c->process (u.format1);
1706    case 2: return c->process (u.format2);
1707    case 3: return c->process (u.format3);
1708    default:return c->default_return_value ();
1709    }
1710  }
1711
1712  inline bool sanitize (hb_sanitize_context_t *c) {
1713    TRACE_SANITIZE ();
1714    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
1715    switch (u.format) {
1716    case 1: return TRACE_RETURN (u.format1.sanitize (c));
1717    case 2: return TRACE_RETURN (u.format2.sanitize (c));
1718    case 3: return TRACE_RETURN (u.format3.sanitize (c));
1719    default:return TRACE_RETURN (true);
1720    }
1721  }
1722
1723  protected:
1724  union {
1725  USHORT		format;	/* Format identifier */
1726  ChainContextFormat1	format1;
1727  ChainContextFormat2	format2;
1728  ChainContextFormat3	format3;
1729  } u;
1730};
1731
1732
1733struct ExtensionFormat1
1734{
1735  inline unsigned int get_type (void) const { return extensionLookupType; }
1736  inline unsigned int get_offset (void) const { return extensionOffset; }
1737
1738  inline bool sanitize (hb_sanitize_context_t *c) {
1739    TRACE_SANITIZE ();
1740    return TRACE_RETURN (c->check_struct (this));
1741  }
1742
1743  protected:
1744  USHORT	format;			/* Format identifier. Set to 1. */
1745  USHORT	extensionLookupType;	/* Lookup type of subtable referenced
1746					 * by ExtensionOffset (i.e. the
1747					 * extension subtable). */
1748  ULONG		extensionOffset;	/* Offset to the extension subtable,
1749					 * of lookup type subtable. */
1750  public:
1751  DEFINE_SIZE_STATIC (8);
1752};
1753
1754struct Extension
1755{
1756  inline unsigned int get_type (void) const
1757  {
1758    switch (u.format) {
1759    case 1: return u.format1.get_type ();
1760    default:return 0;
1761    }
1762  }
1763  inline unsigned int get_offset (void) const
1764  {
1765    switch (u.format) {
1766    case 1: return u.format1.get_offset ();
1767    default:return 0;
1768    }
1769  }
1770
1771  inline bool sanitize (hb_sanitize_context_t *c) {
1772    TRACE_SANITIZE ();
1773    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
1774    switch (u.format) {
1775    case 1: return TRACE_RETURN (u.format1.sanitize (c));
1776    default:return TRACE_RETURN (true);
1777    }
1778  }
1779
1780  protected:
1781  union {
1782  USHORT		format;		/* Format identifier */
1783  ExtensionFormat1	format1;
1784  } u;
1785};
1786
1787
1788/*
1789 * GSUB/GPOS Common
1790 */
1791
1792struct GSUBGPOS
1793{
1794  static const hb_tag_t GSUBTag	= HB_OT_TAG_GSUB;
1795  static const hb_tag_t GPOSTag	= HB_OT_TAG_GPOS;
1796
1797  inline unsigned int get_script_count (void) const
1798  { return (this+scriptList).len; }
1799  inline const Tag& get_script_tag (unsigned int i) const
1800  { return (this+scriptList).get_tag (i); }
1801  inline unsigned int get_script_tags (unsigned int start_offset,
1802				       unsigned int *script_count /* IN/OUT */,
1803				       hb_tag_t     *script_tags /* OUT */) const
1804  { return (this+scriptList).get_tags (start_offset, script_count, script_tags); }
1805  inline const Script& get_script (unsigned int i) const
1806  { return (this+scriptList)[i]; }
1807  inline bool find_script_index (hb_tag_t tag, unsigned int *index) const
1808  { return (this+scriptList).find_index (tag, index); }
1809
1810  inline unsigned int get_feature_count (void) const
1811  { return (this+featureList).len; }
1812  inline const Tag& get_feature_tag (unsigned int i) const
1813  { return (this+featureList).get_tag (i); }
1814  inline unsigned int get_feature_tags (unsigned int start_offset,
1815					unsigned int *feature_count /* IN/OUT */,
1816					hb_tag_t     *feature_tags /* OUT */) const
1817  { return (this+featureList).get_tags (start_offset, feature_count, feature_tags); }
1818  inline const Feature& get_feature (unsigned int i) const
1819  { return (this+featureList)[i]; }
1820  inline bool find_feature_index (hb_tag_t tag, unsigned int *index) const
1821  { return (this+featureList).find_index (tag, index); }
1822
1823  inline unsigned int get_lookup_count (void) const
1824  { return (this+lookupList).len; }
1825  inline const Lookup& get_lookup (unsigned int i) const
1826  { return (this+lookupList)[i]; }
1827
1828  inline bool sanitize (hb_sanitize_context_t *c) {
1829    TRACE_SANITIZE ();
1830    return TRACE_RETURN (version.sanitize (c) && likely (version.major == 1) &&
1831			 scriptList.sanitize (c, this) &&
1832			 featureList.sanitize (c, this) &&
1833			 lookupList.sanitize (c, this));
1834  }
1835
1836  protected:
1837  FixedVersion	version;	/* Version of the GSUB/GPOS table--initially set
1838				 * to 0x00010000 */
1839  OffsetTo<ScriptList>
1840		scriptList;  	/* ScriptList table */
1841  OffsetTo<FeatureList>
1842		featureList; 	/* FeatureList table */
1843  OffsetTo<LookupList>
1844		lookupList; 	/* LookupList table */
1845  public:
1846  DEFINE_SIZE_STATIC (10);
1847};
1848
1849
1850} /* namespace OT */
1851
1852
1853#endif /* HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH */
1854