Add git cl format presubmit warning for extension and apps.
[chromium-blink-merge.git] / third_party / harfbuzz-ng / src / hb-ot-layout-gsubgpos-private.hh
blobbdd773e36b9030ff0425c9956722ed225370446f
1 /*
2 * Copyright © 2007,2008,2009,2010 Red Hat, Inc.
3 * Copyright © 2010,2012 Google, Inc.
5 * This is part of HarfBuzz, a text shaping library.
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.
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.
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.
25 * Red Hat Author(s): Behdad Esfahbod
26 * Google Author(s): Behdad Esfahbod
29 #ifndef HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH
30 #define HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH
32 #include "hb-buffer-private.hh"
33 #include "hb-ot-layout-gdef-table.hh"
34 #include "hb-set-private.hh"
37 namespace OT {
41 #define TRACE_DISPATCH(this) \
42 hb_auto_trace_t<context_t::max_debug_depth, typename context_t::return_t> trace \
43 (&c->debug_depth, c->get_name (), this, HB_FUNC, \
44 "");
46 #ifndef HB_DEBUG_CLOSURE
47 #define HB_DEBUG_CLOSURE (HB_DEBUG+0)
48 #endif
50 #define TRACE_CLOSURE(this) \
51 hb_auto_trace_t<HB_DEBUG_CLOSURE, hb_void_t> trace \
52 (&c->debug_depth, c->get_name (), this, HB_FUNC, \
53 "");
55 struct hb_closure_context_t
57 inline const char *get_name (void) { return "CLOSURE"; }
58 static const unsigned int max_debug_depth = HB_DEBUG_CLOSURE;
59 typedef hb_void_t return_t;
60 typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
61 template <typename T>
62 inline return_t dispatch (const T &obj) { obj.closure (this); return HB_VOID; }
63 static return_t default_return_value (void) { return HB_VOID; }
64 bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
65 return_t recurse (unsigned int lookup_index)
67 if (unlikely (nesting_level_left == 0 || !recurse_func))
68 return default_return_value ();
70 nesting_level_left--;
71 recurse_func (this, lookup_index);
72 nesting_level_left++;
73 return HB_VOID;
76 hb_face_t *face;
77 hb_set_t *glyphs;
78 recurse_func_t recurse_func;
79 unsigned int nesting_level_left;
80 unsigned int debug_depth;
82 hb_closure_context_t (hb_face_t *face_,
83 hb_set_t *glyphs_,
84 unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) :
85 face (face_),
86 glyphs (glyphs_),
87 recurse_func (NULL),
88 nesting_level_left (nesting_level_left_),
89 debug_depth (0) {}
91 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
96 #ifndef HB_DEBUG_WOULD_APPLY
97 #define HB_DEBUG_WOULD_APPLY (HB_DEBUG+0)
98 #endif
100 #define TRACE_WOULD_APPLY(this) \
101 hb_auto_trace_t<HB_DEBUG_WOULD_APPLY, bool> trace \
102 (&c->debug_depth, c->get_name (), this, HB_FUNC, \
103 "%d glyphs", c->len);
105 struct hb_would_apply_context_t
107 inline const char *get_name (void) { return "WOULD_APPLY"; }
108 static const unsigned int max_debug_depth = HB_DEBUG_WOULD_APPLY;
109 typedef bool return_t;
110 template <typename T>
111 inline return_t dispatch (const T &obj) { return obj.would_apply (this); }
112 static return_t default_return_value (void) { return false; }
113 bool stop_sublookup_iteration (return_t r) const { return r; }
115 hb_face_t *face;
116 const hb_codepoint_t *glyphs;
117 unsigned int len;
118 bool zero_context;
119 unsigned int debug_depth;
121 hb_would_apply_context_t (hb_face_t *face_,
122 const hb_codepoint_t *glyphs_,
123 unsigned int len_,
124 bool zero_context_) :
125 face (face_),
126 glyphs (glyphs_),
127 len (len_),
128 zero_context (zero_context_),
129 debug_depth (0) {}
134 #ifndef HB_DEBUG_COLLECT_GLYPHS
135 #define HB_DEBUG_COLLECT_GLYPHS (HB_DEBUG+0)
136 #endif
138 #define TRACE_COLLECT_GLYPHS(this) \
139 hb_auto_trace_t<HB_DEBUG_COLLECT_GLYPHS, hb_void_t> trace \
140 (&c->debug_depth, c->get_name (), this, HB_FUNC, \
141 "");
143 struct hb_collect_glyphs_context_t
145 inline const char *get_name (void) { return "COLLECT_GLYPHS"; }
146 static const unsigned int max_debug_depth = HB_DEBUG_COLLECT_GLYPHS;
147 typedef hb_void_t return_t;
148 typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index);
149 template <typename T>
150 inline return_t dispatch (const T &obj) { obj.collect_glyphs (this); return HB_VOID; }
151 static return_t default_return_value (void) { return HB_VOID; }
152 bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
153 return_t recurse (unsigned int lookup_index)
155 if (unlikely (nesting_level_left == 0 || !recurse_func))
156 return default_return_value ();
158 /* Note that GPOS sets recurse_func to NULL already, so it doesn't get
159 * past the previous check. For GSUB, we only want to collect the output
160 * glyphs in the recursion. If output is not requested, we can go home now.
162 * Note further, that the above is not exactly correct. A recursed lookup
163 * is allowed to match input that is not matched in the context, but that's
164 * not how most fonts are built. It's possible to relax that and recurse
165 * with all sets here if it proves to be an issue.
168 if (output == hb_set_get_empty ())
169 return HB_VOID;
171 hb_set_t *old_before = before;
172 hb_set_t *old_input = input;
173 hb_set_t *old_after = after;
174 before = input = after = hb_set_get_empty ();
176 nesting_level_left--;
177 recurse_func (this, lookup_index);
178 nesting_level_left++;
180 before = old_before;
181 input = old_input;
182 after = old_after;
184 return HB_VOID;
187 hb_face_t *face;
188 hb_set_t *before;
189 hb_set_t *input;
190 hb_set_t *after;
191 hb_set_t *output;
192 recurse_func_t recurse_func;
193 unsigned int nesting_level_left;
194 unsigned int debug_depth;
196 hb_collect_glyphs_context_t (hb_face_t *face_,
197 hb_set_t *glyphs_before, /* OUT. May be NULL */
198 hb_set_t *glyphs_input, /* OUT. May be NULL */
199 hb_set_t *glyphs_after, /* OUT. May be NULL */
200 hb_set_t *glyphs_output, /* OUT. May be NULL */
201 unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) :
202 face (face_),
203 before (glyphs_before ? glyphs_before : hb_set_get_empty ()),
204 input (glyphs_input ? glyphs_input : hb_set_get_empty ()),
205 after (glyphs_after ? glyphs_after : hb_set_get_empty ()),
206 output (glyphs_output ? glyphs_output : hb_set_get_empty ()),
207 recurse_func (NULL),
208 nesting_level_left (nesting_level_left_),
209 debug_depth (0) {}
211 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
216 struct hb_get_coverage_context_t
218 inline const char *get_name (void) { return "GET_COVERAGE"; }
219 static const unsigned int max_debug_depth = 0;
220 typedef const Coverage &return_t;
221 template <typename T>
222 inline return_t dispatch (const T &obj) { return obj.get_coverage (); }
223 static return_t default_return_value (void) { return Null(Coverage); }
225 hb_get_coverage_context_t (void) :
226 debug_depth (0) {}
228 unsigned int debug_depth;
233 #ifndef HB_DEBUG_APPLY
234 #define HB_DEBUG_APPLY (HB_DEBUG+0)
235 #endif
237 #define TRACE_APPLY(this) \
238 hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace \
239 (&c->debug_depth, c->get_name (), this, HB_FUNC, \
240 "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);
242 struct hb_apply_context_t
244 inline const char *get_name (void) { return "APPLY"; }
245 static const unsigned int max_debug_depth = HB_DEBUG_APPLY;
246 typedef bool return_t;
247 typedef return_t (*recurse_func_t) (hb_apply_context_t *c, unsigned int lookup_index);
248 template <typename T>
249 inline return_t dispatch (const T &obj) { return obj.apply (this); }
250 static return_t default_return_value (void) { return false; }
251 bool stop_sublookup_iteration (return_t r) const { return r; }
252 return_t recurse (unsigned int lookup_index)
254 if (unlikely (nesting_level_left == 0 || !recurse_func))
255 return default_return_value ();
257 nesting_level_left--;
258 bool ret = recurse_func (this, lookup_index);
259 nesting_level_left++;
260 return ret;
263 unsigned int table_index; /* GSUB/GPOS */
264 hb_font_t *font;
265 hb_face_t *face;
266 hb_buffer_t *buffer;
267 hb_direction_t direction;
268 hb_mask_t lookup_mask;
269 bool auto_zwj;
270 recurse_func_t recurse_func;
271 unsigned int nesting_level_left;
272 unsigned int lookup_props;
273 const GDEF &gdef;
274 bool has_glyph_classes;
275 unsigned int debug_depth;
278 hb_apply_context_t (unsigned int table_index_,
279 hb_font_t *font_,
280 hb_buffer_t *buffer_) :
281 table_index (table_index_),
282 font (font_), face (font->face), buffer (buffer_),
283 direction (buffer_->props.direction),
284 lookup_mask (1),
285 auto_zwj (true),
286 recurse_func (NULL),
287 nesting_level_left (MAX_NESTING_LEVEL),
288 lookup_props (0),
289 gdef (*hb_ot_layout_from_face (face)->gdef),
290 has_glyph_classes (gdef.has_glyph_classes ()),
291 debug_depth (0) {}
293 inline void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; }
294 inline void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; }
295 inline void set_recurse_func (recurse_func_t func) { recurse_func = func; }
296 inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
297 inline void set_lookup (const Lookup &l) { lookup_props = l.get_props (); }
299 struct matcher_t
301 inline matcher_t (void) :
302 lookup_props (0),
303 ignore_zwnj (false),
304 ignore_zwj (false),
305 mask (-1),
306 #define arg1(arg) (arg) /* Remove the macro to see why it's needed! */
307 syllable arg1(0),
308 #undef arg1
309 match_func (NULL),
310 match_data (NULL) {};
312 typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data);
314 inline void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; }
315 inline void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
316 inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
317 inline void set_mask (hb_mask_t mask_) { mask = mask_; }
318 inline void set_syllable (uint8_t syllable_) { syllable = syllable_; }
319 inline void set_match_func (match_func_t match_func_,
320 const void *match_data_)
321 { match_func = match_func_; match_data = match_data_; }
323 enum may_match_t {
324 MATCH_NO,
325 MATCH_YES,
326 MATCH_MAYBE
329 inline may_match_t may_match (const hb_glyph_info_t &info,
330 const USHORT *glyph_data) const
332 if (!(info.mask & mask) ||
333 (syllable && syllable != info.syllable ()))
334 return MATCH_NO;
336 if (match_func)
337 return match_func (info.codepoint, *glyph_data, match_data) ? MATCH_YES : MATCH_NO;
339 return MATCH_MAYBE;
342 enum may_skip_t {
343 SKIP_NO,
344 SKIP_YES,
345 SKIP_MAYBE
348 inline may_skip_t
349 may_skip (const hb_apply_context_t *c,
350 const hb_glyph_info_t &info) const
352 unsigned int property;
354 property = _hb_glyph_info_get_glyph_props (&info);
356 if (!c->match_properties (info.codepoint, property, lookup_props))
357 return SKIP_YES;
359 if (unlikely (_hb_glyph_info_is_default_ignorable (&info) &&
360 (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) &&
361 (ignore_zwj || !_hb_glyph_info_is_zwj (&info)) &&
362 !_hb_glyph_info_ligated (&info)))
363 return SKIP_MAYBE;
365 return SKIP_NO;
368 protected:
369 unsigned int lookup_props;
370 bool ignore_zwnj;
371 bool ignore_zwj;
372 hb_mask_t mask;
373 uint8_t syllable;
374 match_func_t match_func;
375 const void *match_data;
378 struct skipping_forward_iterator_t
380 inline skipping_forward_iterator_t (hb_apply_context_t *c_,
381 unsigned int start_index_,
382 unsigned int num_items_,
383 bool context_match = false) :
384 idx (start_index_),
385 c (c_),
386 match_glyph_data (NULL),
387 num_items (num_items_),
388 end (c->buffer->len)
390 matcher.set_lookup_props (c->lookup_props);
391 /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
392 matcher.set_ignore_zwnj (context_match || c->table_index == 1);
393 /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */
394 matcher.set_ignore_zwj (context_match || c->table_index == 1 || c->auto_zwj);
395 if (!context_match)
396 matcher.set_mask (c->lookup_mask);
397 matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
399 inline void set_lookup_props (unsigned int lookup_props) { matcher.set_lookup_props (lookup_props); }
400 inline void set_syllable (unsigned int syllable) { matcher.set_syllable (syllable); }
401 inline void set_match_func (matcher_t::match_func_t match_func,
402 const void *match_data,
403 const USHORT glyph_data[])
405 matcher.set_match_func (match_func, match_data);
406 match_glyph_data = glyph_data;
409 inline bool has_no_chance (void) const { return unlikely (num_items && idx + num_items >= end); }
410 inline void reject (void) { num_items++; match_glyph_data--; }
411 inline bool next (void)
413 assert (num_items > 0);
414 while (!has_no_chance ())
416 idx++;
417 const hb_glyph_info_t &info = c->buffer->info[idx];
419 matcher_t::may_skip_t skip = matcher.may_skip (c, info);
420 if (unlikely (skip == matcher_t::SKIP_YES))
421 continue;
423 matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
424 if (match == matcher_t::MATCH_YES ||
425 (match == matcher_t::MATCH_MAYBE &&
426 skip == matcher_t::SKIP_NO))
428 num_items--;
429 match_glyph_data++;
430 return true;
433 if (skip == matcher_t::SKIP_NO)
434 return false;
436 return false;
439 unsigned int idx;
440 protected:
441 hb_apply_context_t *c;
442 matcher_t matcher;
443 const USHORT *match_glyph_data;
445 unsigned int num_items;
446 unsigned int end;
449 struct skipping_backward_iterator_t
451 inline skipping_backward_iterator_t (hb_apply_context_t *c_,
452 unsigned int start_index_,
453 unsigned int num_items_,
454 bool context_match = false) :
455 idx (start_index_),
456 c (c_),
457 match_glyph_data (NULL),
458 num_items (num_items_)
460 matcher.set_lookup_props (c->lookup_props);
461 /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
462 matcher.set_ignore_zwnj (context_match || c->table_index == 1);
463 /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */
464 matcher.set_ignore_zwj (context_match || c->table_index == 1 || c->auto_zwj);
465 if (!context_match)
466 matcher.set_mask (c->lookup_mask);
467 matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
469 inline void set_lookup_props (unsigned int lookup_props) { matcher.set_lookup_props (lookup_props); }
470 inline void set_syllable (unsigned int syllable) { matcher.set_syllable (syllable); }
471 inline void set_match_func (matcher_t::match_func_t match_func,
472 const void *match_data,
473 const USHORT glyph_data[])
475 matcher.set_match_func (match_func, match_data);
476 match_glyph_data = glyph_data;
479 inline bool has_no_chance (void) const { return unlikely (idx < num_items); }
480 inline void reject (void) { num_items++; }
481 inline bool prev (void)
483 assert (num_items > 0);
484 while (!has_no_chance ())
486 idx--;
487 const hb_glyph_info_t &info = c->buffer->out_info[idx];
489 matcher_t::may_skip_t skip = matcher.may_skip (c, info);
491 if (unlikely (skip == matcher_t::SKIP_YES))
492 continue;
494 matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
495 if (match == matcher_t::MATCH_YES ||
496 (match == matcher_t::MATCH_MAYBE &&
497 skip == matcher_t::SKIP_NO))
499 num_items--;
500 match_glyph_data++;
501 return true;
504 if (skip == matcher_t::SKIP_NO)
505 return false;
507 return false;
510 unsigned int idx;
511 protected:
512 hb_apply_context_t *c;
513 matcher_t matcher;
514 const USHORT *match_glyph_data;
516 unsigned int num_items;
519 inline bool
520 match_properties_mark (hb_codepoint_t glyph,
521 unsigned int glyph_props,
522 unsigned int lookup_props) const
524 /* If using mark filtering sets, the high short of
525 * lookup_props has the set index.
527 if (lookup_props & LookupFlag::UseMarkFilteringSet)
528 return gdef.mark_set_covers (lookup_props >> 16, glyph);
530 /* The second byte of lookup_props has the meaning
531 * "ignore marks of attachment type different than
532 * the attachment type specified."
534 if (lookup_props & LookupFlag::MarkAttachmentType)
535 return (lookup_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);
537 return true;
540 inline bool
541 match_properties (hb_codepoint_t glyph,
542 unsigned int glyph_props,
543 unsigned int lookup_props) const
545 /* Not covered, if, for example, glyph class is ligature and
546 * lookup_props includes LookupFlags::IgnoreLigatures
548 if (glyph_props & lookup_props & LookupFlag::IgnoreFlags)
549 return false;
551 if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK))
552 return match_properties_mark (glyph, glyph_props, lookup_props);
554 return true;
557 inline bool
558 check_glyph_property (hb_glyph_info_t *info,
559 unsigned int lookup_props) const
561 unsigned int property;
563 property = _hb_glyph_info_get_glyph_props (info);
565 return match_properties (info->codepoint, property, lookup_props);
568 inline void _set_glyph_props (hb_codepoint_t glyph_index,
569 unsigned int class_guess = 0,
570 bool ligature = false) const
572 unsigned int add_in = _hb_glyph_info_get_glyph_props (&buffer->cur()) &
573 HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE;
574 add_in |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED;
575 if (ligature)
576 add_in |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED;
577 if (likely (has_glyph_classes))
578 _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | gdef.get_glyph_props (glyph_index));
579 else if (class_guess)
580 _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | class_guess);
583 inline void replace_glyph (hb_codepoint_t glyph_index) const
585 _set_glyph_props (glyph_index);
586 buffer->replace_glyph (glyph_index);
588 inline void replace_glyph_inplace (hb_codepoint_t glyph_index) const
590 _set_glyph_props (glyph_index);
591 buffer->cur().codepoint = glyph_index;
593 inline void replace_glyph_with_ligature (hb_codepoint_t glyph_index,
594 unsigned int class_guess) const
596 _set_glyph_props (glyph_index, class_guess, true);
597 buffer->replace_glyph (glyph_index);
599 inline void output_glyph (hb_codepoint_t glyph_index,
600 unsigned int class_guess) const
602 _set_glyph_props (glyph_index, class_guess);
603 buffer->output_glyph (glyph_index);
609 typedef bool (*intersects_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data);
610 typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data);
611 typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data);
613 struct ContextClosureFuncs
615 intersects_func_t intersects;
617 struct ContextCollectGlyphsFuncs
619 collect_glyphs_func_t collect;
621 struct ContextApplyFuncs
623 match_func_t match;
627 static inline bool intersects_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED)
629 return glyphs->has (value);
631 static inline bool intersects_class (hb_set_t *glyphs, const USHORT &value, const void *data)
633 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
634 return class_def.intersects_class (glyphs, value);
636 static inline bool intersects_coverage (hb_set_t *glyphs, const USHORT &value, const void *data)
638 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
639 return (data+coverage).intersects (glyphs);
642 static inline bool intersects_array (hb_closure_context_t *c,
643 unsigned int count,
644 const USHORT values[],
645 intersects_func_t intersects_func,
646 const void *intersects_data)
648 for (unsigned int i = 0; i < count; i++)
649 if (likely (!intersects_func (c->glyphs, values[i], intersects_data)))
650 return false;
651 return true;
655 static inline void collect_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED)
657 glyphs->add (value);
659 static inline void collect_class (hb_set_t *glyphs, const USHORT &value, const void *data)
661 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
662 class_def.add_class (glyphs, value);
664 static inline void collect_coverage (hb_set_t *glyphs, const USHORT &value, const void *data)
666 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
667 (data+coverage).add_coverage (glyphs);
669 static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
670 hb_set_t *glyphs,
671 unsigned int count,
672 const USHORT values[],
673 collect_glyphs_func_t collect_func,
674 const void *collect_data)
676 for (unsigned int i = 0; i < count; i++)
677 collect_func (glyphs, values[i], collect_data);
681 static inline bool match_glyph (hb_codepoint_t glyph_id, const USHORT &value, const void *data HB_UNUSED)
683 return glyph_id == value;
685 static inline bool match_class (hb_codepoint_t glyph_id, const USHORT &value, const void *data)
687 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
688 return class_def.get_class (glyph_id) == value;
690 static inline bool match_coverage (hb_codepoint_t glyph_id, const USHORT &value, const void *data)
692 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
693 return (data+coverage).get_coverage (glyph_id) != NOT_COVERED;
696 static inline bool would_match_input (hb_would_apply_context_t *c,
697 unsigned int count, /* Including the first glyph (not matched) */
698 const USHORT input[], /* Array of input values--start with second glyph */
699 match_func_t match_func,
700 const void *match_data)
702 if (count != c->len)
703 return false;
705 for (unsigned int i = 1; i < count; i++)
706 if (likely (!match_func (c->glyphs[i], input[i - 1], match_data)))
707 return false;
709 return true;
711 static inline bool match_input (hb_apply_context_t *c,
712 unsigned int count, /* Including the first glyph (not matched) */
713 const USHORT input[], /* Array of input values--start with second glyph */
714 match_func_t match_func,
715 const void *match_data,
716 unsigned int *end_offset,
717 unsigned int match_positions[MAX_CONTEXT_LENGTH],
718 bool *p_is_mark_ligature = NULL,
719 unsigned int *p_total_component_count = NULL)
721 TRACE_APPLY (NULL);
723 if (unlikely (count > MAX_CONTEXT_LENGTH)) TRACE_RETURN (false);
725 hb_buffer_t *buffer = c->buffer;
727 hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, buffer->idx, count - 1);
728 skippy_iter.set_match_func (match_func, match_data, input);
729 if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
732 * This is perhaps the trickiest part of OpenType... Remarks:
734 * - If all components of the ligature were marks, we call this a mark ligature.
736 * - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize
737 * it as a ligature glyph.
739 * - Ligatures cannot be formed across glyphs attached to different components
740 * of previous ligatures. Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and
741 * LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother.
742 * However, it would be wrong to ligate that SHADDA,FATHA sequence.o
743 * There is an exception to this: If a ligature tries ligating with marks that
744 * belong to it itself, go ahead, assuming that the font designer knows what
745 * they are doing (otherwise it can break Indic stuff when a matra wants to
746 * ligate with a conjunct...)
749 bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->cur());
751 unsigned int total_component_count = 0;
752 total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur());
754 unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
755 unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
757 match_positions[0] = buffer->idx;
758 for (unsigned int i = 1; i < count; i++)
760 if (!skippy_iter.next ()) return TRACE_RETURN (false);
762 match_positions[i] = skippy_iter.idx;
764 unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]);
765 unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]);
767 if (first_lig_id && first_lig_comp) {
768 /* If first component was attached to a previous ligature component,
769 * all subsequent components should be attached to the same ligature
770 * component, otherwise we shouldn't ligate them. */
771 if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
772 return TRACE_RETURN (false);
773 } else {
774 /* If first component was NOT attached to a previous ligature component,
775 * all subsequent components should also NOT be attached to any ligature
776 * component, unless they are attached to the first component itself! */
777 if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id))
778 return TRACE_RETURN (false);
781 is_mark_ligature = is_mark_ligature && _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx]);
782 total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]);
785 *end_offset = skippy_iter.idx - buffer->idx + 1;
787 if (p_is_mark_ligature)
788 *p_is_mark_ligature = is_mark_ligature;
790 if (p_total_component_count)
791 *p_total_component_count = total_component_count;
793 return TRACE_RETURN (true);
795 static inline void ligate_input (hb_apply_context_t *c,
796 unsigned int count, /* Including the first glyph */
797 unsigned int match_positions[MAX_CONTEXT_LENGTH], /* Including the first glyph */
798 unsigned int match_length,
799 hb_codepoint_t lig_glyph,
800 bool is_mark_ligature,
801 unsigned int total_component_count)
803 TRACE_APPLY (NULL);
805 hb_buffer_t *buffer = c->buffer;
807 buffer->merge_clusters (buffer->idx, buffer->idx + match_length);
810 * - If it *is* a mark ligature, we don't allocate a new ligature id, and leave
811 * the ligature to keep its old ligature id. This will allow it to attach to
812 * a base ligature in GPOS. Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH,
813 * and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA wit a
814 * ligature id and component value of 2. Then if SHADDA,FATHA form a ligature
815 * later, we don't want them to lose their ligature id/component, otherwise
816 * GPOS will fail to correctly position the mark ligature on top of the
817 * LAM,LAM,HEH ligature. See:
818 * https://bugzilla.gnome.org/show_bug.cgi?id=676343
820 * - If a ligature is formed of components that some of which are also ligatures
821 * themselves, and those ligature components had marks attached to *their*
822 * components, we have to attach the marks to the new ligature component
823 * positions! Now *that*'s tricky! And these marks may be following the
824 * last component of the whole sequence, so we should loop forward looking
825 * for them and update them.
827 * Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a
828 * 'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature
829 * id and component == 1. Now, during 'liga', the LAM and the LAM-HEH ligature
830 * form a LAM-LAM-HEH ligature. We need to reassign the SHADDA and FATHA to
831 * the new ligature with a component value of 2.
833 * This in fact happened to a font... See:
834 * https://bugzilla.gnome.org/show_bug.cgi?id=437633
837 unsigned int klass = is_mark_ligature ? 0 : HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
838 unsigned int lig_id = is_mark_ligature ? 0 : _hb_allocate_lig_id (buffer);
839 unsigned int last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
840 unsigned int last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
841 unsigned int components_so_far = last_num_components;
843 if (!is_mark_ligature)
845 _hb_glyph_info_set_lig_props_for_ligature (&buffer->cur(), lig_id, total_component_count);
846 if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
848 _hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER);
849 _hb_glyph_info_set_modified_combining_class (&buffer->cur(), 0);
852 c->replace_glyph_with_ligature (lig_glyph, klass);
854 for (unsigned int i = 1; i < count; i++)
856 while (buffer->idx < match_positions[i])
858 if (!is_mark_ligature) {
859 unsigned int new_lig_comp = components_so_far - last_num_components +
860 MIN (MAX (_hb_glyph_info_get_lig_comp (&buffer->cur()), 1u), last_num_components);
861 _hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
863 buffer->next_glyph ();
866 last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
867 last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
868 components_so_far += last_num_components;
870 /* Skip the base glyph */
871 buffer->idx++;
874 if (!is_mark_ligature && last_lig_id) {
875 /* Re-adjust components for any marks following. */
876 for (unsigned int i = buffer->idx; i < buffer->len; i++) {
877 if (last_lig_id == _hb_glyph_info_get_lig_id (&buffer->info[i])) {
878 unsigned int new_lig_comp = components_so_far - last_num_components +
879 MIN (MAX (_hb_glyph_info_get_lig_comp (&buffer->info[i]), 1u), last_num_components);
880 _hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
881 } else
882 break;
887 static inline bool match_backtrack (hb_apply_context_t *c,
888 unsigned int count,
889 const USHORT backtrack[],
890 match_func_t match_func,
891 const void *match_data)
893 TRACE_APPLY (NULL);
895 hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, c->buffer->backtrack_len (), count, true);
896 skippy_iter.set_match_func (match_func, match_data, backtrack);
897 if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
899 for (unsigned int i = 0; i < count; i++)
900 if (!skippy_iter.prev ())
901 return TRACE_RETURN (false);
903 return TRACE_RETURN (true);
906 static inline bool match_lookahead (hb_apply_context_t *c,
907 unsigned int count,
908 const USHORT lookahead[],
909 match_func_t match_func,
910 const void *match_data,
911 unsigned int offset)
913 TRACE_APPLY (NULL);
915 hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx + offset - 1, count, true);
916 skippy_iter.set_match_func (match_func, match_data, lookahead);
917 if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
919 for (unsigned int i = 0; i < count; i++)
920 if (!skippy_iter.next ())
921 return TRACE_RETURN (false);
923 return TRACE_RETURN (true);
928 struct LookupRecord
930 inline bool sanitize (hb_sanitize_context_t *c) {
931 TRACE_SANITIZE (this);
932 return TRACE_RETURN (c->check_struct (this));
935 USHORT sequenceIndex; /* Index into current glyph
936 * sequence--first glyph = 0 */
937 USHORT lookupListIndex; /* Lookup to apply to that
938 * position--zero--based */
939 public:
940 DEFINE_SIZE_STATIC (4);
944 template <typename context_t>
945 static inline void recurse_lookups (context_t *c,
946 unsigned int lookupCount,
947 const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
949 for (unsigned int i = 0; i < lookupCount; i++)
950 c->recurse (lookupRecord[i].lookupListIndex);
953 static inline bool apply_lookup (hb_apply_context_t *c,
954 unsigned int count, /* Including the first glyph */
955 unsigned int match_positions[MAX_CONTEXT_LENGTH], /* Including the first glyph */
956 unsigned int lookupCount,
957 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
958 unsigned int match_length)
960 TRACE_APPLY (NULL);
962 hb_buffer_t *buffer = c->buffer;
963 unsigned int end;
965 /* All positions are distance from beginning of *output* buffer.
966 * Adjust. */
968 unsigned int bl = buffer->backtrack_len ();
969 end = bl + match_length;
971 int delta = bl - buffer->idx;
972 /* Convert positions to new indexing. */
973 for (unsigned int j = 0; j < count; j++)
974 match_positions[j] += delta;
977 for (unsigned int i = 0; i < lookupCount; i++)
979 unsigned int idx = lookupRecord[i].sequenceIndex;
980 if (idx >= count)
981 continue;
983 buffer->move_to (match_positions[idx]);
985 unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
986 if (!c->recurse (lookupRecord[i].lookupListIndex))
987 continue;
989 unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len ();
990 int delta = new_len - orig_len;
992 if (!delta)
993 continue;
995 /* Recursed lookup changed buffer len. Adjust. */
997 /* end can't go back past the current match position. */
998 end = MAX ((int) match_positions[idx] + 1, int (end) + delta);
1000 unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */
1002 if (delta > 0)
1004 if (unlikely (delta + count > MAX_CONTEXT_LENGTH))
1005 break;
1007 else
1009 /* NOTE: delta is negative. */
1010 delta = MAX (delta, (int) next - (int) count);
1011 next -= delta;
1014 /* Shift! */
1015 memmove (match_positions + next + delta, match_positions + next,
1016 (count - next) * sizeof (match_positions[0]));
1017 next += delta;
1018 count += delta;
1020 /* Fill in new entries. */
1021 for (unsigned int j = idx + 1; j < next; j++)
1022 match_positions[j] = match_positions[j - 1] + 1;
1024 /* And fixup the rest. */
1025 for (; next < count; next++)
1026 match_positions[next] += delta;
1029 buffer->move_to (end);
1031 return TRACE_RETURN (true);
1036 /* Contextual lookups */
1038 struct ContextClosureLookupContext
1040 ContextClosureFuncs funcs;
1041 const void *intersects_data;
1044 struct ContextCollectGlyphsLookupContext
1046 ContextCollectGlyphsFuncs funcs;
1047 const void *collect_data;
1050 struct ContextApplyLookupContext
1052 ContextApplyFuncs funcs;
1053 const void *match_data;
1056 static inline void context_closure_lookup (hb_closure_context_t *c,
1057 unsigned int inputCount, /* Including the first glyph (not matched) */
1058 const USHORT input[], /* Array of input values--start with second glyph */
1059 unsigned int lookupCount,
1060 const LookupRecord lookupRecord[],
1061 ContextClosureLookupContext &lookup_context)
1063 if (intersects_array (c,
1064 inputCount ? inputCount - 1 : 0, input,
1065 lookup_context.funcs.intersects, lookup_context.intersects_data))
1066 recurse_lookups (c,
1067 lookupCount, lookupRecord);
1070 static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
1071 unsigned int inputCount, /* Including the first glyph (not matched) */
1072 const USHORT input[], /* Array of input values--start with second glyph */
1073 unsigned int lookupCount,
1074 const LookupRecord lookupRecord[],
1075 ContextCollectGlyphsLookupContext &lookup_context)
1077 collect_array (c, c->input,
1078 inputCount ? inputCount - 1 : 0, input,
1079 lookup_context.funcs.collect, lookup_context.collect_data);
1080 recurse_lookups (c,
1081 lookupCount, lookupRecord);
1084 static inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
1085 unsigned int inputCount, /* Including the first glyph (not matched) */
1086 const USHORT input[], /* Array of input values--start with second glyph */
1087 unsigned int lookupCount HB_UNUSED,
1088 const LookupRecord lookupRecord[] HB_UNUSED,
1089 ContextApplyLookupContext &lookup_context)
1091 return would_match_input (c,
1092 inputCount, input,
1093 lookup_context.funcs.match, lookup_context.match_data);
1095 static inline bool context_apply_lookup (hb_apply_context_t *c,
1096 unsigned int inputCount, /* Including the first glyph (not matched) */
1097 const USHORT input[], /* Array of input values--start with second glyph */
1098 unsigned int lookupCount,
1099 const LookupRecord lookupRecord[],
1100 ContextApplyLookupContext &lookup_context)
1102 unsigned int match_length = 0;
1103 unsigned int match_positions[MAX_CONTEXT_LENGTH];
1104 return match_input (c,
1105 inputCount, input,
1106 lookup_context.funcs.match, lookup_context.match_data,
1107 &match_length, match_positions)
1108 && apply_lookup (c,
1109 inputCount, match_positions,
1110 lookupCount, lookupRecord,
1111 match_length);
1114 struct Rule
1116 inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
1118 TRACE_CLOSURE (this);
1119 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
1120 context_closure_lookup (c,
1121 inputCount, input,
1122 lookupCount, lookupRecord,
1123 lookup_context);
1126 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const
1128 TRACE_COLLECT_GLYPHS (this);
1129 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
1130 context_collect_glyphs_lookup (c,
1131 inputCount, input,
1132 lookupCount, lookupRecord,
1133 lookup_context);
1136 inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
1138 TRACE_WOULD_APPLY (this);
1139 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
1140 return TRACE_RETURN (context_would_apply_lookup (c, inputCount, input, lookupCount, lookupRecord, lookup_context));
1143 inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
1145 TRACE_APPLY (this);
1146 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
1147 return TRACE_RETURN (context_apply_lookup (c, inputCount, input, lookupCount, lookupRecord, lookup_context));
1150 public:
1151 inline bool sanitize (hb_sanitize_context_t *c) {
1152 TRACE_SANITIZE (this);
1153 return inputCount.sanitize (c)
1154 && lookupCount.sanitize (c)
1155 && c->check_range (input,
1156 input[0].static_size * inputCount
1157 + lookupRecordX[0].static_size * lookupCount);
1160 protected:
1161 USHORT inputCount; /* Total number of glyphs in input
1162 * glyph sequence--includes the first
1163 * glyph */
1164 USHORT lookupCount; /* Number of LookupRecords */
1165 USHORT input[VAR]; /* Array of match inputs--start with
1166 * second glyph */
1167 LookupRecord lookupRecordX[VAR]; /* Array of LookupRecords--in
1168 * design order */
1169 public:
1170 DEFINE_SIZE_ARRAY2 (4, input, lookupRecordX);
1173 struct RuleSet
1175 inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
1177 TRACE_CLOSURE (this);
1178 unsigned int num_rules = rule.len;
1179 for (unsigned int i = 0; i < num_rules; i++)
1180 (this+rule[i]).closure (c, lookup_context);
1183 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const
1185 TRACE_COLLECT_GLYPHS (this);
1186 unsigned int num_rules = rule.len;
1187 for (unsigned int i = 0; i < num_rules; i++)
1188 (this+rule[i]).collect_glyphs (c, lookup_context);
1191 inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
1193 TRACE_WOULD_APPLY (this);
1194 unsigned int num_rules = rule.len;
1195 for (unsigned int i = 0; i < num_rules; i++)
1197 if ((this+rule[i]).would_apply (c, lookup_context))
1198 return TRACE_RETURN (true);
1200 return TRACE_RETURN (false);
1203 inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
1205 TRACE_APPLY (this);
1206 unsigned int num_rules = rule.len;
1207 for (unsigned int i = 0; i < num_rules; i++)
1209 if ((this+rule[i]).apply (c, lookup_context))
1210 return TRACE_RETURN (true);
1212 return TRACE_RETURN (false);
1215 inline bool sanitize (hb_sanitize_context_t *c) {
1216 TRACE_SANITIZE (this);
1217 return TRACE_RETURN (rule.sanitize (c, this));
1220 protected:
1221 OffsetArrayOf<Rule>
1222 rule; /* Array of Rule tables
1223 * ordered by preference */
1224 public:
1225 DEFINE_SIZE_ARRAY (2, rule);
1229 struct ContextFormat1
1231 inline void closure (hb_closure_context_t *c) const
1233 TRACE_CLOSURE (this);
1235 const Coverage &cov = (this+coverage);
1237 struct ContextClosureLookupContext lookup_context = {
1238 {intersects_glyph},
1239 NULL
1242 unsigned int count = ruleSet.len;
1243 for (unsigned int i = 0; i < count; i++)
1244 if (cov.intersects_coverage (c->glyphs, i)) {
1245 const RuleSet &rule_set = this+ruleSet[i];
1246 rule_set.closure (c, lookup_context);
1250 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1252 TRACE_COLLECT_GLYPHS (this);
1253 (this+coverage).add_coverage (c->input);
1255 struct ContextCollectGlyphsLookupContext lookup_context = {
1256 {collect_glyph},
1257 NULL
1260 unsigned int count = ruleSet.len;
1261 for (unsigned int i = 0; i < count; i++)
1262 (this+ruleSet[i]).collect_glyphs (c, lookup_context);
1265 inline bool would_apply (hb_would_apply_context_t *c) const
1267 TRACE_WOULD_APPLY (this);
1269 const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
1270 struct ContextApplyLookupContext lookup_context = {
1271 {match_glyph},
1272 NULL
1274 return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
1277 inline const Coverage &get_coverage (void) const
1279 return this+coverage;
1282 inline bool apply (hb_apply_context_t *c) const
1284 TRACE_APPLY (this);
1285 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
1286 if (likely (index == NOT_COVERED))
1287 return TRACE_RETURN (false);
1289 const RuleSet &rule_set = this+ruleSet[index];
1290 struct ContextApplyLookupContext lookup_context = {
1291 {match_glyph},
1292 NULL
1294 return TRACE_RETURN (rule_set.apply (c, lookup_context));
1297 inline bool sanitize (hb_sanitize_context_t *c) {
1298 TRACE_SANITIZE (this);
1299 return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
1302 protected:
1303 USHORT format; /* Format identifier--format = 1 */
1304 OffsetTo<Coverage>
1305 coverage; /* Offset to Coverage table--from
1306 * beginning of table */
1307 OffsetArrayOf<RuleSet>
1308 ruleSet; /* Array of RuleSet tables
1309 * ordered by Coverage Index */
1310 public:
1311 DEFINE_SIZE_ARRAY (6, ruleSet);
1315 struct ContextFormat2
1317 inline void closure (hb_closure_context_t *c) const
1319 TRACE_CLOSURE (this);
1320 if (!(this+coverage).intersects (c->glyphs))
1321 return;
1323 const ClassDef &class_def = this+classDef;
1325 struct ContextClosureLookupContext lookup_context = {
1326 {intersects_class},
1327 &class_def
1330 unsigned int count = ruleSet.len;
1331 for (unsigned int i = 0; i < count; i++)
1332 if (class_def.intersects_class (c->glyphs, i)) {
1333 const RuleSet &rule_set = this+ruleSet[i];
1334 rule_set.closure (c, lookup_context);
1338 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1340 TRACE_COLLECT_GLYPHS (this);
1341 (this+coverage).add_coverage (c->input);
1343 const ClassDef &class_def = this+classDef;
1344 struct ContextCollectGlyphsLookupContext lookup_context = {
1345 {collect_class},
1346 &class_def
1349 unsigned int count = ruleSet.len;
1350 for (unsigned int i = 0; i < count; i++)
1351 (this+ruleSet[i]).collect_glyphs (c, lookup_context);
1354 inline bool would_apply (hb_would_apply_context_t *c) const
1356 TRACE_WOULD_APPLY (this);
1358 const ClassDef &class_def = this+classDef;
1359 unsigned int index = class_def.get_class (c->glyphs[0]);
1360 const RuleSet &rule_set = this+ruleSet[index];
1361 struct ContextApplyLookupContext lookup_context = {
1362 {match_class},
1363 &class_def
1365 return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
1368 inline const Coverage &get_coverage (void) const
1370 return this+coverage;
1373 inline bool apply (hb_apply_context_t *c) const
1375 TRACE_APPLY (this);
1376 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
1377 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
1379 const ClassDef &class_def = this+classDef;
1380 index = class_def.get_class (c->buffer->cur().codepoint);
1381 const RuleSet &rule_set = this+ruleSet[index];
1382 struct ContextApplyLookupContext lookup_context = {
1383 {match_class},
1384 &class_def
1386 return TRACE_RETURN (rule_set.apply (c, lookup_context));
1389 inline bool sanitize (hb_sanitize_context_t *c) {
1390 TRACE_SANITIZE (this);
1391 return TRACE_RETURN (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
1394 protected:
1395 USHORT format; /* Format identifier--format = 2 */
1396 OffsetTo<Coverage>
1397 coverage; /* Offset to Coverage table--from
1398 * beginning of table */
1399 OffsetTo<ClassDef>
1400 classDef; /* Offset to glyph ClassDef table--from
1401 * beginning of table */
1402 OffsetArrayOf<RuleSet>
1403 ruleSet; /* Array of RuleSet tables
1404 * ordered by class */
1405 public:
1406 DEFINE_SIZE_ARRAY (8, ruleSet);
1410 struct ContextFormat3
1412 inline void closure (hb_closure_context_t *c) const
1414 TRACE_CLOSURE (this);
1415 if (!(this+coverage[0]).intersects (c->glyphs))
1416 return;
1418 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
1419 struct ContextClosureLookupContext lookup_context = {
1420 {intersects_coverage},
1421 this
1423 context_closure_lookup (c,
1424 glyphCount, (const USHORT *) (coverage + 1),
1425 lookupCount, lookupRecord,
1426 lookup_context);
1429 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1431 TRACE_COLLECT_GLYPHS (this);
1432 (this+coverage[0]).add_coverage (c->input);
1434 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
1435 struct ContextCollectGlyphsLookupContext lookup_context = {
1436 {collect_coverage},
1437 this
1440 context_collect_glyphs_lookup (c,
1441 glyphCount, (const USHORT *) (coverage + 1),
1442 lookupCount, lookupRecord,
1443 lookup_context);
1446 inline bool would_apply (hb_would_apply_context_t *c) const
1448 TRACE_WOULD_APPLY (this);
1450 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
1451 struct ContextApplyLookupContext lookup_context = {
1452 {match_coverage},
1453 this
1455 return TRACE_RETURN (context_would_apply_lookup (c, glyphCount, (const USHORT *) (coverage + 1), lookupCount, lookupRecord, lookup_context));
1458 inline const Coverage &get_coverage (void) const
1460 return this+coverage[0];
1463 inline bool apply (hb_apply_context_t *c) const
1465 TRACE_APPLY (this);
1466 unsigned int index = (this+coverage[0]).get_coverage (c->buffer->cur().codepoint);
1467 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
1469 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
1470 struct ContextApplyLookupContext lookup_context = {
1471 {match_coverage},
1472 this
1474 return TRACE_RETURN (context_apply_lookup (c, glyphCount, (const USHORT *) (coverage + 1), lookupCount, lookupRecord, lookup_context));
1477 inline bool sanitize (hb_sanitize_context_t *c) {
1478 TRACE_SANITIZE (this);
1479 if (!c->check_struct (this)) return TRACE_RETURN (false);
1480 unsigned int count = glyphCount;
1481 if (!c->check_array (coverage, coverage[0].static_size, count)) return TRACE_RETURN (false);
1482 for (unsigned int i = 0; i < count; i++)
1483 if (!coverage[i].sanitize (c, this)) return TRACE_RETURN (false);
1484 LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * count);
1485 return TRACE_RETURN (c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount));
1488 protected:
1489 USHORT format; /* Format identifier--format = 3 */
1490 USHORT glyphCount; /* Number of glyphs in the input glyph
1491 * sequence */
1492 USHORT lookupCount; /* Number of LookupRecords */
1493 OffsetTo<Coverage>
1494 coverage[VAR]; /* Array of offsets to Coverage
1495 * table in glyph sequence order */
1496 LookupRecord lookupRecordX[VAR]; /* Array of LookupRecords--in
1497 * design order */
1498 public:
1499 DEFINE_SIZE_ARRAY2 (6, coverage, lookupRecordX);
1502 struct Context
1504 template <typename context_t>
1505 inline typename context_t::return_t dispatch (context_t *c) const
1507 TRACE_DISPATCH (this);
1508 switch (u.format) {
1509 case 1: return TRACE_RETURN (c->dispatch (u.format1));
1510 case 2: return TRACE_RETURN (c->dispatch (u.format2));
1511 case 3: return TRACE_RETURN (c->dispatch (u.format3));
1512 default:return TRACE_RETURN (c->default_return_value ());
1516 inline bool sanitize (hb_sanitize_context_t *c) {
1517 TRACE_SANITIZE (this);
1518 if (!u.format.sanitize (c)) return TRACE_RETURN (false);
1519 switch (u.format) {
1520 case 1: return TRACE_RETURN (u.format1.sanitize (c));
1521 case 2: return TRACE_RETURN (u.format2.sanitize (c));
1522 case 3: return TRACE_RETURN (u.format3.sanitize (c));
1523 default:return TRACE_RETURN (true);
1527 protected:
1528 union {
1529 USHORT format; /* Format identifier */
1530 ContextFormat1 format1;
1531 ContextFormat2 format2;
1532 ContextFormat3 format3;
1533 } u;
1537 /* Chaining Contextual lookups */
1539 struct ChainContextClosureLookupContext
1541 ContextClosureFuncs funcs;
1542 const void *intersects_data[3];
1545 struct ChainContextCollectGlyphsLookupContext
1547 ContextCollectGlyphsFuncs funcs;
1548 const void *collect_data[3];
1551 struct ChainContextApplyLookupContext
1553 ContextApplyFuncs funcs;
1554 const void *match_data[3];
1557 static inline void chain_context_closure_lookup (hb_closure_context_t *c,
1558 unsigned int backtrackCount,
1559 const USHORT backtrack[],
1560 unsigned int inputCount, /* Including the first glyph (not matched) */
1561 const USHORT input[], /* Array of input values--start with second glyph */
1562 unsigned int lookaheadCount,
1563 const USHORT lookahead[],
1564 unsigned int lookupCount,
1565 const LookupRecord lookupRecord[],
1566 ChainContextClosureLookupContext &lookup_context)
1568 if (intersects_array (c,
1569 backtrackCount, backtrack,
1570 lookup_context.funcs.intersects, lookup_context.intersects_data[0])
1571 && intersects_array (c,
1572 inputCount ? inputCount - 1 : 0, input,
1573 lookup_context.funcs.intersects, lookup_context.intersects_data[1])
1574 && intersects_array (c,
1575 lookaheadCount, lookahead,
1576 lookup_context.funcs.intersects, lookup_context.intersects_data[2]))
1577 recurse_lookups (c,
1578 lookupCount, lookupRecord);
1581 static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
1582 unsigned int backtrackCount,
1583 const USHORT backtrack[],
1584 unsigned int inputCount, /* Including the first glyph (not matched) */
1585 const USHORT input[], /* Array of input values--start with second glyph */
1586 unsigned int lookaheadCount,
1587 const USHORT lookahead[],
1588 unsigned int lookupCount,
1589 const LookupRecord lookupRecord[],
1590 ChainContextCollectGlyphsLookupContext &lookup_context)
1592 collect_array (c, c->before,
1593 backtrackCount, backtrack,
1594 lookup_context.funcs.collect, lookup_context.collect_data[0]);
1595 collect_array (c, c->input,
1596 inputCount ? inputCount - 1 : 0, input,
1597 lookup_context.funcs.collect, lookup_context.collect_data[1]);
1598 collect_array (c, c->after,
1599 lookaheadCount, lookahead,
1600 lookup_context.funcs.collect, lookup_context.collect_data[2]);
1601 recurse_lookups (c,
1602 lookupCount, lookupRecord);
1605 static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c,
1606 unsigned int backtrackCount,
1607 const USHORT backtrack[] HB_UNUSED,
1608 unsigned int inputCount, /* Including the first glyph (not matched) */
1609 const USHORT input[], /* Array of input values--start with second glyph */
1610 unsigned int lookaheadCount,
1611 const USHORT lookahead[] HB_UNUSED,
1612 unsigned int lookupCount HB_UNUSED,
1613 const LookupRecord lookupRecord[] HB_UNUSED,
1614 ChainContextApplyLookupContext &lookup_context)
1616 return (c->zero_context ? !backtrackCount && !lookaheadCount : true)
1617 && would_match_input (c,
1618 inputCount, input,
1619 lookup_context.funcs.match, lookup_context.match_data[1]);
1622 static inline bool chain_context_apply_lookup (hb_apply_context_t *c,
1623 unsigned int backtrackCount,
1624 const USHORT backtrack[],
1625 unsigned int inputCount, /* Including the first glyph (not matched) */
1626 const USHORT input[], /* Array of input values--start with second glyph */
1627 unsigned int lookaheadCount,
1628 const USHORT lookahead[],
1629 unsigned int lookupCount,
1630 const LookupRecord lookupRecord[],
1631 ChainContextApplyLookupContext &lookup_context)
1633 unsigned int match_length = 0;
1634 unsigned int match_positions[MAX_CONTEXT_LENGTH];
1635 return match_input (c,
1636 inputCount, input,
1637 lookup_context.funcs.match, lookup_context.match_data[1],
1638 &match_length, match_positions)
1639 && match_backtrack (c,
1640 backtrackCount, backtrack,
1641 lookup_context.funcs.match, lookup_context.match_data[0])
1642 && match_lookahead (c,
1643 lookaheadCount, lookahead,
1644 lookup_context.funcs.match, lookup_context.match_data[2],
1645 match_length)
1646 && apply_lookup (c,
1647 inputCount, match_positions,
1648 lookupCount, lookupRecord,
1649 match_length);
1652 struct ChainRule
1654 inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
1656 TRACE_CLOSURE (this);
1657 const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
1658 const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
1659 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1660 chain_context_closure_lookup (c,
1661 backtrack.len, backtrack.array,
1662 input.len, input.array,
1663 lookahead.len, lookahead.array,
1664 lookup.len, lookup.array,
1665 lookup_context);
1668 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
1670 TRACE_COLLECT_GLYPHS (this);
1671 const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
1672 const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
1673 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1674 chain_context_collect_glyphs_lookup (c,
1675 backtrack.len, backtrack.array,
1676 input.len, input.array,
1677 lookahead.len, lookahead.array,
1678 lookup.len, lookup.array,
1679 lookup_context);
1682 inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
1684 TRACE_WOULD_APPLY (this);
1685 const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
1686 const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
1687 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1688 return TRACE_RETURN (chain_context_would_apply_lookup (c,
1689 backtrack.len, backtrack.array,
1690 input.len, input.array,
1691 lookahead.len, lookahead.array, lookup.len,
1692 lookup.array, lookup_context));
1695 inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
1697 TRACE_APPLY (this);
1698 const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
1699 const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
1700 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1701 return TRACE_RETURN (chain_context_apply_lookup (c,
1702 backtrack.len, backtrack.array,
1703 input.len, input.array,
1704 lookahead.len, lookahead.array, lookup.len,
1705 lookup.array, lookup_context));
1708 inline bool sanitize (hb_sanitize_context_t *c) {
1709 TRACE_SANITIZE (this);
1710 if (!backtrack.sanitize (c)) return TRACE_RETURN (false);
1711 HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
1712 if (!input.sanitize (c)) return TRACE_RETURN (false);
1713 ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
1714 if (!lookahead.sanitize (c)) return TRACE_RETURN (false);
1715 ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1716 return TRACE_RETURN (lookup.sanitize (c));
1719 protected:
1720 ArrayOf<USHORT>
1721 backtrack; /* Array of backtracking values
1722 * (to be matched before the input
1723 * sequence) */
1724 HeadlessArrayOf<USHORT>
1725 inputX; /* Array of input values (start with
1726 * second glyph) */
1727 ArrayOf<USHORT>
1728 lookaheadX; /* Array of lookahead values's (to be
1729 * matched after the input sequence) */
1730 ArrayOf<LookupRecord>
1731 lookupX; /* Array of LookupRecords--in
1732 * design order) */
1733 public:
1734 DEFINE_SIZE_MIN (8);
1737 struct ChainRuleSet
1739 inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
1741 TRACE_CLOSURE (this);
1742 unsigned int num_rules = rule.len;
1743 for (unsigned int i = 0; i < num_rules; i++)
1744 (this+rule[i]).closure (c, lookup_context);
1747 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
1749 TRACE_COLLECT_GLYPHS (this);
1750 unsigned int num_rules = rule.len;
1751 for (unsigned int i = 0; i < num_rules; i++)
1752 (this+rule[i]).collect_glyphs (c, lookup_context);
1755 inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
1757 TRACE_WOULD_APPLY (this);
1758 unsigned int num_rules = rule.len;
1759 for (unsigned int i = 0; i < num_rules; i++)
1760 if ((this+rule[i]).would_apply (c, lookup_context))
1761 return TRACE_RETURN (true);
1763 return TRACE_RETURN (false);
1766 inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
1768 TRACE_APPLY (this);
1769 unsigned int num_rules = rule.len;
1770 for (unsigned int i = 0; i < num_rules; i++)
1771 if ((this+rule[i]).apply (c, lookup_context))
1772 return TRACE_RETURN (true);
1774 return TRACE_RETURN (false);
1777 inline bool sanitize (hb_sanitize_context_t *c) {
1778 TRACE_SANITIZE (this);
1779 return TRACE_RETURN (rule.sanitize (c, this));
1782 protected:
1783 OffsetArrayOf<ChainRule>
1784 rule; /* Array of ChainRule tables
1785 * ordered by preference */
1786 public:
1787 DEFINE_SIZE_ARRAY (2, rule);
1790 struct ChainContextFormat1
1792 inline void closure (hb_closure_context_t *c) const
1794 TRACE_CLOSURE (this);
1795 const Coverage &cov = (this+coverage);
1797 struct ChainContextClosureLookupContext lookup_context = {
1798 {intersects_glyph},
1799 {NULL, NULL, NULL}
1802 unsigned int count = ruleSet.len;
1803 for (unsigned int i = 0; i < count; i++)
1804 if (cov.intersects_coverage (c->glyphs, i)) {
1805 const ChainRuleSet &rule_set = this+ruleSet[i];
1806 rule_set.closure (c, lookup_context);
1810 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1812 TRACE_COLLECT_GLYPHS (this);
1813 (this+coverage).add_coverage (c->input);
1815 struct ChainContextCollectGlyphsLookupContext lookup_context = {
1816 {collect_glyph},
1817 {NULL, NULL, NULL}
1820 unsigned int count = ruleSet.len;
1821 for (unsigned int i = 0; i < count; i++)
1822 (this+ruleSet[i]).collect_glyphs (c, lookup_context);
1825 inline bool would_apply (hb_would_apply_context_t *c) const
1827 TRACE_WOULD_APPLY (this);
1829 const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
1830 struct ChainContextApplyLookupContext lookup_context = {
1831 {match_glyph},
1832 {NULL, NULL, NULL}
1834 return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
1837 inline const Coverage &get_coverage (void) const
1839 return this+coverage;
1842 inline bool apply (hb_apply_context_t *c) const
1844 TRACE_APPLY (this);
1845 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
1846 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
1848 const ChainRuleSet &rule_set = this+ruleSet[index];
1849 struct ChainContextApplyLookupContext lookup_context = {
1850 {match_glyph},
1851 {NULL, NULL, NULL}
1853 return TRACE_RETURN (rule_set.apply (c, lookup_context));
1856 inline bool sanitize (hb_sanitize_context_t *c) {
1857 TRACE_SANITIZE (this);
1858 return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
1861 protected:
1862 USHORT format; /* Format identifier--format = 1 */
1863 OffsetTo<Coverage>
1864 coverage; /* Offset to Coverage table--from
1865 * beginning of table */
1866 OffsetArrayOf<ChainRuleSet>
1867 ruleSet; /* Array of ChainRuleSet tables
1868 * ordered by Coverage Index */
1869 public:
1870 DEFINE_SIZE_ARRAY (6, ruleSet);
1873 struct ChainContextFormat2
1875 inline void closure (hb_closure_context_t *c) const
1877 TRACE_CLOSURE (this);
1878 if (!(this+coverage).intersects (c->glyphs))
1879 return;
1881 const ClassDef &backtrack_class_def = this+backtrackClassDef;
1882 const ClassDef &input_class_def = this+inputClassDef;
1883 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
1885 struct ChainContextClosureLookupContext lookup_context = {
1886 {intersects_class},
1887 {&backtrack_class_def,
1888 &input_class_def,
1889 &lookahead_class_def}
1892 unsigned int count = ruleSet.len;
1893 for (unsigned int i = 0; i < count; i++)
1894 if (input_class_def.intersects_class (c->glyphs, i)) {
1895 const ChainRuleSet &rule_set = this+ruleSet[i];
1896 rule_set.closure (c, lookup_context);
1900 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1902 TRACE_COLLECT_GLYPHS (this);
1903 (this+coverage).add_coverage (c->input);
1905 const ClassDef &backtrack_class_def = this+backtrackClassDef;
1906 const ClassDef &input_class_def = this+inputClassDef;
1907 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
1909 struct ChainContextCollectGlyphsLookupContext lookup_context = {
1910 {collect_class},
1911 {&backtrack_class_def,
1912 &input_class_def,
1913 &lookahead_class_def}
1916 unsigned int count = ruleSet.len;
1917 for (unsigned int i = 0; i < count; i++)
1918 (this+ruleSet[i]).collect_glyphs (c, lookup_context);
1921 inline bool would_apply (hb_would_apply_context_t *c) const
1923 TRACE_WOULD_APPLY (this);
1925 const ClassDef &backtrack_class_def = this+backtrackClassDef;
1926 const ClassDef &input_class_def = this+inputClassDef;
1927 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
1929 unsigned int index = input_class_def.get_class (c->glyphs[0]);
1930 const ChainRuleSet &rule_set = this+ruleSet[index];
1931 struct ChainContextApplyLookupContext lookup_context = {
1932 {match_class},
1933 {&backtrack_class_def,
1934 &input_class_def,
1935 &lookahead_class_def}
1937 return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
1940 inline const Coverage &get_coverage (void) const
1942 return this+coverage;
1945 inline bool apply (hb_apply_context_t *c) const
1947 TRACE_APPLY (this);
1948 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
1949 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
1951 const ClassDef &backtrack_class_def = this+backtrackClassDef;
1952 const ClassDef &input_class_def = this+inputClassDef;
1953 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
1955 index = input_class_def.get_class (c->buffer->cur().codepoint);
1956 const ChainRuleSet &rule_set = this+ruleSet[index];
1957 struct ChainContextApplyLookupContext lookup_context = {
1958 {match_class},
1959 {&backtrack_class_def,
1960 &input_class_def,
1961 &lookahead_class_def}
1963 return TRACE_RETURN (rule_set.apply (c, lookup_context));
1966 inline bool sanitize (hb_sanitize_context_t *c) {
1967 TRACE_SANITIZE (this);
1968 return TRACE_RETURN (coverage.sanitize (c, this) && backtrackClassDef.sanitize (c, this) &&
1969 inputClassDef.sanitize (c, this) && lookaheadClassDef.sanitize (c, this) &&
1970 ruleSet.sanitize (c, this));
1973 protected:
1974 USHORT format; /* Format identifier--format = 2 */
1975 OffsetTo<Coverage>
1976 coverage; /* Offset to Coverage table--from
1977 * beginning of table */
1978 OffsetTo<ClassDef>
1979 backtrackClassDef; /* Offset to glyph ClassDef table
1980 * containing backtrack sequence
1981 * data--from beginning of table */
1982 OffsetTo<ClassDef>
1983 inputClassDef; /* Offset to glyph ClassDef
1984 * table containing input sequence
1985 * data--from beginning of table */
1986 OffsetTo<ClassDef>
1987 lookaheadClassDef; /* Offset to glyph ClassDef table
1988 * containing lookahead sequence
1989 * data--from beginning of table */
1990 OffsetArrayOf<ChainRuleSet>
1991 ruleSet; /* Array of ChainRuleSet tables
1992 * ordered by class */
1993 public:
1994 DEFINE_SIZE_ARRAY (12, ruleSet);
1997 struct ChainContextFormat3
1999 inline void closure (hb_closure_context_t *c) const
2001 TRACE_CLOSURE (this);
2002 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2004 if (!(this+input[0]).intersects (c->glyphs))
2005 return;
2007 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2008 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2009 struct ChainContextClosureLookupContext lookup_context = {
2010 {intersects_coverage},
2011 {this, this, this}
2013 chain_context_closure_lookup (c,
2014 backtrack.len, (const USHORT *) backtrack.array,
2015 input.len, (const USHORT *) input.array + 1,
2016 lookahead.len, (const USHORT *) lookahead.array,
2017 lookup.len, lookup.array,
2018 lookup_context);
2021 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
2023 TRACE_COLLECT_GLYPHS (this);
2024 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2026 (this+input[0]).add_coverage (c->input);
2028 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2029 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2030 struct ChainContextCollectGlyphsLookupContext lookup_context = {
2031 {collect_coverage},
2032 {this, this, this}
2034 chain_context_collect_glyphs_lookup (c,
2035 backtrack.len, (const USHORT *) backtrack.array,
2036 input.len, (const USHORT *) input.array + 1,
2037 lookahead.len, (const USHORT *) lookahead.array,
2038 lookup.len, lookup.array,
2039 lookup_context);
2042 inline bool would_apply (hb_would_apply_context_t *c) const
2044 TRACE_WOULD_APPLY (this);
2046 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2047 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2048 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2049 struct ChainContextApplyLookupContext lookup_context = {
2050 {match_coverage},
2051 {this, this, this}
2053 return TRACE_RETURN (chain_context_would_apply_lookup (c,
2054 backtrack.len, (const USHORT *) backtrack.array,
2055 input.len, (const USHORT *) input.array + 1,
2056 lookahead.len, (const USHORT *) lookahead.array,
2057 lookup.len, lookup.array, lookup_context));
2060 inline const Coverage &get_coverage (void) const
2062 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2063 return this+input[0];
2066 inline bool apply (hb_apply_context_t *c) const
2068 TRACE_APPLY (this);
2069 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2071 unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint);
2072 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
2074 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2075 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2076 struct ChainContextApplyLookupContext lookup_context = {
2077 {match_coverage},
2078 {this, this, this}
2080 return TRACE_RETURN (chain_context_apply_lookup (c,
2081 backtrack.len, (const USHORT *) backtrack.array,
2082 input.len, (const USHORT *) input.array + 1,
2083 lookahead.len, (const USHORT *) lookahead.array,
2084 lookup.len, lookup.array, lookup_context));
2087 inline bool sanitize (hb_sanitize_context_t *c) {
2088 TRACE_SANITIZE (this);
2089 if (!backtrack.sanitize (c, this)) return TRACE_RETURN (false);
2090 OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2091 if (!input.sanitize (c, this)) return TRACE_RETURN (false);
2092 OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2093 if (!lookahead.sanitize (c, this)) return TRACE_RETURN (false);
2094 ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2095 return TRACE_RETURN (lookup.sanitize (c));
2098 protected:
2099 USHORT format; /* Format identifier--format = 3 */
2100 OffsetArrayOf<Coverage>
2101 backtrack; /* Array of coverage tables
2102 * in backtracking sequence, in glyph
2103 * sequence order */
2104 OffsetArrayOf<Coverage>
2105 inputX ; /* Array of coverage
2106 * tables in input sequence, in glyph
2107 * sequence order */
2108 OffsetArrayOf<Coverage>
2109 lookaheadX; /* Array of coverage tables
2110 * in lookahead sequence, in glyph
2111 * sequence order */
2112 ArrayOf<LookupRecord>
2113 lookupX; /* Array of LookupRecords--in
2114 * design order) */
2115 public:
2116 DEFINE_SIZE_MIN (10);
2119 struct ChainContext
2121 template <typename context_t>
2122 inline typename context_t::return_t dispatch (context_t *c) const
2124 TRACE_DISPATCH (this);
2125 switch (u.format) {
2126 case 1: return TRACE_RETURN (c->dispatch (u.format1));
2127 case 2: return TRACE_RETURN (c->dispatch (u.format2));
2128 case 3: return TRACE_RETURN (c->dispatch (u.format3));
2129 default:return TRACE_RETURN (c->default_return_value ());
2133 inline bool sanitize (hb_sanitize_context_t *c) {
2134 TRACE_SANITIZE (this);
2135 if (!u.format.sanitize (c)) return TRACE_RETURN (false);
2136 switch (u.format) {
2137 case 1: return TRACE_RETURN (u.format1.sanitize (c));
2138 case 2: return TRACE_RETURN (u.format2.sanitize (c));
2139 case 3: return TRACE_RETURN (u.format3.sanitize (c));
2140 default:return TRACE_RETURN (true);
2144 protected:
2145 union {
2146 USHORT format; /* Format identifier */
2147 ChainContextFormat1 format1;
2148 ChainContextFormat2 format2;
2149 ChainContextFormat3 format3;
2150 } u;
2154 struct ExtensionFormat1
2156 inline unsigned int get_type (void) const { return extensionLookupType; }
2157 inline unsigned int get_offset (void) const { return extensionOffset; }
2159 inline bool sanitize (hb_sanitize_context_t *c) {
2160 TRACE_SANITIZE (this);
2161 return TRACE_RETURN (c->check_struct (this));
2164 protected:
2165 USHORT format; /* Format identifier. Set to 1. */
2166 USHORT extensionLookupType; /* Lookup type of subtable referenced
2167 * by ExtensionOffset (i.e. the
2168 * extension subtable). */
2169 ULONG extensionOffset; /* Offset to the extension subtable,
2170 * of lookup type subtable. */
2171 public:
2172 DEFINE_SIZE_STATIC (8);
2175 template <typename T>
2176 struct Extension
2178 inline unsigned int get_type (void) const
2180 switch (u.format) {
2181 case 1: return u.format1.get_type ();
2182 default:return 0;
2185 inline unsigned int get_offset (void) const
2187 switch (u.format) {
2188 case 1: return u.format1.get_offset ();
2189 default:return 0;
2193 template <typename X>
2194 inline const X& get_subtable (void) const
2196 unsigned int offset = get_offset ();
2197 if (unlikely (!offset)) return Null(typename T::LookupSubTable);
2198 return StructAtOffset<typename T::LookupSubTable> (this, offset);
2201 template <typename context_t>
2202 inline typename context_t::return_t dispatch (context_t *c) const
2204 return get_subtable<typename T::LookupSubTable> ().dispatch (c, get_type ());
2207 inline bool sanitize_self (hb_sanitize_context_t *c) {
2208 TRACE_SANITIZE (this);
2209 if (!u.format.sanitize (c)) return TRACE_RETURN (false);
2210 switch (u.format) {
2211 case 1: return TRACE_RETURN (u.format1.sanitize (c));
2212 default:return TRACE_RETURN (true);
2216 inline bool sanitize (hb_sanitize_context_t *c) {
2217 TRACE_SANITIZE (this);
2218 if (!sanitize_self (c)) return TRACE_RETURN (false);
2219 unsigned int offset = get_offset ();
2220 if (unlikely (!offset)) return TRACE_RETURN (true);
2221 return TRACE_RETURN (StructAtOffset<typename T::LookupSubTable> (this, offset).sanitize (c, get_type ()));
2224 protected:
2225 union {
2226 USHORT format; /* Format identifier */
2227 ExtensionFormat1 format1;
2228 } u;
2233 * GSUB/GPOS Common
2236 struct GSUBGPOS
2238 static const hb_tag_t GSUBTag = HB_OT_TAG_GSUB;
2239 static const hb_tag_t GPOSTag = HB_OT_TAG_GPOS;
2241 inline unsigned int get_script_count (void) const
2242 { return (this+scriptList).len; }
2243 inline const Tag& get_script_tag (unsigned int i) const
2244 { return (this+scriptList).get_tag (i); }
2245 inline unsigned int get_script_tags (unsigned int start_offset,
2246 unsigned int *script_count /* IN/OUT */,
2247 hb_tag_t *script_tags /* OUT */) const
2248 { return (this+scriptList).get_tags (start_offset, script_count, script_tags); }
2249 inline const Script& get_script (unsigned int i) const
2250 { return (this+scriptList)[i]; }
2251 inline bool find_script_index (hb_tag_t tag, unsigned int *index) const
2252 { return (this+scriptList).find_index (tag, index); }
2254 inline unsigned int get_feature_count (void) const
2255 { return (this+featureList).len; }
2256 inline const Tag& get_feature_tag (unsigned int i) const
2257 { return (this+featureList).get_tag (i); }
2258 inline unsigned int get_feature_tags (unsigned int start_offset,
2259 unsigned int *feature_count /* IN/OUT */,
2260 hb_tag_t *feature_tags /* OUT */) const
2261 { return (this+featureList).get_tags (start_offset, feature_count, feature_tags); }
2262 inline const Feature& get_feature (unsigned int i) const
2263 { return (this+featureList)[i]; }
2264 inline bool find_feature_index (hb_tag_t tag, unsigned int *index) const
2265 { return (this+featureList).find_index (tag, index); }
2267 inline unsigned int get_lookup_count (void) const
2268 { return (this+lookupList).len; }
2269 inline const Lookup& get_lookup (unsigned int i) const
2270 { return (this+lookupList)[i]; }
2272 inline bool sanitize (hb_sanitize_context_t *c) {
2273 TRACE_SANITIZE (this);
2274 return TRACE_RETURN (version.sanitize (c) && likely (version.major == 1) &&
2275 scriptList.sanitize (c, this) &&
2276 featureList.sanitize (c, this) &&
2277 lookupList.sanitize (c, this));
2280 protected:
2281 FixedVersion version; /* Version of the GSUB/GPOS table--initially set
2282 * to 0x00010000 */
2283 OffsetTo<ScriptList>
2284 scriptList; /* ScriptList table */
2285 OffsetTo<FeatureList>
2286 featureList; /* FeatureList table */
2287 OffsetTo<LookupList>
2288 lookupList; /* LookupList table */
2289 public:
2290 DEFINE_SIZE_STATIC (10);
2294 } /* namespace OT */
2297 #endif /* HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH */