Update harfbuzz-ng to 0.9.14 from 0.9.10
[chromium-blink-merge.git] / third_party / harfbuzz-ng / src / hb-ot-layout-gsubgpos-private.hh
blobf46b3782ec71218709eb73aee3eebbff02427f0b
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 "");
47 #ifndef HB_DEBUG_CLOSURE
48 #define HB_DEBUG_CLOSURE (HB_DEBUG+0)
49 #endif
51 #define TRACE_CLOSURE(this) \
52 hb_auto_trace_t<HB_DEBUG_CLOSURE, hb_void_t> trace \
53 (&c->debug_depth, c->get_name (), this, HB_FUNC, \
54 "");
56 struct hb_closure_context_t
58 inline const char *get_name (void) { return "CLOSURE"; }
59 static const unsigned int max_debug_depth = HB_DEBUG_CLOSURE;
60 typedef hb_void_t return_t;
61 typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
62 template <typename T>
63 inline return_t dispatch (const T &obj) { obj.closure (this); return HB_VOID; }
64 static return_t default_return_value (void) { return HB_VOID; }
65 bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
66 return_t recurse (unsigned int lookup_index)
68 if (unlikely (nesting_level_left == 0 || !recurse_func))
69 return default_return_value ();
71 nesting_level_left--;
72 recurse_func (this, lookup_index);
73 nesting_level_left++;
74 return HB_VOID;
77 hb_face_t *face;
78 hb_set_t *glyphs;
79 recurse_func_t recurse_func;
80 unsigned int nesting_level_left;
81 unsigned int debug_depth;
83 hb_closure_context_t (hb_face_t *face_,
84 hb_set_t *glyphs_,
85 unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) :
86 face (face_),
87 glyphs (glyphs_),
88 recurse_func (NULL),
89 nesting_level_left (nesting_level_left_),
90 debug_depth (0) {}
92 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
97 #ifndef HB_DEBUG_WOULD_APPLY
98 #define HB_DEBUG_WOULD_APPLY (HB_DEBUG+0)
99 #endif
101 #define TRACE_WOULD_APPLY(this) \
102 hb_auto_trace_t<HB_DEBUG_WOULD_APPLY, bool> trace \
103 (&c->debug_depth, c->get_name (), this, HB_FUNC, \
104 "%d glyphs", c->len);
106 struct hb_would_apply_context_t
108 inline const char *get_name (void) { return "WOULD_APPLY"; }
109 static const unsigned int max_debug_depth = HB_DEBUG_WOULD_APPLY;
110 typedef bool return_t;
111 template <typename T>
112 inline return_t dispatch (const T &obj) { return obj.would_apply (this); }
113 static return_t default_return_value (void) { return false; }
114 bool stop_sublookup_iteration (return_t r) const { return r; }
116 hb_face_t *face;
117 const hb_codepoint_t *glyphs;
118 unsigned int len;
119 bool zero_context;
120 unsigned int debug_depth;
122 hb_would_apply_context_t (hb_face_t *face_,
123 const hb_codepoint_t *glyphs_,
124 unsigned int len_,
125 bool zero_context_) :
126 face (face_),
127 glyphs (glyphs_),
128 len (len_),
129 zero_context (zero_context_),
130 debug_depth (0) {}
135 #ifndef HB_DEBUG_COLLECT_GLYPHS
136 #define HB_DEBUG_COLLECT_GLYPHS (HB_DEBUG+0)
137 #endif
139 #define TRACE_COLLECT_GLYPHS(this) \
140 hb_auto_trace_t<HB_DEBUG_COLLECT_GLYPHS, hb_void_t> trace \
141 (&c->debug_depth, c->get_name (), this, HB_FUNC, \
142 "");
144 struct hb_collect_glyphs_context_t
146 inline const char *get_name (void) { return "COLLECT_GLYPHS"; }
147 static const unsigned int max_debug_depth = HB_DEBUG_COLLECT_GLYPHS;
148 typedef hb_void_t return_t;
149 typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index);
150 template <typename T>
151 inline return_t dispatch (const T &obj) { obj.collect_glyphs (this); return HB_VOID; }
152 static return_t default_return_value (void) { return HB_VOID; }
153 bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; }
154 return_t recurse (unsigned int lookup_index)
156 if (unlikely (nesting_level_left == 0 || !recurse_func))
157 return default_return_value ();
159 /* Note that GPOS sets recurse_func to NULL already, so it doesn't get
160 * past the previous check. For GSUB, we only want to collect the output
161 * glyphs in the recursion. If output is not requested, we can go home now. */
163 if (output == hb_set_get_empty ())
164 return HB_VOID;
166 hb_set_t *old_before = before;
167 hb_set_t *old_input = input;
168 hb_set_t *old_after = after;
169 before = input = after = hb_set_get_empty ();
171 nesting_level_left--;
172 recurse_func (this, lookup_index);
173 nesting_level_left++;
175 before = old_before;
176 input = old_input;
177 after = old_after;
179 return HB_VOID;
182 hb_face_t *face;
183 hb_set_t *before;
184 hb_set_t *input;
185 hb_set_t *after;
186 hb_set_t *output;
187 recurse_func_t recurse_func;
188 unsigned int nesting_level_left;
189 unsigned int debug_depth;
191 hb_collect_glyphs_context_t (hb_face_t *face_,
192 hb_set_t *glyphs_before, /* OUT. May be NULL */
193 hb_set_t *glyphs_input, /* OUT. May be NULL */
194 hb_set_t *glyphs_after, /* OUT. May be NULL */
195 hb_set_t *glyphs_output, /* OUT. May be NULL */
196 unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) :
197 face (face_),
198 before (glyphs_before ? glyphs_before : hb_set_get_empty ()),
199 input (glyphs_input ? glyphs_input : hb_set_get_empty ()),
200 after (glyphs_after ? glyphs_after : hb_set_get_empty ()),
201 output (glyphs_output ? glyphs_output : hb_set_get_empty ()),
202 recurse_func (NULL),
203 nesting_level_left (nesting_level_left_),
204 debug_depth (0) {}
206 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
211 struct hb_get_coverage_context_t
213 inline const char *get_name (void) { return "GET_COVERAGE"; }
214 static const unsigned int max_debug_depth = 0;
215 typedef const Coverage &return_t;
216 template <typename T>
217 inline return_t dispatch (const T &obj) { return obj.get_coverage (); }
218 static return_t default_return_value (void) { return Null(Coverage); }
220 hb_get_coverage_context_t (void) :
221 debug_depth (0) {}
223 unsigned int debug_depth;
228 #ifndef HB_DEBUG_APPLY
229 #define HB_DEBUG_APPLY (HB_DEBUG+0)
230 #endif
232 #define TRACE_APPLY(this) \
233 hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace \
234 (&c->debug_depth, c->get_name (), this, HB_FUNC, \
235 "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint);
237 struct hb_apply_context_t
239 inline const char *get_name (void) { return "APPLY"; }
240 static const unsigned int max_debug_depth = HB_DEBUG_APPLY;
241 typedef bool return_t;
242 typedef return_t (*recurse_func_t) (hb_apply_context_t *c, unsigned int lookup_index);
243 template <typename T>
244 inline return_t dispatch (const T &obj) { return obj.apply (this); }
245 static return_t default_return_value (void) { return false; }
246 bool stop_sublookup_iteration (return_t r) const { return r; }
247 return_t recurse (unsigned int lookup_index)
249 if (unlikely (nesting_level_left == 0 || !recurse_func))
250 return default_return_value ();
252 nesting_level_left--;
253 bool ret = recurse_func (this, lookup_index);
254 nesting_level_left++;
255 return ret;
258 unsigned int table_index; /* GSUB/GPOS */
259 hb_font_t *font;
260 hb_face_t *face;
261 hb_buffer_t *buffer;
262 hb_direction_t direction;
263 hb_mask_t lookup_mask;
264 bool auto_zwj;
265 recurse_func_t recurse_func;
266 unsigned int nesting_level_left;
267 unsigned int lookup_props;
268 const GDEF &gdef;
269 bool has_glyph_classes;
270 unsigned int debug_depth;
273 hb_apply_context_t (unsigned int table_index_,
274 hb_font_t *font_,
275 hb_buffer_t *buffer_,
276 hb_mask_t lookup_mask_,
277 bool auto_zwj_) :
278 table_index (table_index_),
279 font (font_), face (font->face), buffer (buffer_),
280 direction (buffer_->props.direction),
281 lookup_mask (lookup_mask_),
282 auto_zwj (auto_zwj_),
283 recurse_func (NULL),
284 nesting_level_left (MAX_NESTING_LEVEL),
285 lookup_props (0),
286 gdef (*hb_ot_layout_from_face (face)->gdef),
287 has_glyph_classes (gdef.has_glyph_classes ()),
288 debug_depth (0) {}
290 inline void set_recurse_func (recurse_func_t func) { recurse_func = func; }
291 inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
292 inline void set_lookup (const Lookup &l) { lookup_props = l.get_props (); }
294 struct matcher_t
296 inline matcher_t (void) :
297 lookup_props (0),
298 ignore_zwnj (false),
299 ignore_zwj (false),
300 mask (-1),
301 #define arg1(arg) (arg) /* Remove the macro to see why it's needed! */
302 syllable arg1(0),
303 #undef arg1
304 match_func (NULL),
305 match_data (NULL) {};
307 typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data);
309 inline void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; }
310 inline void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
311 inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
312 inline void set_mask (hb_mask_t mask_) { mask = mask_; }
313 inline void set_syllable (uint8_t syllable_) { syllable = syllable_; }
314 inline void set_match_func (match_func_t match_func_,
315 const void *match_data_)
316 { match_func = match_func_; match_data = match_data_; }
318 enum may_match_t {
319 MATCH_NO,
320 MATCH_YES,
321 MATCH_MAYBE
324 inline may_match_t may_match (const hb_glyph_info_t &info,
325 const USHORT *glyph_data) const
327 if (!(info.mask & mask) ||
328 (syllable && syllable != info.syllable ()))
329 return MATCH_NO;
331 if (match_func)
332 return match_func (info.codepoint, *glyph_data, match_data) ? MATCH_YES : MATCH_NO;
334 return MATCH_MAYBE;
337 enum may_skip_t {
338 SKIP_NO,
339 SKIP_YES,
340 SKIP_MAYBE
343 inline may_skip_t
344 may_skip (const hb_apply_context_t *c,
345 const hb_glyph_info_t &info) const
347 unsigned int property;
349 property = info.glyph_props();
351 if (!c->match_properties (info.codepoint, property, lookup_props))
352 return SKIP_YES;
354 if (unlikely (_hb_glyph_info_is_default_ignorable (&info) &&
355 (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) &&
356 (ignore_zwj || !_hb_glyph_info_is_zwj (&info)) &&
357 !is_a_ligature (info)))
358 return SKIP_MAYBE;
360 return SKIP_NO;
363 protected:
364 unsigned int lookup_props;
365 bool ignore_zwnj;
366 bool ignore_zwj;
367 hb_mask_t mask;
368 uint8_t syllable;
369 match_func_t match_func;
370 const void *match_data;
373 struct skipping_forward_iterator_t
375 inline skipping_forward_iterator_t (hb_apply_context_t *c_,
376 unsigned int start_index_,
377 unsigned int num_items_,
378 bool context_match = false) :
379 idx (start_index_),
380 c (c_),
381 match_glyph_data (NULL),
382 num_items (num_items_),
383 end (c->buffer->len)
385 matcher.set_lookup_props (c->lookup_props);
386 /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
387 matcher.set_ignore_zwnj (context_match || c->table_index == 1);
388 /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */
389 matcher.set_ignore_zwj (context_match || c->table_index == 1 || c->auto_zwj);
390 if (!context_match)
391 matcher.set_mask (c->lookup_mask);
392 matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
394 inline void set_lookup_props (unsigned int lookup_props) { matcher.set_lookup_props (lookup_props); }
395 inline void set_syllable (unsigned int syllable) { matcher.set_syllable (syllable); }
396 inline void set_match_func (matcher_t::match_func_t match_func,
397 const void *match_data,
398 const USHORT glyph_data[])
400 matcher.set_match_func (match_func, match_data);
401 match_glyph_data = glyph_data;
404 inline bool has_no_chance (void) const { return unlikely (num_items && idx + num_items >= end); }
405 inline void reject (void) { num_items++; match_glyph_data--; }
406 inline bool next (void)
408 assert (num_items > 0);
409 while (!has_no_chance ())
411 idx++;
412 const hb_glyph_info_t &info = c->buffer->info[idx];
414 matcher_t::may_skip_t skip = matcher.may_skip (c, info);
415 if (unlikely (skip == matcher_t::SKIP_YES))
416 continue;
418 matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
419 if (match == matcher_t::MATCH_YES ||
420 (match == matcher_t::MATCH_MAYBE &&
421 skip == matcher_t::SKIP_NO))
423 num_items--;
424 match_glyph_data++;
425 return true;
428 if (skip == matcher_t::SKIP_NO)
429 return false;
431 return false;
434 unsigned int idx;
435 protected:
436 hb_apply_context_t *c;
437 matcher_t matcher;
438 const USHORT *match_glyph_data;
440 unsigned int num_items;
441 unsigned int end;
444 struct skipping_backward_iterator_t
446 inline skipping_backward_iterator_t (hb_apply_context_t *c_,
447 unsigned int start_index_,
448 unsigned int num_items_,
449 bool context_match = false) :
450 idx (start_index_),
451 c (c_),
452 match_glyph_data (NULL),
453 num_items (num_items_)
455 matcher.set_lookup_props (c->lookup_props);
456 /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
457 matcher.set_ignore_zwnj (context_match || c->table_index == 1);
458 /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */
459 matcher.set_ignore_zwj (context_match || c->table_index == 1 || c->auto_zwj);
460 if (!context_match)
461 matcher.set_mask (c->lookup_mask);
462 matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
464 inline void set_lookup_props (unsigned int lookup_props) { matcher.set_lookup_props (lookup_props); }
465 inline void set_syllable (unsigned int syllable) { matcher.set_syllable (syllable); }
466 inline void set_match_func (matcher_t::match_func_t match_func,
467 const void *match_data,
468 const USHORT glyph_data[])
470 matcher.set_match_func (match_func, match_data);
471 match_glyph_data = glyph_data;
474 inline bool has_no_chance (void) const { return unlikely (idx < num_items); }
475 inline void reject (void) { num_items++; }
476 inline bool prev (void)
478 assert (num_items > 0);
479 while (!has_no_chance ())
481 idx--;
482 const hb_glyph_info_t &info = c->buffer->out_info[idx];
484 matcher_t::may_skip_t skip = matcher.may_skip (c, info);
486 if (unlikely (skip == matcher_t::SKIP_YES))
487 continue;
489 matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
490 if (match == matcher_t::MATCH_YES ||
491 (match == matcher_t::MATCH_MAYBE &&
492 skip == matcher_t::SKIP_NO))
494 num_items--;
495 match_glyph_data++;
496 return true;
499 if (skip == matcher_t::SKIP_NO)
500 return false;
502 return false;
505 unsigned int idx;
506 protected:
507 hb_apply_context_t *c;
508 matcher_t matcher;
509 const USHORT *match_glyph_data;
511 unsigned int num_items;
514 inline bool
515 match_properties_mark (hb_codepoint_t glyph,
516 unsigned int glyph_props,
517 unsigned int lookup_props) const
519 /* If using mark filtering sets, the high short of
520 * lookup_props has the set index.
522 if (lookup_props & LookupFlag::UseMarkFilteringSet)
523 return gdef.mark_set_covers (lookup_props >> 16, glyph);
525 /* The second byte of lookup_props has the meaning
526 * "ignore marks of attachment type different than
527 * the attachment type specified."
529 if (lookup_props & LookupFlag::MarkAttachmentType)
530 return (lookup_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);
532 return true;
535 inline bool
536 match_properties (hb_codepoint_t glyph,
537 unsigned int glyph_props,
538 unsigned int lookup_props) const
540 /* Not covered, if, for example, glyph class is ligature and
541 * lookup_props includes LookupFlags::IgnoreLigatures
543 if (glyph_props & lookup_props & LookupFlag::IgnoreFlags)
544 return false;
546 if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK))
547 return match_properties_mark (glyph, glyph_props, lookup_props);
549 return true;
552 inline bool
553 check_glyph_property (hb_glyph_info_t *info,
554 unsigned int lookup_props) const
556 unsigned int property;
558 property = info->glyph_props();
560 return match_properties (info->codepoint, property, lookup_props);
563 inline void set_class (hb_codepoint_t glyph_index, unsigned int class_guess) const
565 if (likely (has_glyph_classes))
566 buffer->cur().glyph_props() = gdef.get_glyph_props (glyph_index);
567 else if (class_guess)
568 buffer->cur().glyph_props() = class_guess;
571 inline void output_glyph (hb_codepoint_t glyph_index,
572 unsigned int class_guess = 0) const
574 set_class (glyph_index, class_guess);
575 buffer->output_glyph (glyph_index);
577 inline void replace_glyph (hb_codepoint_t glyph_index,
578 unsigned int class_guess = 0) const
580 set_class (glyph_index, class_guess);
581 buffer->replace_glyph (glyph_index);
583 inline void replace_glyph_inplace (hb_codepoint_t glyph_index,
584 unsigned int class_guess = 0) const
586 set_class (glyph_index, class_guess);
587 buffer->cur().codepoint = glyph_index;
593 typedef bool (*intersects_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data);
594 typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data);
595 typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data);
597 struct ContextClosureFuncs
599 intersects_func_t intersects;
601 struct ContextCollectGlyphsFuncs
603 collect_glyphs_func_t collect;
605 struct ContextApplyFuncs
607 match_func_t match;
611 static inline bool intersects_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED)
613 return glyphs->has (value);
615 static inline bool intersects_class (hb_set_t *glyphs, const USHORT &value, const void *data)
617 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
618 return class_def.intersects_class (glyphs, value);
620 static inline bool intersects_coverage (hb_set_t *glyphs, const USHORT &value, const void *data)
622 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
623 return (data+coverage).intersects (glyphs);
626 static inline bool intersects_array (hb_closure_context_t *c,
627 unsigned int count,
628 const USHORT values[],
629 intersects_func_t intersects_func,
630 const void *intersects_data)
632 for (unsigned int i = 0; i < count; i++)
633 if (likely (!intersects_func (c->glyphs, values[i], intersects_data)))
634 return false;
635 return true;
639 static inline void collect_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED)
641 glyphs->add (value);
643 static inline void collect_class (hb_set_t *glyphs, const USHORT &value, const void *data)
645 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
646 class_def.add_class (glyphs, value);
648 static inline void collect_coverage (hb_set_t *glyphs, const USHORT &value, const void *data)
650 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
651 (data+coverage).add_coverage (glyphs);
653 static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
654 hb_set_t *glyphs,
655 unsigned int count,
656 const USHORT values[],
657 collect_glyphs_func_t collect_func,
658 const void *collect_data)
660 for (unsigned int i = 0; i < count; i++)
661 collect_func (glyphs, values[i], collect_data);
665 static inline bool match_glyph (hb_codepoint_t glyph_id, const USHORT &value, const void *data HB_UNUSED)
667 return glyph_id == value;
669 static inline bool match_class (hb_codepoint_t glyph_id, const USHORT &value, const void *data)
671 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
672 return class_def.get_class (glyph_id) == value;
674 static inline bool match_coverage (hb_codepoint_t glyph_id, const USHORT &value, const void *data)
676 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
677 return (data+coverage).get_coverage (glyph_id) != NOT_COVERED;
680 static inline bool would_match_input (hb_would_apply_context_t *c,
681 unsigned int count, /* Including the first glyph (not matched) */
682 const USHORT input[], /* Array of input values--start with second glyph */
683 match_func_t match_func,
684 const void *match_data)
686 if (count != c->len)
687 return false;
689 for (unsigned int i = 1; i < count; i++)
690 if (likely (!match_func (c->glyphs[i], input[i - 1], match_data)))
691 return false;
693 return true;
695 static inline bool match_input (hb_apply_context_t *c,
696 unsigned int count, /* Including the first glyph (not matched) */
697 const USHORT input[], /* Array of input values--start with second glyph */
698 match_func_t match_func,
699 const void *match_data,
700 unsigned int *end_offset = NULL,
701 bool *p_is_mark_ligature = NULL,
702 unsigned int *p_total_component_count = NULL)
704 TRACE_APPLY (NULL);
706 hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1);
707 skippy_iter.set_match_func (match_func, match_data, input);
708 if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
711 * This is perhaps the trickiest part of OpenType... Remarks:
713 * - If all components of the ligature were marks, we call this a mark ligature.
715 * - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize
716 * it as a ligature glyph.
718 * - Ligatures cannot be formed across glyphs attached to different components
719 * of previous ligatures. Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and
720 * LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother.
721 * However, it would be wrong to ligate that SHADDA,FATHA sequence.o
722 * There is an exception to this: If a ligature tries ligating with marks that
723 * belong to it itself, go ahead, assuming that the font designer knows what
724 * they are doing (otherwise it can break Indic stuff when a matra wants to
725 * ligate with a conjunct...)
728 bool is_mark_ligature = !!(c->buffer->cur().glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK);
730 unsigned int total_component_count = 0;
731 total_component_count += get_lig_num_comps (c->buffer->cur());
733 unsigned int first_lig_id = get_lig_id (c->buffer->cur());
734 unsigned int first_lig_comp = get_lig_comp (c->buffer->cur());
736 for (unsigned int i = 1; i < count; i++)
738 if (!skippy_iter.next ()) return TRACE_RETURN (false);
740 unsigned int this_lig_id = get_lig_id (c->buffer->info[skippy_iter.idx]);
741 unsigned int this_lig_comp = get_lig_comp (c->buffer->info[skippy_iter.idx]);
743 if (first_lig_id && first_lig_comp) {
744 /* If first component was attached to a previous ligature component,
745 * all subsequent components should be attached to the same ligature
746 * component, otherwise we shouldn't ligate them. */
747 if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
748 return TRACE_RETURN (false);
749 } else {
750 /* If first component was NOT attached to a previous ligature component,
751 * all subsequent components should also NOT be attached to any ligature
752 * component, unless they are attached to the first component itself! */
753 if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id))
754 return TRACE_RETURN (false);
757 is_mark_ligature = is_mark_ligature && (c->buffer->info[skippy_iter.idx].glyph_props() & HB_OT_LAYOUT_GLYPH_PROPS_MARK);
758 total_component_count += get_lig_num_comps (c->buffer->info[skippy_iter.idx]);
761 if (end_offset)
762 *end_offset = skippy_iter.idx - c->buffer->idx + 1;
764 if (p_is_mark_ligature)
765 *p_is_mark_ligature = is_mark_ligature;
767 if (p_total_component_count)
768 *p_total_component_count = total_component_count;
770 return TRACE_RETURN (true);
772 static inline void ligate_input (hb_apply_context_t *c,
773 unsigned int count, /* Including the first glyph (not matched) */
774 const USHORT input[], /* Array of input values--start with second glyph */
775 match_func_t match_func,
776 const void *match_data,
777 hb_codepoint_t lig_glyph,
778 bool is_mark_ligature,
779 unsigned int total_component_count)
781 hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1);
782 skippy_iter.set_match_func (match_func, match_data, input);
783 if (skippy_iter.has_no_chance ()) return;
786 * - If it *is* a mark ligature, we don't allocate a new ligature id, and leave
787 * the ligature to keep its old ligature id. This will allow it to attach to
788 * a base ligature in GPOS. Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH,
789 * and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA wit a
790 * ligature id and component value of 2. Then if SHADDA,FATHA form a ligature
791 * later, we don't want them to lose their ligature id/component, otherwise
792 * GPOS will fail to correctly position the mark ligature on top of the
793 * LAM,LAM,HEH ligature. See:
794 * https://bugzilla.gnome.org/show_bug.cgi?id=676343
796 * - If a ligature is formed of components that some of which are also ligatures
797 * themselves, and those ligature components had marks attached to *their*
798 * components, we have to attach the marks to the new ligature component
799 * positions! Now *that*'s tricky! And these marks may be following the
800 * last component of the whole sequence, so we should loop forward looking
801 * for them and update them.
803 * Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a
804 * 'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature
805 * id and component == 1. Now, during 'liga', the LAM and the LAM-HEH ligature
806 * form a LAM-LAM-HEH ligature. We need to reassign the SHADDA and FATHA to
807 * the new ligature with a component value of 2.
809 * This in fact happened to a font... See:
810 * https://bugzilla.gnome.org/show_bug.cgi?id=437633
813 unsigned int klass = is_mark_ligature ? 0 : HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
814 unsigned int lig_id = is_mark_ligature ? 0 : allocate_lig_id (c->buffer);
815 unsigned int last_lig_id = get_lig_id (c->buffer->cur());
816 unsigned int last_num_components = get_lig_num_comps (c->buffer->cur());
817 unsigned int components_so_far = last_num_components;
819 if (!is_mark_ligature)
820 set_lig_props_for_ligature (c->buffer->cur(), lig_id, total_component_count);
821 c->replace_glyph (lig_glyph, klass);
823 for (unsigned int i = 1; i < count; i++)
825 if (!skippy_iter.next ()) return;
827 while (c->buffer->idx < skippy_iter.idx)
829 if (!is_mark_ligature) {
830 unsigned int new_lig_comp = components_so_far - last_num_components +
831 MIN (MAX (get_lig_comp (c->buffer->cur()), 1u), last_num_components);
832 set_lig_props_for_mark (c->buffer->cur(), lig_id, new_lig_comp);
834 c->buffer->next_glyph ();
837 last_lig_id = get_lig_id (c->buffer->cur());
838 last_num_components = get_lig_num_comps (c->buffer->cur());
839 components_so_far += last_num_components;
841 /* Skip the base glyph */
842 c->buffer->idx++;
845 if (!is_mark_ligature && last_lig_id) {
846 /* Re-adjust components for any marks following. */
847 for (unsigned int i = c->buffer->idx; i < c->buffer->len; i++) {
848 if (last_lig_id == get_lig_id (c->buffer->info[i])) {
849 unsigned int new_lig_comp = components_so_far - last_num_components +
850 MIN (MAX (get_lig_comp (c->buffer->info[i]), 1u), last_num_components);
851 set_lig_props_for_mark (c->buffer->info[i], lig_id, new_lig_comp);
852 } else
853 break;
858 static inline bool match_backtrack (hb_apply_context_t *c,
859 unsigned int count,
860 const USHORT backtrack[],
861 match_func_t match_func,
862 const void *match_data)
864 TRACE_APPLY (NULL);
866 hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, c->buffer->backtrack_len (), count, true);
867 skippy_iter.set_match_func (match_func, match_data, backtrack);
868 if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
870 for (unsigned int i = 0; i < count; i++)
871 if (!skippy_iter.prev ())
872 return TRACE_RETURN (false);
874 return TRACE_RETURN (true);
877 static inline bool match_lookahead (hb_apply_context_t *c,
878 unsigned int count,
879 const USHORT lookahead[],
880 match_func_t match_func,
881 const void *match_data,
882 unsigned int offset)
884 TRACE_APPLY (NULL);
886 hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx + offset - 1, count, true);
887 skippy_iter.set_match_func (match_func, match_data, lookahead);
888 if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
890 for (unsigned int i = 0; i < count; i++)
891 if (!skippy_iter.next ())
892 return TRACE_RETURN (false);
894 return TRACE_RETURN (true);
899 struct LookupRecord
901 inline bool sanitize (hb_sanitize_context_t *c) {
902 TRACE_SANITIZE (this);
903 return TRACE_RETURN (c->check_struct (this));
906 USHORT sequenceIndex; /* Index into current glyph
907 * sequence--first glyph = 0 */
908 USHORT lookupListIndex; /* Lookup to apply to that
909 * position--zero--based */
910 public:
911 DEFINE_SIZE_STATIC (4);
915 template <typename context_t>
916 static inline void recurse_lookups (context_t *c,
917 unsigned int lookupCount,
918 const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
920 for (unsigned int i = 0; i < lookupCount; i++)
921 c->recurse (lookupRecord->lookupListIndex);
924 static inline bool apply_lookup (hb_apply_context_t *c,
925 unsigned int count, /* Including the first glyph */
926 const USHORT input[], /* Array of input values--start with second glyph */
927 match_func_t match_func,
928 const void *match_data,
929 unsigned int lookupCount,
930 const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
932 TRACE_APPLY (NULL);
934 unsigned int end = c->buffer->len;
935 if (unlikely (count == 0 || c->buffer->idx + count > end))
936 return TRACE_RETURN (false);
938 /* TODO We don't support lookupRecord arrays that are not increasing:
939 * Should be easy for in_place ones at least. */
941 /* Note: If sublookup is reverse, it will underflow after the first loop
942 * and we jump out of it. Not entirely disastrous. So we don't check
943 * for reverse lookup here.
946 hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx, count - 1);
947 skippy_iter.set_match_func (match_func, match_data, input);
948 uint8_t syllable = c->buffer->cur().syllable();
950 unsigned int i = 0;
951 if (lookupCount && 0 == lookupRecord->sequenceIndex)
953 unsigned int old_pos = c->buffer->idx;
955 /* Apply a lookup */
956 bool done = c->recurse (lookupRecord->lookupListIndex);
958 lookupRecord++;
959 lookupCount--;
960 /* Err, this is wrong if the lookup jumped over some glyphs */
961 i += c->buffer->idx - old_pos;
963 if (!done)
964 goto not_applied;
965 else
967 /* Reinitialize iterator. */
968 hb_apply_context_t::skipping_forward_iterator_t tmp (c, c->buffer->idx - 1, count - i);
969 tmp.set_syllable (syllable);
970 skippy_iter = tmp;
973 else
975 not_applied:
976 /* No lookup applied for this index */
977 c->buffer->next_glyph ();
978 i++;
980 while (i < count)
982 if (!skippy_iter.next ()) return TRACE_RETURN (true);
983 while (c->buffer->idx < skippy_iter.idx)
984 c->buffer->next_glyph ();
986 if (lookupCount && i == lookupRecord->sequenceIndex)
988 unsigned int old_pos = c->buffer->idx;
990 /* Apply a lookup */
991 bool done = c->recurse (lookupRecord->lookupListIndex);
993 lookupRecord++;
994 lookupCount--;
995 /* Err, this is wrong if the lookup jumped over some glyphs */
996 i += c->buffer->idx - old_pos;
998 if (!done)
999 goto not_applied2;
1000 else
1002 /* Reinitialize iterator. */
1003 hb_apply_context_t::skipping_forward_iterator_t tmp (c, c->buffer->idx - 1, count - i);
1004 tmp.set_syllable (syllable);
1005 skippy_iter = tmp;
1008 else
1010 not_applied2:
1011 /* No lookup applied for this index */
1012 c->buffer->next_glyph ();
1013 i++;
1017 return TRACE_RETURN (true);
1022 /* Contextual lookups */
1024 struct ContextClosureLookupContext
1026 ContextClosureFuncs funcs;
1027 const void *intersects_data;
1030 struct ContextCollectGlyphsLookupContext
1032 ContextCollectGlyphsFuncs funcs;
1033 const void *collect_data;
1036 struct ContextApplyLookupContext
1038 ContextApplyFuncs funcs;
1039 const void *match_data;
1042 static inline void context_closure_lookup (hb_closure_context_t *c,
1043 unsigned int inputCount, /* Including the first glyph (not matched) */
1044 const USHORT input[], /* Array of input values--start with second glyph */
1045 unsigned int lookupCount,
1046 const LookupRecord lookupRecord[],
1047 ContextClosureLookupContext &lookup_context)
1049 if (intersects_array (c,
1050 inputCount ? inputCount - 1 : 0, input,
1051 lookup_context.funcs.intersects, lookup_context.intersects_data))
1052 recurse_lookups (c,
1053 lookupCount, lookupRecord);
1056 static inline void context_collect_glyphs_lookup (hb_collect_glyphs_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 ContextCollectGlyphsLookupContext &lookup_context)
1063 collect_array (c, c->input,
1064 inputCount ? inputCount - 1 : 0, input,
1065 lookup_context.funcs.collect, lookup_context.collect_data);
1066 recurse_lookups (c,
1067 lookupCount, lookupRecord);
1070 static inline bool context_would_apply_lookup (hb_would_apply_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 HB_UNUSED,
1074 const LookupRecord lookupRecord[] HB_UNUSED,
1075 ContextApplyLookupContext &lookup_context)
1077 return would_match_input (c,
1078 inputCount, input,
1079 lookup_context.funcs.match, lookup_context.match_data);
1081 static inline bool context_apply_lookup (hb_apply_context_t *c,
1082 unsigned int inputCount, /* Including the first glyph (not matched) */
1083 const USHORT input[], /* Array of input values--start with second glyph */
1084 unsigned int lookupCount,
1085 const LookupRecord lookupRecord[],
1086 ContextApplyLookupContext &lookup_context)
1088 return match_input (c,
1089 inputCount, input,
1090 lookup_context.funcs.match, lookup_context.match_data)
1091 && apply_lookup (c,
1092 inputCount, input,
1093 lookup_context.funcs.match, lookup_context.match_data,
1094 lookupCount, lookupRecord);
1097 struct Rule
1099 inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
1101 TRACE_CLOSURE (this);
1102 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
1103 context_closure_lookup (c,
1104 inputCount, input,
1105 lookupCount, lookupRecord,
1106 lookup_context);
1109 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const
1111 TRACE_COLLECT_GLYPHS (this);
1112 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
1113 context_collect_glyphs_lookup (c,
1114 inputCount, input,
1115 lookupCount, lookupRecord,
1116 lookup_context);
1119 inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
1121 TRACE_WOULD_APPLY (this);
1122 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
1123 return TRACE_RETURN (context_would_apply_lookup (c, inputCount, input, lookupCount, lookupRecord, lookup_context));
1126 inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
1128 TRACE_APPLY (this);
1129 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0));
1130 return TRACE_RETURN (context_apply_lookup (c, inputCount, input, lookupCount, lookupRecord, lookup_context));
1133 public:
1134 inline bool sanitize (hb_sanitize_context_t *c) {
1135 TRACE_SANITIZE (this);
1136 return inputCount.sanitize (c)
1137 && lookupCount.sanitize (c)
1138 && c->check_range (input,
1139 input[0].static_size * inputCount
1140 + lookupRecordX[0].static_size * lookupCount);
1143 protected:
1144 USHORT inputCount; /* Total number of glyphs in input
1145 * glyph sequence--includes the first
1146 * glyph */
1147 USHORT lookupCount; /* Number of LookupRecords */
1148 USHORT input[VAR]; /* Array of match inputs--start with
1149 * second glyph */
1150 LookupRecord lookupRecordX[VAR]; /* Array of LookupRecords--in
1151 * design order */
1152 public:
1153 DEFINE_SIZE_ARRAY2 (4, input, lookupRecordX);
1156 struct RuleSet
1158 inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
1160 TRACE_CLOSURE (this);
1161 unsigned int num_rules = rule.len;
1162 for (unsigned int i = 0; i < num_rules; i++)
1163 (this+rule[i]).closure (c, lookup_context);
1166 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const
1168 TRACE_COLLECT_GLYPHS (this);
1169 unsigned int num_rules = rule.len;
1170 for (unsigned int i = 0; i < num_rules; i++)
1171 (this+rule[i]).collect_glyphs (c, lookup_context);
1174 inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
1176 TRACE_WOULD_APPLY (this);
1177 unsigned int num_rules = rule.len;
1178 for (unsigned int i = 0; i < num_rules; i++)
1180 if ((this+rule[i]).would_apply (c, lookup_context))
1181 return TRACE_RETURN (true);
1183 return TRACE_RETURN (false);
1186 inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const
1188 TRACE_APPLY (this);
1189 unsigned int num_rules = rule.len;
1190 for (unsigned int i = 0; i < num_rules; i++)
1192 if ((this+rule[i]).apply (c, lookup_context))
1193 return TRACE_RETURN (true);
1195 return TRACE_RETURN (false);
1198 inline bool sanitize (hb_sanitize_context_t *c) {
1199 TRACE_SANITIZE (this);
1200 return TRACE_RETURN (rule.sanitize (c, this));
1203 protected:
1204 OffsetArrayOf<Rule>
1205 rule; /* Array of Rule tables
1206 * ordered by preference */
1207 public:
1208 DEFINE_SIZE_ARRAY (2, rule);
1212 struct ContextFormat1
1214 inline void closure (hb_closure_context_t *c) const
1216 TRACE_CLOSURE (this);
1218 const Coverage &cov = (this+coverage);
1220 struct ContextClosureLookupContext lookup_context = {
1221 {intersects_glyph},
1222 NULL
1225 unsigned int count = ruleSet.len;
1226 for (unsigned int i = 0; i < count; i++)
1227 if (cov.intersects_coverage (c->glyphs, i)) {
1228 const RuleSet &rule_set = this+ruleSet[i];
1229 rule_set.closure (c, lookup_context);
1233 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1235 TRACE_COLLECT_GLYPHS (this);
1236 (this+coverage).add_coverage (c->input);
1238 struct ContextCollectGlyphsLookupContext lookup_context = {
1239 {collect_glyph},
1240 NULL
1243 unsigned int count = ruleSet.len;
1244 for (unsigned int i = 0; i < count; i++)
1245 (this+ruleSet[i]).collect_glyphs (c, lookup_context);
1248 inline bool would_apply (hb_would_apply_context_t *c) const
1250 TRACE_WOULD_APPLY (this);
1252 const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
1253 struct ContextApplyLookupContext lookup_context = {
1254 {match_glyph},
1255 NULL
1257 return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
1260 inline const Coverage &get_coverage (void) const
1262 return this+coverage;
1265 inline bool apply (hb_apply_context_t *c) const
1267 TRACE_APPLY (this);
1268 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
1269 if (likely (index == NOT_COVERED))
1270 return TRACE_RETURN (false);
1272 const RuleSet &rule_set = this+ruleSet[index];
1273 struct ContextApplyLookupContext lookup_context = {
1274 {match_glyph},
1275 NULL
1277 return TRACE_RETURN (rule_set.apply (c, lookup_context));
1280 inline bool sanitize (hb_sanitize_context_t *c) {
1281 TRACE_SANITIZE (this);
1282 return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
1285 protected:
1286 USHORT format; /* Format identifier--format = 1 */
1287 OffsetTo<Coverage>
1288 coverage; /* Offset to Coverage table--from
1289 * beginning of table */
1290 OffsetArrayOf<RuleSet>
1291 ruleSet; /* Array of RuleSet tables
1292 * ordered by Coverage Index */
1293 public:
1294 DEFINE_SIZE_ARRAY (6, ruleSet);
1298 struct ContextFormat2
1300 inline void closure (hb_closure_context_t *c) const
1302 TRACE_CLOSURE (this);
1303 if (!(this+coverage).intersects (c->glyphs))
1304 return;
1306 const ClassDef &class_def = this+classDef;
1308 struct ContextClosureLookupContext lookup_context = {
1309 {intersects_class},
1310 &class_def
1313 unsigned int count = ruleSet.len;
1314 for (unsigned int i = 0; i < count; i++)
1315 if (class_def.intersects_class (c->glyphs, i)) {
1316 const RuleSet &rule_set = this+ruleSet[i];
1317 rule_set.closure (c, lookup_context);
1321 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1323 TRACE_COLLECT_GLYPHS (this);
1324 (this+coverage).add_coverage (c->input);
1326 const ClassDef &class_def = this+classDef;
1327 struct ContextCollectGlyphsLookupContext lookup_context = {
1328 {collect_class},
1329 &class_def
1332 unsigned int count = ruleSet.len;
1333 for (unsigned int i = 0; i < count; i++)
1334 (this+ruleSet[i]).collect_glyphs (c, lookup_context);
1337 inline bool would_apply (hb_would_apply_context_t *c) const
1339 TRACE_WOULD_APPLY (this);
1341 const ClassDef &class_def = this+classDef;
1342 unsigned int index = class_def.get_class (c->glyphs[0]);
1343 const RuleSet &rule_set = this+ruleSet[index];
1344 struct ContextApplyLookupContext lookup_context = {
1345 {match_class},
1346 &class_def
1348 return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
1351 inline const Coverage &get_coverage (void) const
1353 return this+coverage;
1356 inline bool apply (hb_apply_context_t *c) const
1358 TRACE_APPLY (this);
1359 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
1360 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
1362 const ClassDef &class_def = this+classDef;
1363 index = class_def.get_class (c->buffer->cur().codepoint);
1364 const RuleSet &rule_set = this+ruleSet[index];
1365 struct ContextApplyLookupContext lookup_context = {
1366 {match_class},
1367 &class_def
1369 return TRACE_RETURN (rule_set.apply (c, lookup_context));
1372 inline bool sanitize (hb_sanitize_context_t *c) {
1373 TRACE_SANITIZE (this);
1374 return TRACE_RETURN (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
1377 protected:
1378 USHORT format; /* Format identifier--format = 2 */
1379 OffsetTo<Coverage>
1380 coverage; /* Offset to Coverage table--from
1381 * beginning of table */
1382 OffsetTo<ClassDef>
1383 classDef; /* Offset to glyph ClassDef table--from
1384 * beginning of table */
1385 OffsetArrayOf<RuleSet>
1386 ruleSet; /* Array of RuleSet tables
1387 * ordered by class */
1388 public:
1389 DEFINE_SIZE_ARRAY (8, ruleSet);
1393 struct ContextFormat3
1395 inline void closure (hb_closure_context_t *c) const
1397 TRACE_CLOSURE (this);
1398 if (!(this+coverage[0]).intersects (c->glyphs))
1399 return;
1401 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
1402 struct ContextClosureLookupContext lookup_context = {
1403 {intersects_coverage},
1404 this
1406 context_closure_lookup (c,
1407 glyphCount, (const USHORT *) (coverage + 1),
1408 lookupCount, lookupRecord,
1409 lookup_context);
1412 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1414 TRACE_COLLECT_GLYPHS (this);
1415 (this+coverage[0]).add_coverage (c->input);
1417 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
1418 struct ContextCollectGlyphsLookupContext lookup_context = {
1419 {collect_coverage},
1420 this
1423 context_collect_glyphs_lookup (c,
1424 glyphCount, (const USHORT *) (coverage + 1),
1425 lookupCount, lookupRecord,
1426 lookup_context);
1429 inline bool would_apply (hb_would_apply_context_t *c) const
1431 TRACE_WOULD_APPLY (this);
1433 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
1434 struct ContextApplyLookupContext lookup_context = {
1435 {match_coverage},
1436 this
1438 return TRACE_RETURN (context_would_apply_lookup (c, glyphCount, (const USHORT *) (coverage + 1), lookupCount, lookupRecord, lookup_context));
1441 inline const Coverage &get_coverage (void) const
1443 return this+coverage[0];
1446 inline bool apply (hb_apply_context_t *c) const
1448 TRACE_APPLY (this);
1449 unsigned int index = (this+coverage[0]).get_coverage (c->buffer->cur().codepoint);
1450 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
1452 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount);
1453 struct ContextApplyLookupContext lookup_context = {
1454 {match_coverage},
1455 this
1457 return TRACE_RETURN (context_apply_lookup (c, glyphCount, (const USHORT *) (coverage + 1), lookupCount, lookupRecord, lookup_context));
1460 inline bool sanitize (hb_sanitize_context_t *c) {
1461 TRACE_SANITIZE (this);
1462 if (!c->check_struct (this)) return TRACE_RETURN (false);
1463 unsigned int count = glyphCount;
1464 if (!c->check_array (coverage, coverage[0].static_size, count)) return TRACE_RETURN (false);
1465 for (unsigned int i = 0; i < count; i++)
1466 if (!coverage[i].sanitize (c, this)) return TRACE_RETURN (false);
1467 LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * count);
1468 return TRACE_RETURN (c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount));
1471 protected:
1472 USHORT format; /* Format identifier--format = 3 */
1473 USHORT glyphCount; /* Number of glyphs in the input glyph
1474 * sequence */
1475 USHORT lookupCount; /* Number of LookupRecords */
1476 OffsetTo<Coverage>
1477 coverage[VAR]; /* Array of offsets to Coverage
1478 * table in glyph sequence order */
1479 LookupRecord lookupRecordX[VAR]; /* Array of LookupRecords--in
1480 * design order */
1481 public:
1482 DEFINE_SIZE_ARRAY2 (6, coverage, lookupRecordX);
1485 struct Context
1487 template <typename context_t>
1488 inline typename context_t::return_t dispatch (context_t *c) const
1490 TRACE_DISPATCH (this);
1491 switch (u.format) {
1492 case 1: return TRACE_RETURN (c->dispatch (u.format1));
1493 case 2: return TRACE_RETURN (c->dispatch (u.format2));
1494 case 3: return TRACE_RETURN (c->dispatch (u.format3));
1495 default:return TRACE_RETURN (c->default_return_value ());
1499 inline bool sanitize (hb_sanitize_context_t *c) {
1500 TRACE_SANITIZE (this);
1501 if (!u.format.sanitize (c)) return TRACE_RETURN (false);
1502 switch (u.format) {
1503 case 1: return TRACE_RETURN (u.format1.sanitize (c));
1504 case 2: return TRACE_RETURN (u.format2.sanitize (c));
1505 case 3: return TRACE_RETURN (u.format3.sanitize (c));
1506 default:return TRACE_RETURN (true);
1510 protected:
1511 union {
1512 USHORT format; /* Format identifier */
1513 ContextFormat1 format1;
1514 ContextFormat2 format2;
1515 ContextFormat3 format3;
1516 } u;
1520 /* Chaining Contextual lookups */
1522 struct ChainContextClosureLookupContext
1524 ContextClosureFuncs funcs;
1525 const void *intersects_data[3];
1528 struct ChainContextCollectGlyphsLookupContext
1530 ContextCollectGlyphsFuncs funcs;
1531 const void *collect_data[3];
1534 struct ChainContextApplyLookupContext
1536 ContextApplyFuncs funcs;
1537 const void *match_data[3];
1540 static inline void chain_context_closure_lookup (hb_closure_context_t *c,
1541 unsigned int backtrackCount,
1542 const USHORT backtrack[],
1543 unsigned int inputCount, /* Including the first glyph (not matched) */
1544 const USHORT input[], /* Array of input values--start with second glyph */
1545 unsigned int lookaheadCount,
1546 const USHORT lookahead[],
1547 unsigned int lookupCount,
1548 const LookupRecord lookupRecord[],
1549 ChainContextClosureLookupContext &lookup_context)
1551 if (intersects_array (c,
1552 backtrackCount, backtrack,
1553 lookup_context.funcs.intersects, lookup_context.intersects_data[0])
1554 && intersects_array (c,
1555 inputCount ? inputCount - 1 : 0, input,
1556 lookup_context.funcs.intersects, lookup_context.intersects_data[1])
1557 && intersects_array (c,
1558 lookaheadCount, lookahead,
1559 lookup_context.funcs.intersects, lookup_context.intersects_data[2]))
1560 recurse_lookups (c,
1561 lookupCount, lookupRecord);
1564 static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
1565 unsigned int backtrackCount,
1566 const USHORT backtrack[],
1567 unsigned int inputCount, /* Including the first glyph (not matched) */
1568 const USHORT input[], /* Array of input values--start with second glyph */
1569 unsigned int lookaheadCount,
1570 const USHORT lookahead[],
1571 unsigned int lookupCount,
1572 const LookupRecord lookupRecord[],
1573 ChainContextCollectGlyphsLookupContext &lookup_context)
1575 collect_array (c, c->before,
1576 backtrackCount, backtrack,
1577 lookup_context.funcs.collect, lookup_context.collect_data[0]);
1578 collect_array (c, c->input,
1579 inputCount ? inputCount - 1 : 0, input,
1580 lookup_context.funcs.collect, lookup_context.collect_data[1]);
1581 collect_array (c, c->after,
1582 lookaheadCount, lookahead,
1583 lookup_context.funcs.collect, lookup_context.collect_data[2]);
1584 recurse_lookups (c,
1585 lookupCount, lookupRecord);
1588 static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c,
1589 unsigned int backtrackCount,
1590 const USHORT backtrack[] HB_UNUSED,
1591 unsigned int inputCount, /* Including the first glyph (not matched) */
1592 const USHORT input[], /* Array of input values--start with second glyph */
1593 unsigned int lookaheadCount,
1594 const USHORT lookahead[] HB_UNUSED,
1595 unsigned int lookupCount HB_UNUSED,
1596 const LookupRecord lookupRecord[] HB_UNUSED,
1597 ChainContextApplyLookupContext &lookup_context)
1599 return (c->zero_context ? !backtrackCount && !lookaheadCount : true)
1600 && would_match_input (c,
1601 inputCount, input,
1602 lookup_context.funcs.match, lookup_context.match_data[1]);
1605 static inline bool chain_context_apply_lookup (hb_apply_context_t *c,
1606 unsigned int backtrackCount,
1607 const USHORT backtrack[],
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[],
1612 unsigned int lookupCount,
1613 const LookupRecord lookupRecord[],
1614 ChainContextApplyLookupContext &lookup_context)
1616 unsigned int lookahead_offset = 0;
1617 return match_input (c,
1618 inputCount, input,
1619 lookup_context.funcs.match, lookup_context.match_data[1],
1620 &lookahead_offset)
1621 && match_backtrack (c,
1622 backtrackCount, backtrack,
1623 lookup_context.funcs.match, lookup_context.match_data[0])
1624 && match_lookahead (c,
1625 lookaheadCount, lookahead,
1626 lookup_context.funcs.match, lookup_context.match_data[2],
1627 lookahead_offset)
1628 && apply_lookup (c,
1629 inputCount, input,
1630 lookup_context.funcs.match, lookup_context.match_data[1],
1631 lookupCount, lookupRecord);
1634 struct ChainRule
1636 inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
1638 TRACE_CLOSURE (this);
1639 const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
1640 const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
1641 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1642 chain_context_closure_lookup (c,
1643 backtrack.len, backtrack.array,
1644 input.len, input.array,
1645 lookahead.len, lookahead.array,
1646 lookup.len, lookup.array,
1647 lookup_context);
1650 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
1652 TRACE_COLLECT_GLYPHS (this);
1653 const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
1654 const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
1655 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1656 chain_context_collect_glyphs_lookup (c,
1657 backtrack.len, backtrack.array,
1658 input.len, input.array,
1659 lookahead.len, lookahead.array,
1660 lookup.len, lookup.array,
1661 lookup_context);
1664 inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
1666 TRACE_WOULD_APPLY (this);
1667 const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
1668 const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
1669 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1670 return TRACE_RETURN (chain_context_would_apply_lookup (c,
1671 backtrack.len, backtrack.array,
1672 input.len, input.array,
1673 lookahead.len, lookahead.array, lookup.len,
1674 lookup.array, lookup_context));
1677 inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
1679 TRACE_APPLY (this);
1680 const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
1681 const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
1682 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1683 return TRACE_RETURN (chain_context_apply_lookup (c,
1684 backtrack.len, backtrack.array,
1685 input.len, input.array,
1686 lookahead.len, lookahead.array, lookup.len,
1687 lookup.array, lookup_context));
1690 inline bool sanitize (hb_sanitize_context_t *c) {
1691 TRACE_SANITIZE (this);
1692 if (!backtrack.sanitize (c)) return TRACE_RETURN (false);
1693 HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
1694 if (!input.sanitize (c)) return TRACE_RETURN (false);
1695 ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
1696 if (!lookahead.sanitize (c)) return TRACE_RETURN (false);
1697 ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1698 return TRACE_RETURN (lookup.sanitize (c));
1701 protected:
1702 ArrayOf<USHORT>
1703 backtrack; /* Array of backtracking values
1704 * (to be matched before the input
1705 * sequence) */
1706 HeadlessArrayOf<USHORT>
1707 inputX; /* Array of input values (start with
1708 * second glyph) */
1709 ArrayOf<USHORT>
1710 lookaheadX; /* Array of lookahead values's (to be
1711 * matched after the input sequence) */
1712 ArrayOf<LookupRecord>
1713 lookupX; /* Array of LookupRecords--in
1714 * design order) */
1715 public:
1716 DEFINE_SIZE_MIN (8);
1719 struct ChainRuleSet
1721 inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
1723 TRACE_CLOSURE (this);
1724 unsigned int num_rules = rule.len;
1725 for (unsigned int i = 0; i < num_rules; i++)
1726 (this+rule[i]).closure (c, lookup_context);
1729 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
1731 TRACE_COLLECT_GLYPHS (this);
1732 unsigned int num_rules = rule.len;
1733 for (unsigned int i = 0; i < num_rules; i++)
1734 (this+rule[i]).collect_glyphs (c, lookup_context);
1737 inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
1739 TRACE_WOULD_APPLY (this);
1740 unsigned int num_rules = rule.len;
1741 for (unsigned int i = 0; i < num_rules; i++)
1742 if ((this+rule[i]).would_apply (c, lookup_context))
1743 return TRACE_RETURN (true);
1745 return TRACE_RETURN (false);
1748 inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
1750 TRACE_APPLY (this);
1751 unsigned int num_rules = rule.len;
1752 for (unsigned int i = 0; i < num_rules; i++)
1753 if ((this+rule[i]).apply (c, lookup_context))
1754 return TRACE_RETURN (true);
1756 return TRACE_RETURN (false);
1759 inline bool sanitize (hb_sanitize_context_t *c) {
1760 TRACE_SANITIZE (this);
1761 return TRACE_RETURN (rule.sanitize (c, this));
1764 protected:
1765 OffsetArrayOf<ChainRule>
1766 rule; /* Array of ChainRule tables
1767 * ordered by preference */
1768 public:
1769 DEFINE_SIZE_ARRAY (2, rule);
1772 struct ChainContextFormat1
1774 inline void closure (hb_closure_context_t *c) const
1776 TRACE_CLOSURE (this);
1777 const Coverage &cov = (this+coverage);
1779 struct ChainContextClosureLookupContext lookup_context = {
1780 {intersects_glyph},
1781 {NULL, NULL, NULL}
1784 unsigned int count = ruleSet.len;
1785 for (unsigned int i = 0; i < count; i++)
1786 if (cov.intersects_coverage (c->glyphs, i)) {
1787 const ChainRuleSet &rule_set = this+ruleSet[i];
1788 rule_set.closure (c, lookup_context);
1792 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1794 TRACE_COLLECT_GLYPHS (this);
1795 (this+coverage).add_coverage (c->input);
1797 struct ChainContextCollectGlyphsLookupContext lookup_context = {
1798 {collect_glyph},
1799 {NULL, NULL, NULL}
1802 unsigned int count = ruleSet.len;
1803 for (unsigned int i = 0; i < count; i++)
1804 (this+ruleSet[i]).collect_glyphs (c, lookup_context);
1807 inline bool would_apply (hb_would_apply_context_t *c) const
1809 TRACE_WOULD_APPLY (this);
1811 const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
1812 struct ChainContextApplyLookupContext lookup_context = {
1813 {match_glyph},
1814 {NULL, NULL, NULL}
1816 return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
1819 inline const Coverage &get_coverage (void) const
1821 return this+coverage;
1824 inline bool apply (hb_apply_context_t *c) const
1826 TRACE_APPLY (this);
1827 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
1828 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
1830 const ChainRuleSet &rule_set = this+ruleSet[index];
1831 struct ChainContextApplyLookupContext lookup_context = {
1832 {match_glyph},
1833 {NULL, NULL, NULL}
1835 return TRACE_RETURN (rule_set.apply (c, lookup_context));
1838 inline bool sanitize (hb_sanitize_context_t *c) {
1839 TRACE_SANITIZE (this);
1840 return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
1843 protected:
1844 USHORT format; /* Format identifier--format = 1 */
1845 OffsetTo<Coverage>
1846 coverage; /* Offset to Coverage table--from
1847 * beginning of table */
1848 OffsetArrayOf<ChainRuleSet>
1849 ruleSet; /* Array of ChainRuleSet tables
1850 * ordered by Coverage Index */
1851 public:
1852 DEFINE_SIZE_ARRAY (6, ruleSet);
1855 struct ChainContextFormat2
1857 inline void closure (hb_closure_context_t *c) const
1859 TRACE_CLOSURE (this);
1860 if (!(this+coverage).intersects (c->glyphs))
1861 return;
1863 const ClassDef &backtrack_class_def = this+backtrackClassDef;
1864 const ClassDef &input_class_def = this+inputClassDef;
1865 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
1867 struct ChainContextClosureLookupContext lookup_context = {
1868 {intersects_class},
1869 {&backtrack_class_def,
1870 &input_class_def,
1871 &lookahead_class_def}
1874 unsigned int count = ruleSet.len;
1875 for (unsigned int i = 0; i < count; i++)
1876 if (input_class_def.intersects_class (c->glyphs, i)) {
1877 const ChainRuleSet &rule_set = this+ruleSet[i];
1878 rule_set.closure (c, lookup_context);
1882 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
1884 TRACE_COLLECT_GLYPHS (this);
1885 (this+coverage).add_coverage (c->input);
1887 const ClassDef &backtrack_class_def = this+backtrackClassDef;
1888 const ClassDef &input_class_def = this+inputClassDef;
1889 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
1891 struct ChainContextCollectGlyphsLookupContext lookup_context = {
1892 {collect_class},
1893 {&backtrack_class_def,
1894 &input_class_def,
1895 &lookahead_class_def}
1898 unsigned int count = ruleSet.len;
1899 for (unsigned int i = 0; i < count; i++)
1900 (this+ruleSet[i]).collect_glyphs (c, lookup_context);
1903 inline bool would_apply (hb_would_apply_context_t *c) const
1905 TRACE_WOULD_APPLY (this);
1907 const ClassDef &backtrack_class_def = this+backtrackClassDef;
1908 const ClassDef &input_class_def = this+inputClassDef;
1909 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
1911 unsigned int index = input_class_def.get_class (c->glyphs[0]);
1912 const ChainRuleSet &rule_set = this+ruleSet[index];
1913 struct ChainContextApplyLookupContext lookup_context = {
1914 {match_class},
1915 {&backtrack_class_def,
1916 &input_class_def,
1917 &lookahead_class_def}
1919 return TRACE_RETURN (rule_set.would_apply (c, lookup_context));
1922 inline const Coverage &get_coverage (void) const
1924 return this+coverage;
1927 inline bool apply (hb_apply_context_t *c) const
1929 TRACE_APPLY (this);
1930 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
1931 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
1933 const ClassDef &backtrack_class_def = this+backtrackClassDef;
1934 const ClassDef &input_class_def = this+inputClassDef;
1935 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
1937 index = input_class_def.get_class (c->buffer->cur().codepoint);
1938 const ChainRuleSet &rule_set = this+ruleSet[index];
1939 struct ChainContextApplyLookupContext lookup_context = {
1940 {match_class},
1941 {&backtrack_class_def,
1942 &input_class_def,
1943 &lookahead_class_def}
1945 return TRACE_RETURN (rule_set.apply (c, lookup_context));
1948 inline bool sanitize (hb_sanitize_context_t *c) {
1949 TRACE_SANITIZE (this);
1950 return TRACE_RETURN (coverage.sanitize (c, this) && backtrackClassDef.sanitize (c, this) &&
1951 inputClassDef.sanitize (c, this) && lookaheadClassDef.sanitize (c, this) &&
1952 ruleSet.sanitize (c, this));
1955 protected:
1956 USHORT format; /* Format identifier--format = 2 */
1957 OffsetTo<Coverage>
1958 coverage; /* Offset to Coverage table--from
1959 * beginning of table */
1960 OffsetTo<ClassDef>
1961 backtrackClassDef; /* Offset to glyph ClassDef table
1962 * containing backtrack sequence
1963 * data--from beginning of table */
1964 OffsetTo<ClassDef>
1965 inputClassDef; /* Offset to glyph ClassDef
1966 * table containing input sequence
1967 * data--from beginning of table */
1968 OffsetTo<ClassDef>
1969 lookaheadClassDef; /* Offset to glyph ClassDef table
1970 * containing lookahead sequence
1971 * data--from beginning of table */
1972 OffsetArrayOf<ChainRuleSet>
1973 ruleSet; /* Array of ChainRuleSet tables
1974 * ordered by class */
1975 public:
1976 DEFINE_SIZE_ARRAY (12, ruleSet);
1979 struct ChainContextFormat3
1981 inline void closure (hb_closure_context_t *c) const
1983 TRACE_CLOSURE (this);
1984 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
1986 if (!(this+input[0]).intersects (c->glyphs))
1987 return;
1989 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
1990 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1991 struct ChainContextClosureLookupContext lookup_context = {
1992 {intersects_coverage},
1993 {this, this, this}
1995 chain_context_closure_lookup (c,
1996 backtrack.len, (const USHORT *) backtrack.array,
1997 input.len, (const USHORT *) input.array + 1,
1998 lookahead.len, (const USHORT *) lookahead.array,
1999 lookup.len, lookup.array,
2000 lookup_context);
2003 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
2005 TRACE_COLLECT_GLYPHS (this);
2006 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2008 (this+input[0]).add_coverage (c->input);
2010 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2011 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2012 struct ChainContextCollectGlyphsLookupContext lookup_context = {
2013 {collect_coverage},
2014 {this, this, this}
2016 chain_context_collect_glyphs_lookup (c,
2017 backtrack.len, (const USHORT *) backtrack.array,
2018 input.len, (const USHORT *) input.array + 1,
2019 lookahead.len, (const USHORT *) lookahead.array,
2020 lookup.len, lookup.array,
2021 lookup_context);
2024 inline bool would_apply (hb_would_apply_context_t *c) const
2026 TRACE_WOULD_APPLY (this);
2028 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2029 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2030 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2031 struct ChainContextApplyLookupContext lookup_context = {
2032 {match_coverage},
2033 {this, this, this}
2035 return TRACE_RETURN (chain_context_would_apply_lookup (c,
2036 backtrack.len, (const USHORT *) backtrack.array,
2037 input.len, (const USHORT *) input.array + 1,
2038 lookahead.len, (const USHORT *) lookahead.array,
2039 lookup.len, lookup.array, lookup_context));
2042 inline const Coverage &get_coverage (void) const
2044 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2045 return this+input[0];
2048 inline bool apply (hb_apply_context_t *c) const
2050 TRACE_APPLY (this);
2051 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2053 unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint);
2054 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
2056 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2057 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2058 struct ChainContextApplyLookupContext lookup_context = {
2059 {match_coverage},
2060 {this, this, this}
2062 return TRACE_RETURN (chain_context_apply_lookup (c,
2063 backtrack.len, (const USHORT *) backtrack.array,
2064 input.len, (const USHORT *) input.array + 1,
2065 lookahead.len, (const USHORT *) lookahead.array,
2066 lookup.len, lookup.array, lookup_context));
2069 inline bool sanitize (hb_sanitize_context_t *c) {
2070 TRACE_SANITIZE (this);
2071 if (!backtrack.sanitize (c, this)) return TRACE_RETURN (false);
2072 OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2073 if (!input.sanitize (c, this)) return TRACE_RETURN (false);
2074 OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2075 if (!lookahead.sanitize (c, this)) return TRACE_RETURN (false);
2076 ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2077 return TRACE_RETURN (lookup.sanitize (c));
2080 protected:
2081 USHORT format; /* Format identifier--format = 3 */
2082 OffsetArrayOf<Coverage>
2083 backtrack; /* Array of coverage tables
2084 * in backtracking sequence, in glyph
2085 * sequence order */
2086 OffsetArrayOf<Coverage>
2087 inputX ; /* Array of coverage
2088 * tables in input sequence, in glyph
2089 * sequence order */
2090 OffsetArrayOf<Coverage>
2091 lookaheadX; /* Array of coverage tables
2092 * in lookahead sequence, in glyph
2093 * sequence order */
2094 ArrayOf<LookupRecord>
2095 lookupX; /* Array of LookupRecords--in
2096 * design order) */
2097 public:
2098 DEFINE_SIZE_MIN (10);
2101 struct ChainContext
2103 template <typename context_t>
2104 inline typename context_t::return_t dispatch (context_t *c) const
2106 TRACE_DISPATCH (this);
2107 switch (u.format) {
2108 case 1: return TRACE_RETURN (c->dispatch (u.format1));
2109 case 2: return TRACE_RETURN (c->dispatch (u.format2));
2110 case 3: return TRACE_RETURN (c->dispatch (u.format3));
2111 default:return TRACE_RETURN (c->default_return_value ());
2115 inline bool sanitize (hb_sanitize_context_t *c) {
2116 TRACE_SANITIZE (this);
2117 if (!u.format.sanitize (c)) return TRACE_RETURN (false);
2118 switch (u.format) {
2119 case 1: return TRACE_RETURN (u.format1.sanitize (c));
2120 case 2: return TRACE_RETURN (u.format2.sanitize (c));
2121 case 3: return TRACE_RETURN (u.format3.sanitize (c));
2122 default:return TRACE_RETURN (true);
2126 protected:
2127 union {
2128 USHORT format; /* Format identifier */
2129 ChainContextFormat1 format1;
2130 ChainContextFormat2 format2;
2131 ChainContextFormat3 format3;
2132 } u;
2136 struct ExtensionFormat1
2138 inline unsigned int get_type (void) const { return extensionLookupType; }
2139 inline unsigned int get_offset (void) const { return extensionOffset; }
2141 inline bool sanitize (hb_sanitize_context_t *c) {
2142 TRACE_SANITIZE (this);
2143 return TRACE_RETURN (c->check_struct (this));
2146 protected:
2147 USHORT format; /* Format identifier. Set to 1. */
2148 USHORT extensionLookupType; /* Lookup type of subtable referenced
2149 * by ExtensionOffset (i.e. the
2150 * extension subtable). */
2151 ULONG extensionOffset; /* Offset to the extension subtable,
2152 * of lookup type subtable. */
2153 public:
2154 DEFINE_SIZE_STATIC (8);
2157 template <typename T>
2158 struct Extension
2160 inline unsigned int get_type (void) const
2162 switch (u.format) {
2163 case 1: return u.format1.get_type ();
2164 default:return 0;
2167 inline unsigned int get_offset (void) const
2169 switch (u.format) {
2170 case 1: return u.format1.get_offset ();
2171 default:return 0;
2175 template <typename X>
2176 inline const X& get_subtable (void) const
2178 unsigned int offset = get_offset ();
2179 if (unlikely (!offset)) return Null(typename T::LookupSubTable);
2180 return StructAtOffset<typename T::LookupSubTable> (this, offset);
2183 template <typename context_t>
2184 inline typename context_t::return_t dispatch (context_t *c) const
2186 return get_subtable<typename T::LookupSubTable> ().dispatch (c, get_type ());
2189 inline bool sanitize_self (hb_sanitize_context_t *c) {
2190 TRACE_SANITIZE (this);
2191 if (!u.format.sanitize (c)) return TRACE_RETURN (false);
2192 switch (u.format) {
2193 case 1: return TRACE_RETURN (u.format1.sanitize (c));
2194 default:return TRACE_RETURN (true);
2198 inline bool sanitize (hb_sanitize_context_t *c) {
2199 TRACE_SANITIZE (this);
2200 if (!sanitize_self (c)) return TRACE_RETURN (false);
2201 unsigned int offset = get_offset ();
2202 if (unlikely (!offset)) return TRACE_RETURN (true);
2203 return TRACE_RETURN (StructAtOffset<typename T::LookupSubTable> (this, offset).sanitize (c, get_type ()));
2206 protected:
2207 union {
2208 USHORT format; /* Format identifier */
2209 ExtensionFormat1 format1;
2210 } u;
2215 * GSUB/GPOS Common
2218 struct GSUBGPOS
2220 static const hb_tag_t GSUBTag = HB_OT_TAG_GSUB;
2221 static const hb_tag_t GPOSTag = HB_OT_TAG_GPOS;
2223 inline unsigned int get_script_count (void) const
2224 { return (this+scriptList).len; }
2225 inline const Tag& get_script_tag (unsigned int i) const
2226 { return (this+scriptList).get_tag (i); }
2227 inline unsigned int get_script_tags (unsigned int start_offset,
2228 unsigned int *script_count /* IN/OUT */,
2229 hb_tag_t *script_tags /* OUT */) const
2230 { return (this+scriptList).get_tags (start_offset, script_count, script_tags); }
2231 inline const Script& get_script (unsigned int i) const
2232 { return (this+scriptList)[i]; }
2233 inline bool find_script_index (hb_tag_t tag, unsigned int *index) const
2234 { return (this+scriptList).find_index (tag, index); }
2236 inline unsigned int get_feature_count (void) const
2237 { return (this+featureList).len; }
2238 inline const Tag& get_feature_tag (unsigned int i) const
2239 { return (this+featureList).get_tag (i); }
2240 inline unsigned int get_feature_tags (unsigned int start_offset,
2241 unsigned int *feature_count /* IN/OUT */,
2242 hb_tag_t *feature_tags /* OUT */) const
2243 { return (this+featureList).get_tags (start_offset, feature_count, feature_tags); }
2244 inline const Feature& get_feature (unsigned int i) const
2245 { return (this+featureList)[i]; }
2246 inline bool find_feature_index (hb_tag_t tag, unsigned int *index) const
2247 { return (this+featureList).find_index (tag, index); }
2249 inline unsigned int get_lookup_count (void) const
2250 { return (this+lookupList).len; }
2251 inline const Lookup& get_lookup (unsigned int i) const
2252 { return (this+lookupList)[i]; }
2254 inline bool sanitize (hb_sanitize_context_t *c) {
2255 TRACE_SANITIZE (this);
2256 return TRACE_RETURN (version.sanitize (c) && likely (version.major == 1) &&
2257 scriptList.sanitize (c, this) &&
2258 featureList.sanitize (c, this) &&
2259 lookupList.sanitize (c, this));
2262 protected:
2263 FixedVersion version; /* Version of the GSUB/GPOS table--initially set
2264 * to 0x00010000 */
2265 OffsetTo<ScriptList>
2266 scriptList; /* ScriptList table */
2267 OffsetTo<FeatureList>
2268 featureList; /* FeatureList table */
2269 OffsetTo<LookupList>
2270 lookupList; /* LookupList table */
2271 public:
2272 DEFINE_SIZE_STATIC (10);
2276 } /* namespace OT */
2279 #endif /* HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH */