1/*
2 * Copyright © 2007,2008,2009,2010 Red Hat, Inc.
3 * Copyright © 2010,2012 Google, Inc.
4 *
5 * This is part of HarfBuzz, a text shaping library.
6 *
7 * Permission is hereby granted, without written agreement and without
8 * license or royalty fees, to use, copy, modify, and distribute this
9 * software and its documentation for any purpose, provided that the
10 * above copyright notice and the following two paragraphs appear in
11 * all copies of this software.
12 *
13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
17 * DAMAGE.
18 *
19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
24 *
25 * Red Hat Author(s): Behdad Esfahbod
26 * Google Author(s): Behdad Esfahbod
27 */
28
29#ifndef HB_OT_LAYOUT_GSUBGPOS_HH
30#define HB_OT_LAYOUT_GSUBGPOS_HH
31
32#include "hb.hh"
33#include "hb-buffer.hh"
34#include "hb-map.hh"
35#include "hb-set.hh"
36#include "hb-ot-map.hh"
37#include "hb-ot-layout-common.hh"
38#include "hb-ot-layout-gdef-table.hh"
39
40
41namespace OT {
42
43
44struct hb_intersects_context_t :
45 hb_dispatch_context_t<hb_intersects_context_t, bool, 0>
46{
47 const char *get_name () { return "INTERSECTS"; }
48 template <typename T>
49 return_t dispatch (const T &obj) { return obj.intersects (this->glyphs); }
50 static return_t default_return_value () { return false; }
51 bool stop_sublookup_iteration (return_t r) const { return r; }
52
53 const hb_set_t *glyphs;
54 unsigned int debug_depth;
55
56 hb_intersects_context_t (const hb_set_t *glyphs_) :
57 glyphs (glyphs_),
58 debug_depth (0) {}
59};
60
61struct hb_closure_context_t :
62 hb_dispatch_context_t<hb_closure_context_t, hb_empty_t, 0>
63{
64 const char *get_name () { return "CLOSURE"; }
65 typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
66 template <typename T>
67 return_t dispatch (const T &obj) { obj.closure (this); return hb_empty_t (); }
68 static return_t default_return_value () { return hb_empty_t (); }
69 void recurse (unsigned int lookup_index)
70 {
71 if (unlikely (nesting_level_left == 0 || !recurse_func))
72 return;
73
74 nesting_level_left--;
75 recurse_func (this, lookup_index);
76 nesting_level_left++;
77 }
78
79 bool should_visit_lookup (unsigned int lookup_index)
80 {
81 if (is_lookup_done (lookup_index))
82 return false;
83 done_lookups->set (lookup_index, glyphs->get_population ());
84 return true;
85 }
86
87 bool is_lookup_done (unsigned int lookup_index)
88 {
89 /* Have we visited this lookup with the current set of glyphs? */
90 return done_lookups->get (lookup_index) == glyphs->get_population ();
91 }
92
93 hb_face_t *face;
94 hb_set_t *glyphs;
95 hb_set_t output[1];
96 recurse_func_t recurse_func;
97 unsigned int nesting_level_left;
98 unsigned int debug_depth;
99
100 hb_closure_context_t (hb_face_t *face_,
101 hb_set_t *glyphs_,
102 hb_map_t *done_lookups_,
103 unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
104 face (face_),
105 glyphs (glyphs_),
106 recurse_func (nullptr),
107 nesting_level_left (nesting_level_left_),
108 debug_depth (0),
109 done_lookups (done_lookups_) {}
110
111 ~hb_closure_context_t () { flush (); }
112
113 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
114
115 void flush ()
116 {
117 hb_set_union (glyphs, output);
118 hb_set_clear (output);
119 }
120
121 private:
122 hb_map_t *done_lookups;
123};
124
125
126struct hb_would_apply_context_t :
127 hb_dispatch_context_t<hb_would_apply_context_t, bool, 0>
128{
129 const char *get_name () { return "WOULD_APPLY"; }
130 template <typename T>
131 return_t dispatch (const T &obj) { return obj.would_apply (this); }
132 static return_t default_return_value () { return false; }
133 bool stop_sublookup_iteration (return_t r) const { return r; }
134
135 hb_face_t *face;
136 const hb_codepoint_t *glyphs;
137 unsigned int len;
138 bool zero_context;
139 unsigned int debug_depth;
140
141 hb_would_apply_context_t (hb_face_t *face_,
142 const hb_codepoint_t *glyphs_,
143 unsigned int len_,
144 bool zero_context_) :
145 face (face_),
146 glyphs (glyphs_),
147 len (len_),
148 zero_context (zero_context_),
149 debug_depth (0) {}
150};
151
152
153struct hb_collect_glyphs_context_t :
154 hb_dispatch_context_t<hb_collect_glyphs_context_t, hb_empty_t, 0>
155{
156 const char *get_name () { return "COLLECT_GLYPHS"; }
157 typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index);
158 template <typename T>
159 return_t dispatch (const T &obj) { obj.collect_glyphs (this); return hb_empty_t (); }
160 static return_t default_return_value () { return hb_empty_t (); }
161 void recurse (unsigned int lookup_index)
162 {
163 if (unlikely (nesting_level_left == 0 || !recurse_func))
164 return;
165
166 /* Note that GPOS sets recurse_func to nullptr already, so it doesn't get
167 * past the previous check. For GSUB, we only want to collect the output
168 * glyphs in the recursion. If output is not requested, we can go home now.
169 *
170 * Note further, that the above is not exactly correct. A recursed lookup
171 * is allowed to match input that is not matched in the context, but that's
172 * not how most fonts are built. It's possible to relax that and recurse
173 * with all sets here if it proves to be an issue.
174 */
175
176 if (output == hb_set_get_empty ())
177 return;
178
179 /* Return if new lookup was recursed to before. */
180 if (recursed_lookups->has (lookup_index))
181 return;
182
183 hb_set_t *old_before = before;
184 hb_set_t *old_input = input;
185 hb_set_t *old_after = after;
186 before = input = after = hb_set_get_empty ();
187
188 nesting_level_left--;
189 recurse_func (this, lookup_index);
190 nesting_level_left++;
191
192 before = old_before;
193 input = old_input;
194 after = old_after;
195
196 recursed_lookups->add (lookup_index);
197 }
198
199 hb_face_t *face;
200 hb_set_t *before;
201 hb_set_t *input;
202 hb_set_t *after;
203 hb_set_t *output;
204 recurse_func_t recurse_func;
205 hb_set_t *recursed_lookups;
206 unsigned int nesting_level_left;
207 unsigned int debug_depth;
208
209 hb_collect_glyphs_context_t (hb_face_t *face_,
210 hb_set_t *glyphs_before, /* OUT. May be NULL */
211 hb_set_t *glyphs_input, /* OUT. May be NULL */
212 hb_set_t *glyphs_after, /* OUT. May be NULL */
213 hb_set_t *glyphs_output, /* OUT. May be NULL */
214 unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
215 face (face_),
216 before (glyphs_before ? glyphs_before : hb_set_get_empty ()),
217 input (glyphs_input ? glyphs_input : hb_set_get_empty ()),
218 after (glyphs_after ? glyphs_after : hb_set_get_empty ()),
219 output (glyphs_output ? glyphs_output : hb_set_get_empty ()),
220 recurse_func (nullptr),
221 recursed_lookups (hb_set_create ()),
222 nesting_level_left (nesting_level_left_),
223 debug_depth (0) {}
224 ~hb_collect_glyphs_context_t () { hb_set_destroy (recursed_lookups); }
225
226 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
227};
228
229
230
231template <typename set_t>
232struct hb_add_coverage_context_t :
233 hb_dispatch_context_t<hb_add_coverage_context_t<set_t>, const Coverage &, HB_DEBUG_GET_COVERAGE>
234{
235 const char *get_name () { return "GET_COVERAGE"; }
236 typedef const Coverage &return_t;
237 template <typename T>
238 return_t dispatch (const T &obj) { return obj.get_coverage (); }
239 static return_t default_return_value () { return Null(Coverage); }
240 bool stop_sublookup_iteration (return_t r) const
241 {
242 r.add_coverage (set);
243 return false;
244 }
245
246 hb_add_coverage_context_t (set_t *set_) :
247 set (set_),
248 debug_depth (0) {}
249
250 set_t *set;
251 unsigned int debug_depth;
252};
253
254
255struct hb_ot_apply_context_t :
256 hb_dispatch_context_t<hb_ot_apply_context_t, bool, HB_DEBUG_APPLY>
257{
258 struct matcher_t
259 {
260 matcher_t () :
261 lookup_props (0),
262 ignore_zwnj (false),
263 ignore_zwj (false),
264 mask (-1),
265#define arg1(arg) (arg) /* Remove the macro to see why it's needed! */
266 syllable arg1(0),
267#undef arg1
268 match_func (nullptr),
269 match_data (nullptr) {}
270
271 typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data);
272
273 void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; }
274 void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
275 void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
276 void set_mask (hb_mask_t mask_) { mask = mask_; }
277 void set_syllable (uint8_t syllable_) { syllable = syllable_; }
278 void set_match_func (match_func_t match_func_,
279 const void *match_data_)
280 { match_func = match_func_; match_data = match_data_; }
281
282 enum may_match_t {
283 MATCH_NO,
284 MATCH_YES,
285 MATCH_MAYBE
286 };
287
288 may_match_t may_match (const hb_glyph_info_t &info,
289 const HBUINT16 *glyph_data) const
290 {
291 if (!(info.mask & mask) ||
292 (syllable && syllable != info.syllable ()))
293 return MATCH_NO;
294
295 if (match_func)
296 return match_func (info.codepoint, *glyph_data, match_data) ? MATCH_YES : MATCH_NO;
297
298 return MATCH_MAYBE;
299 }
300
301 enum may_skip_t {
302 SKIP_NO,
303 SKIP_YES,
304 SKIP_MAYBE
305 };
306
307 may_skip_t may_skip (const hb_ot_apply_context_t *c,
308 const hb_glyph_info_t &info) const
309 {
310 if (!c->check_glyph_property (&info, lookup_props))
311 return SKIP_YES;
312
313 if (unlikely (_hb_glyph_info_is_default_ignorable_and_not_hidden (&info) &&
314 (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) &&
315 (ignore_zwj || !_hb_glyph_info_is_zwj (&info))))
316 return SKIP_MAYBE;
317
318 return SKIP_NO;
319 }
320
321 protected:
322 unsigned int lookup_props;
323 bool ignore_zwnj;
324 bool ignore_zwj;
325 hb_mask_t mask;
326 uint8_t syllable;
327 match_func_t match_func;
328 const void *match_data;
329 };
330
331 struct skipping_iterator_t
332 {
333 void init (hb_ot_apply_context_t *c_, bool context_match = false)
334 {
335 c = c_;
336 match_glyph_data = nullptr;
337 matcher.set_match_func (nullptr, nullptr);
338 matcher.set_lookup_props (c->lookup_props);
339 /* Ignore ZWNJ if we are matching GPOS, or matching GSUB context and asked to. */
340 matcher.set_ignore_zwnj (c->table_index == 1 || (context_match && c->auto_zwnj));
341 /* Ignore ZWJ if we are matching context, or asked to. */
342 matcher.set_ignore_zwj (context_match || c->auto_zwj);
343 matcher.set_mask (context_match ? -1 : c->lookup_mask);
344 }
345 void set_lookup_props (unsigned int lookup_props)
346 {
347 matcher.set_lookup_props (lookup_props);
348 }
349 void set_match_func (matcher_t::match_func_t match_func_,
350 const void *match_data_,
351 const HBUINT16 glyph_data[])
352 {
353 matcher.set_match_func (match_func_, match_data_);
354 match_glyph_data = glyph_data;
355 }
356
357 void reset (unsigned int start_index_,
358 unsigned int num_items_)
359 {
360 idx = start_index_;
361 num_items = num_items_;
362 end = c->buffer->len;
363 matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
364 }
365
366 void reject () { num_items++; match_glyph_data--; }
367
368 matcher_t::may_skip_t
369 may_skip (const hb_glyph_info_t &info) const
370 { return matcher.may_skip (c, info); }
371
372 bool next ()
373 {
374 assert (num_items > 0);
375 while (idx + num_items < end)
376 {
377 idx++;
378 const hb_glyph_info_t &info = c->buffer->info[idx];
379
380 matcher_t::may_skip_t skip = matcher.may_skip (c, info);
381 if (unlikely (skip == matcher_t::SKIP_YES))
382 continue;
383
384 matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
385 if (match == matcher_t::MATCH_YES ||
386 (match == matcher_t::MATCH_MAYBE &&
387 skip == matcher_t::SKIP_NO))
388 {
389 num_items--;
390 if (match_glyph_data) match_glyph_data++;
391 return true;
392 }
393
394 if (skip == matcher_t::SKIP_NO)
395 return false;
396 }
397 return false;
398 }
399 bool prev ()
400 {
401 assert (num_items > 0);
402 while (idx > num_items - 1)
403 {
404 idx--;
405 const hb_glyph_info_t &info = c->buffer->out_info[idx];
406
407 matcher_t::may_skip_t skip = matcher.may_skip (c, info);
408 if (unlikely (skip == matcher_t::SKIP_YES))
409 continue;
410
411 matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data);
412 if (match == matcher_t::MATCH_YES ||
413 (match == matcher_t::MATCH_MAYBE &&
414 skip == matcher_t::SKIP_NO))
415 {
416 num_items--;
417 if (match_glyph_data) match_glyph_data++;
418 return true;
419 }
420
421 if (skip == matcher_t::SKIP_NO)
422 return false;
423 }
424 return false;
425 }
426
427 unsigned int idx;
428 protected:
429 hb_ot_apply_context_t *c;
430 matcher_t matcher;
431 const HBUINT16 *match_glyph_data;
432
433 unsigned int num_items;
434 unsigned int end;
435 };
436
437
438 const char *get_name () { return "APPLY"; }
439 typedef return_t (*recurse_func_t) (hb_ot_apply_context_t *c, unsigned int lookup_index);
440 template <typename T>
441 return_t dispatch (const T &obj) { return obj.apply (this); }
442 static return_t default_return_value () { return false; }
443 bool stop_sublookup_iteration (return_t r) const { return r; }
444 return_t recurse (unsigned int sub_lookup_index)
445 {
446 if (unlikely (nesting_level_left == 0 || !recurse_func || buffer->max_ops-- <= 0))
447 return default_return_value ();
448
449 nesting_level_left--;
450 bool ret = recurse_func (this, sub_lookup_index);
451 nesting_level_left++;
452 return ret;
453 }
454
455 skipping_iterator_t iter_input, iter_context;
456
457 hb_font_t *font;
458 hb_face_t *face;
459 hb_buffer_t *buffer;
460 recurse_func_t recurse_func;
461 const GDEF &gdef;
462 const VariationStore &var_store;
463
464 hb_direction_t direction;
465 hb_mask_t lookup_mask;
466 unsigned int table_index; /* GSUB/GPOS */
467 unsigned int lookup_index;
468 unsigned int lookup_props;
469 unsigned int nesting_level_left;
470 unsigned int debug_depth;
471
472 bool has_glyph_classes;
473 bool auto_zwnj;
474 bool auto_zwj;
475 bool random;
476
477 uint32_t random_state;
478
479
480 hb_ot_apply_context_t (unsigned int table_index_,
481 hb_font_t *font_,
482 hb_buffer_t *buffer_) :
483 iter_input (), iter_context (),
484 font (font_), face (font->face), buffer (buffer_),
485 recurse_func (nullptr),
486 gdef (
487#ifndef HB_NO_OT_LAYOUT
488 *face->table.GDEF->table
489#else
490 Null(GDEF)
491#endif
492 ),
493 var_store (gdef.get_var_store ()),
494 direction (buffer_->props.direction),
495 lookup_mask (1),
496 table_index (table_index_),
497 lookup_index ((unsigned int) -1),
498 lookup_props (0),
499 nesting_level_left (HB_MAX_NESTING_LEVEL),
500 debug_depth (0),
501 has_glyph_classes (gdef.has_glyph_classes ()),
502 auto_zwnj (true),
503 auto_zwj (true),
504 random (false),
505 random_state (1) { init_iters (); }
506
507 void init_iters ()
508 {
509 iter_input.init (this, false);
510 iter_context.init (this, true);
511 }
512
513 void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; init_iters (); }
514 void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; init_iters (); }
515 void set_auto_zwnj (bool auto_zwnj_) { auto_zwnj = auto_zwnj_; init_iters (); }
516 void set_random (bool random_) { random = random_; }
517 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
518 void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; }
519 void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; init_iters (); }
520
521 uint32_t random_number ()
522 {
523 /* http://www.cplusplus.com/reference/random/minstd_rand/ */
524 random_state = random_state * 48271 % 2147483647;
525 return random_state;
526 }
527
528 bool match_properties_mark (hb_codepoint_t glyph,
529 unsigned int glyph_props,
530 unsigned int match_props) const
531 {
532 /* If using mark filtering sets, the high short of
533 * match_props has the set index.
534 */
535 if (match_props & LookupFlag::UseMarkFilteringSet)
536 return gdef.mark_set_covers (match_props >> 16, glyph);
537
538 /* The second byte of match_props has the meaning
539 * "ignore marks of attachment type different than
540 * the attachment type specified."
541 */
542 if (match_props & LookupFlag::MarkAttachmentType)
543 return (match_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);
544
545 return true;
546 }
547
548 bool check_glyph_property (const hb_glyph_info_t *info,
549 unsigned int match_props) const
550 {
551 hb_codepoint_t glyph = info->codepoint;
552 unsigned int glyph_props = _hb_glyph_info_get_glyph_props (info);
553
554 /* Not covered, if, for example, glyph class is ligature and
555 * match_props includes LookupFlags::IgnoreLigatures
556 */
557 if (glyph_props & match_props & LookupFlag::IgnoreFlags)
558 return false;
559
560 if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK))
561 return match_properties_mark (glyph, glyph_props, match_props);
562
563 return true;
564 }
565
566 void _set_glyph_props (hb_codepoint_t glyph_index,
567 unsigned int class_guess = 0,
568 bool ligature = false,
569 bool component = false) const
570 {
571 unsigned int add_in = _hb_glyph_info_get_glyph_props (&buffer->cur()) &
572 HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE;
573 add_in |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED;
574 if (ligature)
575 {
576 add_in |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED;
577 /* In the only place that the MULTIPLIED bit is used, Uniscribe
578 * seems to only care about the "last" transformation between
579 * Ligature and Multiple substitutions. Ie. if you ligate, expand,
580 * and ligate again, it forgives the multiplication and acts as
581 * if only ligation happened. As such, clear MULTIPLIED bit.
582 */
583 add_in &= ~HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
584 }
585 if (component)
586 add_in |= HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
587 if (likely (has_glyph_classes))
588 _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | gdef.get_glyph_props (glyph_index));
589 else if (class_guess)
590 _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | class_guess);
591 }
592
593 void replace_glyph (hb_codepoint_t glyph_index) const
594 {
595 _set_glyph_props (glyph_index);
596 buffer->replace_glyph (glyph_index);
597 }
598 void replace_glyph_inplace (hb_codepoint_t glyph_index) const
599 {
600 _set_glyph_props (glyph_index);
601 buffer->cur().codepoint = glyph_index;
602 }
603 void replace_glyph_with_ligature (hb_codepoint_t glyph_index,
604 unsigned int class_guess) const
605 {
606 _set_glyph_props (glyph_index, class_guess, true);
607 buffer->replace_glyph (glyph_index);
608 }
609 void output_glyph_for_component (hb_codepoint_t glyph_index,
610 unsigned int class_guess) const
611 {
612 _set_glyph_props (glyph_index, class_guess, false, true);
613 buffer->output_glyph (glyph_index);
614 }
615};
616
617
618struct hb_get_subtables_context_t :
619 hb_dispatch_context_t<hb_get_subtables_context_t, hb_empty_t, HB_DEBUG_APPLY>
620{
621 template <typename Type>
622 HB_INTERNAL static bool apply_to (const void *obj, OT::hb_ot_apply_context_t *c)
623 {
624 const Type *typed_obj = (const Type *) obj;
625 return typed_obj->apply (c);
626 }
627
628 typedef bool (*hb_apply_func_t) (const void *obj, OT::hb_ot_apply_context_t *c);
629
630 struct hb_applicable_t
631 {
632 template <typename T>
633 void init (const T &obj_, hb_apply_func_t apply_func_)
634 {
635 obj = &obj_;
636 apply_func = apply_func_;
637 digest.init ();
638 obj_.get_coverage ().add_coverage (&digest);
639 }
640
641 bool apply (OT::hb_ot_apply_context_t *c) const
642 {
643 return digest.may_have (c->buffer->cur().codepoint) && apply_func (obj, c);
644 }
645
646 private:
647 const void *obj;
648 hb_apply_func_t apply_func;
649 hb_set_digest_t digest;
650 };
651
652 typedef hb_vector_t<hb_applicable_t> array_t;
653
654 /* Dispatch interface. */
655 const char *get_name () { return "GET_SUBTABLES"; }
656 template <typename T>
657 return_t dispatch (const T &obj)
658 {
659 hb_applicable_t *entry = array.push();
660 entry->init (obj, apply_to<T>);
661 return hb_empty_t ();
662 }
663 static return_t default_return_value () { return hb_empty_t (); }
664
665 hb_get_subtables_context_t (array_t &array_) :
666 array (array_),
667 debug_depth (0) {}
668
669 array_t &array;
670 unsigned int debug_depth;
671};
672
673
674
675
676typedef bool (*intersects_func_t) (const hb_set_t *glyphs, const HBUINT16 &value, const void *data);
677typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const HBUINT16 &value, const void *data);
678typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data);
679
680struct ContextClosureFuncs
681{
682 intersects_func_t intersects;
683};
684struct ContextCollectGlyphsFuncs
685{
686 collect_glyphs_func_t collect;
687};
688struct ContextApplyFuncs
689{
690 match_func_t match;
691};
692
693
694static inline bool intersects_glyph (const hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
695{
696 return glyphs->has (value);
697}
698static inline bool intersects_class (const hb_set_t *glyphs, const HBUINT16 &value, const void *data)
699{
700 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
701 return class_def.intersects_class (glyphs, value);
702}
703static inline bool intersects_coverage (const hb_set_t *glyphs, const HBUINT16 &value, const void *data)
704{
705 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
706 return (data+coverage).intersects (glyphs);
707}
708
709static inline bool intersects_array (const hb_set_t *glyphs,
710 unsigned int count,
711 const HBUINT16 values[],
712 intersects_func_t intersects_func,
713 const void *intersects_data)
714{
715 for (const HBUINT16 &_ : + hb_iter (values, count))
716 if (intersects_func (glyphs, _, intersects_data)) return true;
717 return false;
718}
719
720
721static inline void collect_glyph (hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
722{
723 glyphs->add (value);
724}
725static inline void collect_class (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
726{
727 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
728 class_def.add_class (glyphs, value);
729}
730static inline void collect_coverage (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
731{
732 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
733 (data+coverage).add_coverage (glyphs);
734}
735static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
736 hb_set_t *glyphs,
737 unsigned int count,
738 const HBUINT16 values[],
739 collect_glyphs_func_t collect_func,
740 const void *collect_data)
741{
742 return
743 + hb_iter (values, count)
744 | hb_apply ([&] (const HBUINT16 &_) { collect_func (glyphs, _, collect_data); })
745 ;
746}
747
748
749static inline bool match_glyph (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data HB_UNUSED)
750{
751 return glyph_id == value;
752}
753static inline bool match_class (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data)
754{
755 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
756 return class_def.get_class (glyph_id) == value;
757}
758static inline bool match_coverage (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data)
759{
760 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
761 return (data+coverage).get_coverage (glyph_id) != NOT_COVERED;
762}
763
764static inline bool would_match_input (hb_would_apply_context_t *c,
765 unsigned int count, /* Including the first glyph (not matched) */
766 const HBUINT16 input[], /* Array of input values--start with second glyph */
767 match_func_t match_func,
768 const void *match_data)
769{
770 if (count != c->len)
771 return false;
772
773 for (unsigned int i = 1; i < count; i++)
774 if (likely (!match_func (c->glyphs[i], input[i - 1], match_data)))
775 return false;
776
777 return true;
778}
779static inline bool match_input (hb_ot_apply_context_t *c,
780 unsigned int count, /* Including the first glyph (not matched) */
781 const HBUINT16 input[], /* Array of input values--start with second glyph */
782 match_func_t match_func,
783 const void *match_data,
784 unsigned int *end_offset,
785 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],
786 unsigned int *p_total_component_count = nullptr)
787{
788 TRACE_APPLY (nullptr);
789
790 if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return_trace (false);
791
792 hb_buffer_t *buffer = c->buffer;
793
794 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
795 skippy_iter.reset (buffer->idx, count - 1);
796 skippy_iter.set_match_func (match_func, match_data, input);
797
798 /*
799 * This is perhaps the trickiest part of OpenType... Remarks:
800 *
801 * - If all components of the ligature were marks, we call this a mark ligature.
802 *
803 * - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize
804 * it as a ligature glyph.
805 *
806 * - Ligatures cannot be formed across glyphs attached to different components
807 * of previous ligatures. Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and
808 * LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother.
809 * However, it would be wrong to ligate that SHADDA,FATHA sequence.
810 * There are a couple of exceptions to this:
811 *
812 * o If a ligature tries ligating with marks that belong to it itself, go ahead,
813 * assuming that the font designer knows what they are doing (otherwise it can
814 * break Indic stuff when a matra wants to ligate with a conjunct,
815 *
816 * o If two marks want to ligate and they belong to different components of the
817 * same ligature glyph, and said ligature glyph is to be ignored according to
818 * mark-filtering rules, then allow.
819 * https://github.com/harfbuzz/harfbuzz/issues/545
820 */
821
822 unsigned int total_component_count = 0;
823 total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur());
824
825 unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
826 unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
827
828 enum {
829 LIGBASE_NOT_CHECKED,
830 LIGBASE_MAY_NOT_SKIP,
831 LIGBASE_MAY_SKIP
832 } ligbase = LIGBASE_NOT_CHECKED;
833
834 match_positions[0] = buffer->idx;
835 for (unsigned int i = 1; i < count; i++)
836 {
837 if (!skippy_iter.next ()) return_trace (false);
838
839 match_positions[i] = skippy_iter.idx;
840
841 unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]);
842 unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]);
843
844 if (first_lig_id && first_lig_comp)
845 {
846 /* If first component was attached to a previous ligature component,
847 * all subsequent components should be attached to the same ligature
848 * component, otherwise we shouldn't ligate them... */
849 if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
850 {
851 /* ...unless, we are attached to a base ligature and that base
852 * ligature is ignorable. */
853 if (ligbase == LIGBASE_NOT_CHECKED)
854 {
855 bool found = false;
856 const auto *out = buffer->out_info;
857 unsigned int j = buffer->out_len;
858 while (j && _hb_glyph_info_get_lig_id (&out[j - 1]) == first_lig_id)
859 {
860 if (_hb_glyph_info_get_lig_comp (&out[j - 1]) == 0)
861 {
862 j--;
863 found = true;
864 break;
865 }
866 j--;
867 }
868
869 if (found && skippy_iter.may_skip (out[j]) == hb_ot_apply_context_t::matcher_t::SKIP_YES)
870 ligbase = LIGBASE_MAY_SKIP;
871 else
872 ligbase = LIGBASE_MAY_NOT_SKIP;
873 }
874
875 if (ligbase == LIGBASE_MAY_NOT_SKIP)
876 return_trace (false);
877 }
878 }
879 else
880 {
881 /* If first component was NOT attached to a previous ligature component,
882 * all subsequent components should also NOT be attached to any ligature
883 * component, unless they are attached to the first component itself! */
884 if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id))
885 return_trace (false);
886 }
887
888 total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]);
889 }
890
891 *end_offset = skippy_iter.idx - buffer->idx + 1;
892
893 if (p_total_component_count)
894 *p_total_component_count = total_component_count;
895
896 return_trace (true);
897}
898static inline bool ligate_input (hb_ot_apply_context_t *c,
899 unsigned int count, /* Including the first glyph */
900 const unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
901 unsigned int match_length,
902 hb_codepoint_t lig_glyph,
903 unsigned int total_component_count)
904{
905 TRACE_APPLY (nullptr);
906
907 hb_buffer_t *buffer = c->buffer;
908
909 buffer->merge_clusters (buffer->idx, buffer->idx + match_length);
910
911 /* - If a base and one or more marks ligate, consider that as a base, NOT
912 * ligature, such that all following marks can still attach to it.
913 * https://github.com/harfbuzz/harfbuzz/issues/1109
914 *
915 * - If all components of the ligature were marks, we call this a mark ligature.
916 * If it *is* a mark ligature, we don't allocate a new ligature id, and leave
917 * the ligature to keep its old ligature id. This will allow it to attach to
918 * a base ligature in GPOS. Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH,
919 * and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA with a
920 * ligature id and component value of 2. Then if SHADDA,FATHA form a ligature
921 * later, we don't want them to lose their ligature id/component, otherwise
922 * GPOS will fail to correctly position the mark ligature on top of the
923 * LAM,LAM,HEH ligature. See:
924 * https://bugzilla.gnome.org/show_bug.cgi?id=676343
925 *
926 * - If a ligature is formed of components that some of which are also ligatures
927 * themselves, and those ligature components had marks attached to *their*
928 * components, we have to attach the marks to the new ligature component
929 * positions! Now *that*'s tricky! And these marks may be following the
930 * last component of the whole sequence, so we should loop forward looking
931 * for them and update them.
932 *
933 * Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a
934 * 'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature
935 * id and component == 1. Now, during 'liga', the LAM and the LAM-HEH ligature
936 * form a LAM-LAM-HEH ligature. We need to reassign the SHADDA and FATHA to
937 * the new ligature with a component value of 2.
938 *
939 * This in fact happened to a font... See:
940 * https://bugzilla.gnome.org/show_bug.cgi?id=437633
941 */
942
943 bool is_base_ligature = _hb_glyph_info_is_base_glyph (&buffer->info[match_positions[0]]);
944 bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->info[match_positions[0]]);
945 for (unsigned int i = 1; i < count; i++)
946 if (!_hb_glyph_info_is_mark (&buffer->info[match_positions[i]]))
947 {
948 is_base_ligature = false;
949 is_mark_ligature = false;
950 break;
951 }
952 bool is_ligature = !is_base_ligature && !is_mark_ligature;
953
954 unsigned int klass = is_ligature ? HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE : 0;
955 unsigned int lig_id = is_ligature ? _hb_allocate_lig_id (buffer) : 0;
956 unsigned int last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
957 unsigned int last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
958 unsigned int components_so_far = last_num_components;
959
960 if (is_ligature)
961 {
962 _hb_glyph_info_set_lig_props_for_ligature (&buffer->cur(), lig_id, total_component_count);
963 if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
964 {
965 _hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER);
966 }
967 }
968 c->replace_glyph_with_ligature (lig_glyph, klass);
969
970 for (unsigned int i = 1; i < count; i++)
971 {
972 while (buffer->idx < match_positions[i] && buffer->successful)
973 {
974 if (is_ligature)
975 {
976 unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
977 if (this_comp == 0)
978 this_comp = last_num_components;
979 unsigned int new_lig_comp = components_so_far - last_num_components +
980 hb_min (this_comp, last_num_components);
981 _hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
982 }
983 buffer->next_glyph ();
984 }
985
986 last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
987 last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
988 components_so_far += last_num_components;
989
990 /* Skip the base glyph */
991 buffer->idx++;
992 }
993
994 if (!is_mark_ligature && last_lig_id) {
995 /* Re-adjust components for any marks following. */
996 for (unsigned int i = buffer->idx; i < buffer->len; i++) {
997 if (last_lig_id == _hb_glyph_info_get_lig_id (&buffer->info[i])) {
998 unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->info[i]);
999 if (!this_comp)
1000 break;
1001 unsigned int new_lig_comp = components_so_far - last_num_components +
1002 hb_min (this_comp, last_num_components);
1003 _hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
1004 } else
1005 break;
1006 }
1007 }
1008 return_trace (true);
1009}
1010
1011static inline bool match_backtrack (hb_ot_apply_context_t *c,
1012 unsigned int count,
1013 const HBUINT16 backtrack[],
1014 match_func_t match_func,
1015 const void *match_data,
1016 unsigned int *match_start)
1017{
1018 TRACE_APPLY (nullptr);
1019
1020 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
1021 skippy_iter.reset (c->buffer->backtrack_len (), count);
1022 skippy_iter.set_match_func (match_func, match_data, backtrack);
1023
1024 for (unsigned int i = 0; i < count; i++)
1025 if (!skippy_iter.prev ())
1026 return_trace (false);
1027
1028 *match_start = skippy_iter.idx;
1029
1030 return_trace (true);
1031}
1032
1033static inline bool match_lookahead (hb_ot_apply_context_t *c,
1034 unsigned int count,
1035 const HBUINT16 lookahead[],
1036 match_func_t match_func,
1037 const void *match_data,
1038 unsigned int offset,
1039 unsigned int *end_index)
1040{
1041 TRACE_APPLY (nullptr);
1042
1043 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
1044 skippy_iter.reset (c->buffer->idx + offset - 1, count);
1045 skippy_iter.set_match_func (match_func, match_data, lookahead);
1046
1047 for (unsigned int i = 0; i < count; i++)
1048 if (!skippy_iter.next ())
1049 return_trace (false);
1050
1051 *end_index = skippy_iter.idx + 1;
1052
1053 return_trace (true);
1054}
1055
1056
1057
1058struct LookupRecord
1059{
1060 bool sanitize (hb_sanitize_context_t *c) const
1061 {
1062 TRACE_SANITIZE (this);
1063 return_trace (c->check_struct (this));
1064 }
1065
1066 HBUINT16 sequenceIndex; /* Index into current glyph
1067 * sequence--first glyph = 0 */
1068 HBUINT16 lookupListIndex; /* Lookup to apply to that
1069 * position--zero--based */
1070 public:
1071 DEFINE_SIZE_STATIC (4);
1072};
1073
1074template <typename context_t>
1075static inline void recurse_lookups (context_t *c,
1076 unsigned int lookupCount,
1077 const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
1078{
1079 for (unsigned int i = 0; i < lookupCount; i++)
1080 c->recurse (lookupRecord[i].lookupListIndex);
1081}
1082
1083static inline bool apply_lookup (hb_ot_apply_context_t *c,
1084 unsigned int count, /* Including the first glyph */
1085 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
1086 unsigned int lookupCount,
1087 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
1088 unsigned int match_length)
1089{
1090 TRACE_APPLY (nullptr);
1091
1092 hb_buffer_t *buffer = c->buffer;
1093 int end;
1094
1095 /* All positions are distance from beginning of *output* buffer.
1096 * Adjust. */
1097 {
1098 unsigned int bl = buffer->backtrack_len ();
1099 end = bl + match_length;
1100
1101 int delta = bl - buffer->idx;
1102 /* Convert positions to new indexing. */
1103 for (unsigned int j = 0; j < count; j++)
1104 match_positions[j] += delta;
1105 }
1106
1107 for (unsigned int i = 0; i < lookupCount && buffer->successful; i++)
1108 {
1109 unsigned int idx = lookupRecord[i].sequenceIndex;
1110 if (idx >= count)
1111 continue;
1112
1113 /* Don't recurse to ourself at same position.
1114 * Note that this test is too naive, it doesn't catch longer loops. */
1115 if (idx == 0 && lookupRecord[i].lookupListIndex == c->lookup_index)
1116 continue;
1117
1118 if (unlikely (!buffer->move_to (match_positions[idx])))
1119 break;
1120
1121 if (unlikely (buffer->max_ops <= 0))
1122 break;
1123
1124 unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
1125 if (!c->recurse (lookupRecord[i].lookupListIndex))
1126 continue;
1127
1128 unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len ();
1129 int delta = new_len - orig_len;
1130
1131 if (!delta)
1132 continue;
1133
1134 /* Recursed lookup changed buffer len. Adjust.
1135 *
1136 * TODO:
1137 *
1138 * Right now, if buffer length increased by n, we assume n new glyphs
1139 * were added right after the current position, and if buffer length
1140 * was decreased by n, we assume n match positions after the current
1141 * one where removed. The former (buffer length increased) case is
1142 * fine, but the decrease case can be improved in at least two ways,
1143 * both of which are significant:
1144 *
1145 * - If recursed-to lookup is MultipleSubst and buffer length
1146 * decreased, then it's current match position that was deleted,
1147 * NOT the one after it.
1148 *
1149 * - If buffer length was decreased by n, it does not necessarily
1150 * mean that n match positions where removed, as there might
1151 * have been marks and default-ignorables in the sequence. We
1152 * should instead drop match positions between current-position
1153 * and current-position + n instead.
1154 *
1155 * It should be possible to construct tests for both of these cases.
1156 */
1157
1158 end += delta;
1159 if (end <= int (match_positions[idx]))
1160 {
1161 /* End might end up being smaller than match_positions[idx] if the recursed
1162 * lookup ended up removing many items, more than we have had matched.
1163 * Just never rewind end back and get out of here.
1164 * https://bugs.chromium.org/p/chromium/issues/detail?id=659496 */
1165 end = match_positions[idx];
1166 /* There can't be any further changes. */
1167 break;
1168 }
1169
1170 unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */
1171
1172 if (delta > 0)
1173 {
1174 if (unlikely (delta + count > HB_MAX_CONTEXT_LENGTH))
1175 break;
1176 }
1177 else
1178 {
1179 /* NOTE: delta is negative. */
1180 delta = hb_max (delta, (int) next - (int) count);
1181 next -= delta;
1182 }
1183
1184 /* Shift! */
1185 memmove (match_positions + next + delta, match_positions + next,
1186 (count - next) * sizeof (match_positions[0]));
1187 next += delta;
1188 count += delta;
1189
1190 /* Fill in new entries. */
1191 for (unsigned int j = idx + 1; j < next; j++)
1192 match_positions[j] = match_positions[j - 1] + 1;
1193
1194 /* And fixup the rest. */
1195 for (; next < count; next++)
1196 match_positions[next] += delta;
1197 }
1198
1199 buffer->move_to (end);
1200
1201 return_trace (true);
1202}
1203
1204
1205
1206/* Contextual lookups */
1207
1208struct ContextClosureLookupContext
1209{
1210 ContextClosureFuncs funcs;
1211 const void *intersects_data;
1212};
1213
1214struct ContextCollectGlyphsLookupContext
1215{
1216 ContextCollectGlyphsFuncs funcs;
1217 const void *collect_data;
1218};
1219
1220struct ContextApplyLookupContext
1221{
1222 ContextApplyFuncs funcs;
1223 const void *match_data;
1224};
1225
1226static inline bool context_intersects (const hb_set_t *glyphs,
1227 unsigned int inputCount, /* Including the first glyph (not matched) */
1228 const HBUINT16 input[], /* Array of input values--start with second glyph */
1229 ContextClosureLookupContext &lookup_context)
1230{
1231 return intersects_array (glyphs,
1232 inputCount ? inputCount - 1 : 0, input,
1233 lookup_context.funcs.intersects, lookup_context.intersects_data);
1234}
1235
1236static inline void context_closure_lookup (hb_closure_context_t *c,
1237 unsigned int inputCount, /* Including the first glyph (not matched) */
1238 const HBUINT16 input[], /* Array of input values--start with second glyph */
1239 unsigned int lookupCount,
1240 const LookupRecord lookupRecord[],
1241 ContextClosureLookupContext &lookup_context)
1242{
1243 if (context_intersects (c->glyphs,
1244 inputCount, input,
1245 lookup_context))
1246 recurse_lookups (c,
1247 lookupCount, lookupRecord);
1248}
1249
1250static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
1251 unsigned int inputCount, /* Including the first glyph (not matched) */
1252 const HBUINT16 input[], /* Array of input values--start with second glyph */
1253 unsigned int lookupCount,
1254 const LookupRecord lookupRecord[],
1255 ContextCollectGlyphsLookupContext &lookup_context)
1256{
1257 collect_array (c, c->input,
1258 inputCount ? inputCount - 1 : 0, input,
1259 lookup_context.funcs.collect, lookup_context.collect_data);
1260 recurse_lookups (c,
1261 lookupCount, lookupRecord);
1262}
1263
1264static inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
1265 unsigned int inputCount, /* Including the first glyph (not matched) */
1266 const HBUINT16 input[], /* Array of input values--start with second glyph */
1267 unsigned int lookupCount HB_UNUSED,
1268 const LookupRecord lookupRecord[] HB_UNUSED,
1269 ContextApplyLookupContext &lookup_context)
1270{
1271 return would_match_input (c,
1272 inputCount, input,
1273 lookup_context.funcs.match, lookup_context.match_data);
1274}
1275static inline bool context_apply_lookup (hb_ot_apply_context_t *c,
1276 unsigned int inputCount, /* Including the first glyph (not matched) */
1277 const HBUINT16 input[], /* Array of input values--start with second glyph */
1278 unsigned int lookupCount,
1279 const LookupRecord lookupRecord[],
1280 ContextApplyLookupContext &lookup_context)
1281{
1282 unsigned int match_length = 0;
1283 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
1284 return match_input (c,
1285 inputCount, input,
1286 lookup_context.funcs.match, lookup_context.match_data,
1287 &match_length, match_positions)
1288 && (c->buffer->unsafe_to_break (c->buffer->idx, c->buffer->idx + match_length),
1289 apply_lookup (c,
1290 inputCount, match_positions,
1291 lookupCount, lookupRecord,
1292 match_length));
1293}
1294
1295struct Rule
1296{
1297 bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const
1298 {
1299 return context_intersects (glyphs,
1300 inputCount, inputZ.arrayZ,
1301 lookup_context);
1302 }
1303
1304 void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
1305 {
1306 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
1307 (inputZ.as_array ((inputCount ? inputCount - 1 : 0)));
1308 context_closure_lookup (c,
1309 inputCount, inputZ.arrayZ,
1310 lookupCount, lookupRecord.arrayZ,
1311 lookup_context);
1312 }
1313
1314 void collect_glyphs (hb_collect_glyphs_context_t *c,
1315 ContextCollectGlyphsLookupContext &lookup_context) const
1316 {
1317 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
1318 (inputZ.as_array (inputCount ? inputCount - 1 : 0));
1319 context_collect_glyphs_lookup (c,
1320 inputCount, inputZ.arrayZ,
1321 lookupCount, lookupRecord.arrayZ,
1322 lookup_context);
1323 }
1324
1325 bool would_apply (hb_would_apply_context_t *c,
1326 ContextApplyLookupContext &lookup_context) const
1327 {
1328 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
1329 (inputZ.as_array (inputCount ? inputCount - 1 : 0));
1330 return context_would_apply_lookup (c,
1331 inputCount, inputZ.arrayZ,
1332 lookupCount, lookupRecord.arrayZ,
1333 lookup_context);
1334 }
1335
1336 bool apply (hb_ot_apply_context_t *c,
1337 ContextApplyLookupContext &lookup_context) const
1338 {
1339 TRACE_APPLY (this);
1340 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord>>
1341 (inputZ.as_array (inputCount ? inputCount - 1 : 0));
1342 return_trace (context_apply_lookup (c, inputCount, inputZ.arrayZ, lookupCount, lookupRecord.arrayZ, lookup_context));
1343 }
1344
1345 public:
1346 bool sanitize (hb_sanitize_context_t *c) const
1347 {
1348 TRACE_SANITIZE (this);
1349 return_trace (inputCount.sanitize (c) &&
1350 lookupCount.sanitize (c) &&
1351 c->check_range (inputZ.arrayZ,
1352 inputZ.item_size * (inputCount ? inputCount - 1 : 0) +
1353 LookupRecord::static_size * lookupCount));
1354 }
1355
1356 protected:
1357 HBUINT16 inputCount; /* Total number of glyphs in input
1358 * glyph sequence--includes the first
1359 * glyph */
1360 HBUINT16 lookupCount; /* Number of LookupRecords */
1361 UnsizedArrayOf<HBUINT16>
1362 inputZ; /* Array of match inputs--start with
1363 * second glyph */
1364/*UnsizedArrayOf<LookupRecord>
1365 lookupRecordX;*/ /* Array of LookupRecords--in
1366 * design order */
1367 public:
1368 DEFINE_SIZE_ARRAY (4, inputZ);
1369};
1370
1371struct RuleSet
1372{
1373 bool intersects (const hb_set_t *glyphs,
1374 ContextClosureLookupContext &lookup_context) const
1375 {
1376 return
1377 + hb_iter (rule)
1378 | hb_map (hb_add (this))
1379 | hb_map ([&] (const Rule &_) { return _.intersects (glyphs, lookup_context); })
1380 | hb_any
1381 ;
1382 }
1383
1384 void closure (hb_closure_context_t *c,
1385 ContextClosureLookupContext &lookup_context) const
1386 {
1387 return
1388 + hb_iter (rule)
1389 | hb_map (hb_add (this))
1390 | hb_apply ([&] (const Rule &_) { _.closure (c, lookup_context); })
1391 ;
1392 }
1393
1394 void collect_glyphs (hb_collect_glyphs_context_t *c,
1395 ContextCollectGlyphsLookupContext &lookup_context) const
1396 {
1397 return
1398 + hb_iter (rule)
1399 | hb_map (hb_add (this))
1400 | hb_apply ([&] (const Rule &_) { _.collect_glyphs (c, lookup_context); })
1401 ;
1402 }
1403
1404 bool would_apply (hb_would_apply_context_t *c,
1405 ContextApplyLookupContext &lookup_context) const
1406 {
1407 return
1408 + hb_iter (rule)
1409 | hb_map (hb_add (this))
1410 | hb_map ([&] (const Rule &_) { return _.would_apply (c, lookup_context); })
1411 | hb_any
1412 ;
1413 }
1414
1415 bool apply (hb_ot_apply_context_t *c,
1416 ContextApplyLookupContext &lookup_context) const
1417 {
1418 TRACE_APPLY (this);
1419 return_trace (
1420 + hb_iter (rule)
1421 | hb_map (hb_add (this))
1422 | hb_map ([&] (const Rule &_) { return _.apply (c, lookup_context); })
1423 | hb_any
1424 )
1425 ;
1426 }
1427
1428 bool sanitize (hb_sanitize_context_t *c) const
1429 {
1430 TRACE_SANITIZE (this);
1431 return_trace (rule.sanitize (c, this));
1432 }
1433
1434 protected:
1435 OffsetArrayOf<Rule>
1436 rule; /* Array of Rule tables
1437 * ordered by preference */
1438 public:
1439 DEFINE_SIZE_ARRAY (2, rule);
1440};
1441
1442
1443struct ContextFormat1
1444{
1445 bool intersects (const hb_set_t *glyphs) const
1446 {
1447 struct ContextClosureLookupContext lookup_context = {
1448 {intersects_glyph},
1449 nullptr
1450 };
1451
1452 return
1453 + hb_zip (this+coverage, ruleSet)
1454 | hb_filter (*glyphs, hb_first)
1455 | hb_map (hb_second)
1456 | hb_map (hb_add (this))
1457 | hb_map ([&] (const RuleSet &_) { return _.intersects (glyphs, lookup_context); })
1458 | hb_any
1459 ;
1460 }
1461
1462 void closure (hb_closure_context_t *c) const
1463 {
1464 struct ContextClosureLookupContext lookup_context = {
1465 {intersects_glyph},
1466 nullptr
1467 };
1468
1469 + hb_zip (this+coverage, ruleSet)
1470 | hb_filter (*c->glyphs, hb_first)
1471 | hb_map (hb_second)
1472 | hb_map (hb_add (this))
1473 | hb_apply ([&] (const RuleSet &_) { _.closure (c, lookup_context); })
1474 ;
1475 }
1476
1477 void collect_glyphs (hb_collect_glyphs_context_t *c) const
1478 {
1479 (this+coverage).add_coverage (c->input);
1480
1481 struct ContextCollectGlyphsLookupContext lookup_context = {
1482 {collect_glyph},
1483 nullptr
1484 };
1485
1486 + hb_iter (ruleSet)
1487 | hb_map (hb_add (this))
1488 | hb_apply ([&] (const RuleSet &_) { _.collect_glyphs (c, lookup_context); })
1489 ;
1490 }
1491
1492 bool would_apply (hb_would_apply_context_t *c) const
1493 {
1494 const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
1495 struct ContextApplyLookupContext lookup_context = {
1496 {match_glyph},
1497 nullptr
1498 };
1499 return rule_set.would_apply (c, lookup_context);
1500 }
1501
1502 const Coverage &get_coverage () const { return this+coverage; }
1503
1504 bool apply (hb_ot_apply_context_t *c) const
1505 {
1506 TRACE_APPLY (this);
1507 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
1508 if (likely (index == NOT_COVERED))
1509 return_trace (false);
1510
1511 const RuleSet &rule_set = this+ruleSet[index];
1512 struct ContextApplyLookupContext lookup_context = {
1513 {match_glyph},
1514 nullptr
1515 };
1516 return_trace (rule_set.apply (c, lookup_context));
1517 }
1518
1519 bool subset (hb_subset_context_t *c) const
1520 {
1521 TRACE_SUBSET (this);
1522 // TODO(subset)
1523 return_trace (false);
1524 }
1525
1526 bool sanitize (hb_sanitize_context_t *c) const
1527 {
1528 TRACE_SANITIZE (this);
1529 return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
1530 }
1531
1532 protected:
1533 HBUINT16 format; /* Format identifier--format = 1 */
1534 OffsetTo<Coverage>
1535 coverage; /* Offset to Coverage table--from
1536 * beginning of table */
1537 OffsetArrayOf<RuleSet>
1538 ruleSet; /* Array of RuleSet tables
1539 * ordered by Coverage Index */
1540 public:
1541 DEFINE_SIZE_ARRAY (6, ruleSet);
1542};
1543
1544
1545struct ContextFormat2
1546{
1547 bool intersects (const hb_set_t *glyphs) const
1548 {
1549 if (!(this+coverage).intersects (glyphs))
1550 return false;
1551
1552 const ClassDef &class_def = this+classDef;
1553
1554 struct ContextClosureLookupContext lookup_context = {
1555 {intersects_class},
1556 &class_def
1557 };
1558
1559 return
1560 + hb_enumerate (ruleSet)
1561 | hb_map ([&] (const hb_pair_t<unsigned, const OffsetTo<RuleSet> &> p)
1562 { return class_def.intersects_class (glyphs, p.first) &&
1563 (this+p.second).intersects (glyphs, lookup_context); })
1564 | hb_any
1565 ;
1566 }
1567
1568 void closure (hb_closure_context_t *c) const
1569 {
1570 if (!(this+coverage).intersects (c->glyphs))
1571 return;
1572
1573 const ClassDef &class_def = this+classDef;
1574
1575 struct ContextClosureLookupContext lookup_context = {
1576 {intersects_class},
1577 &class_def
1578 };
1579
1580 return
1581 + hb_enumerate (ruleSet)
1582 | hb_filter ([&] (unsigned _)
1583 { return class_def.intersects_class (c->glyphs, _); },
1584 hb_first)
1585 | hb_map (hb_second)
1586 | hb_map (hb_add (this))
1587 | hb_apply ([&] (const RuleSet &_) { _.closure (c, lookup_context); })
1588 ;
1589 }
1590
1591 void collect_glyphs (hb_collect_glyphs_context_t *c) const
1592 {
1593 (this+coverage).add_coverage (c->input);
1594
1595 const ClassDef &class_def = this+classDef;
1596 struct ContextCollectGlyphsLookupContext lookup_context = {
1597 {collect_class},
1598 &class_def
1599 };
1600
1601 + hb_iter (ruleSet)
1602 | hb_map (hb_add (this))
1603 | hb_apply ([&] (const RuleSet &_) { _.collect_glyphs (c, lookup_context); })
1604 ;
1605 }
1606
1607 bool would_apply (hb_would_apply_context_t *c) const
1608 {
1609 const ClassDef &class_def = this+classDef;
1610 unsigned int index = class_def.get_class (c->glyphs[0]);
1611 const RuleSet &rule_set = this+ruleSet[index];
1612 struct ContextApplyLookupContext lookup_context = {
1613 {match_class},
1614 &class_def
1615 };
1616 return rule_set.would_apply (c, lookup_context);
1617 }
1618
1619 const Coverage &get_coverage () const { return this+coverage; }
1620
1621 bool apply (hb_ot_apply_context_t *c) const
1622 {
1623 TRACE_APPLY (this);
1624 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
1625 if (likely (index == NOT_COVERED)) return_trace (false);
1626
1627 const ClassDef &class_def = this+classDef;
1628 index = class_def.get_class (c->buffer->cur().codepoint);
1629 const RuleSet &rule_set = this+ruleSet[index];
1630 struct ContextApplyLookupContext lookup_context = {
1631 {match_class},
1632 &class_def
1633 };
1634 return_trace (rule_set.apply (c, lookup_context));
1635 }
1636
1637 bool subset (hb_subset_context_t *c) const
1638 {
1639 TRACE_SUBSET (this);
1640 // TODO(subset)
1641 return_trace (false);
1642 }
1643
1644 bool sanitize (hb_sanitize_context_t *c) const
1645 {
1646 TRACE_SANITIZE (this);
1647 return_trace (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
1648 }
1649
1650 protected:
1651 HBUINT16 format; /* Format identifier--format = 2 */
1652 OffsetTo<Coverage>
1653 coverage; /* Offset to Coverage table--from
1654 * beginning of table */
1655 OffsetTo<ClassDef>
1656 classDef; /* Offset to glyph ClassDef table--from
1657 * beginning of table */
1658 OffsetArrayOf<RuleSet>
1659 ruleSet; /* Array of RuleSet tables
1660 * ordered by class */
1661 public:
1662 DEFINE_SIZE_ARRAY (8, ruleSet);
1663};
1664
1665
1666struct ContextFormat3
1667{
1668 bool intersects (const hb_set_t *glyphs) const
1669 {
1670 if (!(this+coverageZ[0]).intersects (glyphs))
1671 return false;
1672
1673 struct ContextClosureLookupContext lookup_context = {
1674 {intersects_coverage},
1675 this
1676 };
1677 return context_intersects (glyphs,
1678 glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
1679 lookup_context);
1680 }
1681
1682 void closure (hb_closure_context_t *c) const
1683 {
1684 if (!(this+coverageZ[0]).intersects (c->glyphs))
1685 return;
1686
1687 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
1688 struct ContextClosureLookupContext lookup_context = {
1689 {intersects_coverage},
1690 this
1691 };
1692 context_closure_lookup (c,
1693 glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
1694 lookupCount, lookupRecord,
1695 lookup_context);
1696 }
1697
1698 void collect_glyphs (hb_collect_glyphs_context_t *c) const
1699 {
1700 (this+coverageZ[0]).add_coverage (c->input);
1701
1702 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
1703 struct ContextCollectGlyphsLookupContext lookup_context = {
1704 {collect_coverage},
1705 this
1706 };
1707
1708 context_collect_glyphs_lookup (c,
1709 glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
1710 lookupCount, lookupRecord,
1711 lookup_context);
1712 }
1713
1714 bool would_apply (hb_would_apply_context_t *c) const
1715 {
1716 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
1717 struct ContextApplyLookupContext lookup_context = {
1718 {match_coverage},
1719 this
1720 };
1721 return context_would_apply_lookup (c,
1722 glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
1723 lookupCount, lookupRecord,
1724 lookup_context);
1725 }
1726
1727 const Coverage &get_coverage () const { return this+coverageZ[0]; }
1728
1729 bool apply (hb_ot_apply_context_t *c) const
1730 {
1731 TRACE_APPLY (this);
1732 unsigned int index = (this+coverageZ[0]).get_coverage (c->buffer->cur().codepoint);
1733 if (likely (index == NOT_COVERED)) return_trace (false);
1734
1735 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
1736 struct ContextApplyLookupContext lookup_context = {
1737 {match_coverage},
1738 this
1739 };
1740 return_trace (context_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, lookup_context));
1741 }
1742
1743 bool subset (hb_subset_context_t *c) const
1744 {
1745 TRACE_SUBSET (this);
1746 // TODO(subset)
1747 return_trace (false);
1748 }
1749
1750 bool sanitize (hb_sanitize_context_t *c) const
1751 {
1752 TRACE_SANITIZE (this);
1753 if (!c->check_struct (this)) return_trace (false);
1754 unsigned int count = glyphCount;
1755 if (!count) return_trace (false); /* We want to access coverageZ[0] freely. */
1756 if (!c->check_array (coverageZ.arrayZ, count)) return_trace (false);
1757 for (unsigned int i = 0; i < count; i++)
1758 if (!coverageZ[i].sanitize (c, this)) return_trace (false);
1759 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
1760 return_trace (c->check_array (lookupRecord, lookupCount));
1761 }
1762
1763 protected:
1764 HBUINT16 format; /* Format identifier--format = 3 */
1765 HBUINT16 glyphCount; /* Number of glyphs in the input glyph
1766 * sequence */
1767 HBUINT16 lookupCount; /* Number of LookupRecords */
1768 UnsizedArrayOf<OffsetTo<Coverage>>
1769 coverageZ; /* Array of offsets to Coverage
1770 * table in glyph sequence order */
1771/*UnsizedArrayOf<LookupRecord>
1772 lookupRecordX;*/ /* Array of LookupRecords--in
1773 * design order */
1774 public:
1775 DEFINE_SIZE_ARRAY (6, coverageZ);
1776};
1777
1778struct Context
1779{
1780 template <typename context_t, typename ...Ts>
1781 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
1782 {
1783 TRACE_DISPATCH (this, u.format);
1784 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1785 switch (u.format) {
1786 case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
1787 case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
1788 case 3: return_trace (c->dispatch (u.format3, hb_forward<Ts> (ds)...));
1789 default:return_trace (c->default_return_value ());
1790 }
1791 }
1792
1793 protected:
1794 union {
1795 HBUINT16 format; /* Format identifier */
1796 ContextFormat1 format1;
1797 ContextFormat2 format2;
1798 ContextFormat3 format3;
1799 } u;
1800};
1801
1802
1803/* Chaining Contextual lookups */
1804
1805struct ChainContextClosureLookupContext
1806{
1807 ContextClosureFuncs funcs;
1808 const void *intersects_data[3];
1809};
1810
1811struct ChainContextCollectGlyphsLookupContext
1812{
1813 ContextCollectGlyphsFuncs funcs;
1814 const void *collect_data[3];
1815};
1816
1817struct ChainContextApplyLookupContext
1818{
1819 ContextApplyFuncs funcs;
1820 const void *match_data[3];
1821};
1822
1823static inline bool chain_context_intersects (const hb_set_t *glyphs,
1824 unsigned int backtrackCount,
1825 const HBUINT16 backtrack[],
1826 unsigned int inputCount, /* Including the first glyph (not matched) */
1827 const HBUINT16 input[], /* Array of input values--start with second glyph */
1828 unsigned int lookaheadCount,
1829 const HBUINT16 lookahead[],
1830 ChainContextClosureLookupContext &lookup_context)
1831{
1832 return intersects_array (glyphs,
1833 backtrackCount, backtrack,
1834 lookup_context.funcs.intersects, lookup_context.intersects_data[0])
1835 && intersects_array (glyphs,
1836 inputCount ? inputCount - 1 : 0, input,
1837 lookup_context.funcs.intersects, lookup_context.intersects_data[1])
1838 && intersects_array (glyphs,
1839 lookaheadCount, lookahead,
1840 lookup_context.funcs.intersects, lookup_context.intersects_data[2]);
1841}
1842
1843static inline void chain_context_closure_lookup (hb_closure_context_t *c,
1844 unsigned int backtrackCount,
1845 const HBUINT16 backtrack[],
1846 unsigned int inputCount, /* Including the first glyph (not matched) */
1847 const HBUINT16 input[], /* Array of input values--start with second glyph */
1848 unsigned int lookaheadCount,
1849 const HBUINT16 lookahead[],
1850 unsigned int lookupCount,
1851 const LookupRecord lookupRecord[],
1852 ChainContextClosureLookupContext &lookup_context)
1853{
1854 if (chain_context_intersects (c->glyphs,
1855 backtrackCount, backtrack,
1856 inputCount, input,
1857 lookaheadCount, lookahead,
1858 lookup_context))
1859 recurse_lookups (c,
1860 lookupCount, lookupRecord);
1861}
1862
1863static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
1864 unsigned int backtrackCount,
1865 const HBUINT16 backtrack[],
1866 unsigned int inputCount, /* Including the first glyph (not matched) */
1867 const HBUINT16 input[], /* Array of input values--start with second glyph */
1868 unsigned int lookaheadCount,
1869 const HBUINT16 lookahead[],
1870 unsigned int lookupCount,
1871 const LookupRecord lookupRecord[],
1872 ChainContextCollectGlyphsLookupContext &lookup_context)
1873{
1874 collect_array (c, c->before,
1875 backtrackCount, backtrack,
1876 lookup_context.funcs.collect, lookup_context.collect_data[0]);
1877 collect_array (c, c->input,
1878 inputCount ? inputCount - 1 : 0, input,
1879 lookup_context.funcs.collect, lookup_context.collect_data[1]);
1880 collect_array (c, c->after,
1881 lookaheadCount, lookahead,
1882 lookup_context.funcs.collect, lookup_context.collect_data[2]);
1883 recurse_lookups (c,
1884 lookupCount, lookupRecord);
1885}
1886
1887static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c,
1888 unsigned int backtrackCount,
1889 const HBUINT16 backtrack[] HB_UNUSED,
1890 unsigned int inputCount, /* Including the first glyph (not matched) */
1891 const HBUINT16 input[], /* Array of input values--start with second glyph */
1892 unsigned int lookaheadCount,
1893 const HBUINT16 lookahead[] HB_UNUSED,
1894 unsigned int lookupCount HB_UNUSED,
1895 const LookupRecord lookupRecord[] HB_UNUSED,
1896 ChainContextApplyLookupContext &lookup_context)
1897{
1898 return (c->zero_context ? !backtrackCount && !lookaheadCount : true)
1899 && would_match_input (c,
1900 inputCount, input,
1901 lookup_context.funcs.match, lookup_context.match_data[1]);
1902}
1903
1904static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
1905 unsigned int backtrackCount,
1906 const HBUINT16 backtrack[],
1907 unsigned int inputCount, /* Including the first glyph (not matched) */
1908 const HBUINT16 input[], /* Array of input values--start with second glyph */
1909 unsigned int lookaheadCount,
1910 const HBUINT16 lookahead[],
1911 unsigned int lookupCount,
1912 const LookupRecord lookupRecord[],
1913 ChainContextApplyLookupContext &lookup_context)
1914{
1915 unsigned int start_index = 0, match_length = 0, end_index = 0;
1916 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
1917 return match_input (c,
1918 inputCount, input,
1919 lookup_context.funcs.match, lookup_context.match_data[1],
1920 &match_length, match_positions)
1921 && match_backtrack (c,
1922 backtrackCount, backtrack,
1923 lookup_context.funcs.match, lookup_context.match_data[0],
1924 &start_index)
1925 && match_lookahead (c,
1926 lookaheadCount, lookahead,
1927 lookup_context.funcs.match, lookup_context.match_data[2],
1928 match_length, &end_index)
1929 && (c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index),
1930 apply_lookup (c,
1931 inputCount, match_positions,
1932 lookupCount, lookupRecord,
1933 match_length));
1934}
1935
1936struct ChainRule
1937{
1938 bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
1939 {
1940 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
1941 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
1942 return chain_context_intersects (glyphs,
1943 backtrack.len, backtrack.arrayZ,
1944 input.lenP1, input.arrayZ,
1945 lookahead.len, lookahead.arrayZ,
1946 lookup_context);
1947 }
1948
1949 void closure (hb_closure_context_t *c,
1950 ChainContextClosureLookupContext &lookup_context) const
1951 {
1952 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
1953 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
1954 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
1955 chain_context_closure_lookup (c,
1956 backtrack.len, backtrack.arrayZ,
1957 input.lenP1, input.arrayZ,
1958 lookahead.len, lookahead.arrayZ,
1959 lookup.len, lookup.arrayZ,
1960 lookup_context);
1961 }
1962
1963 void collect_glyphs (hb_collect_glyphs_context_t *c,
1964 ChainContextCollectGlyphsLookupContext &lookup_context) const
1965 {
1966 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
1967 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
1968 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
1969 chain_context_collect_glyphs_lookup (c,
1970 backtrack.len, backtrack.arrayZ,
1971 input.lenP1, input.arrayZ,
1972 lookahead.len, lookahead.arrayZ,
1973 lookup.len, lookup.arrayZ,
1974 lookup_context);
1975 }
1976
1977 bool would_apply (hb_would_apply_context_t *c,
1978 ChainContextApplyLookupContext &lookup_context) const
1979 {
1980 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
1981 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
1982 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
1983 return chain_context_would_apply_lookup (c,
1984 backtrack.len, backtrack.arrayZ,
1985 input.lenP1, input.arrayZ,
1986 lookahead.len, lookahead.arrayZ, lookup.len,
1987 lookup.arrayZ, lookup_context);
1988 }
1989
1990 bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
1991 {
1992 TRACE_APPLY (this);
1993 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
1994 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
1995 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
1996 return_trace (chain_context_apply_lookup (c,
1997 backtrack.len, backtrack.arrayZ,
1998 input.lenP1, input.arrayZ,
1999 lookahead.len, lookahead.arrayZ, lookup.len,
2000 lookup.arrayZ, lookup_context));
2001 }
2002
2003 template<typename Iterator,
2004 hb_requires (hb_is_iterator (Iterator))>
2005 void serialize_array (hb_serialize_context_t *c,
2006 HBUINT16 len,
2007 Iterator it) const
2008 {
2009 c->copy (len);
2010 for (const auto g : it)
2011 {
2012 HBUINT16 gid;
2013 gid = g;
2014 c->copy (gid);
2015 }
2016 }
2017
2018 ChainRule* copy (hb_serialize_context_t *c,
2019 const hb_map_t *backtrack_map,
2020 const hb_map_t *input_map = nullptr,
2021 const hb_map_t *lookahead_map = nullptr) const
2022 {
2023 TRACE_SERIALIZE (this);
2024 auto *out = c->start_embed (this);
2025 if (unlikely (!out)) return_trace (nullptr);
2026
2027 const hb_map_t *mapping = backtrack_map;
2028 serialize_array (c, backtrack.len, + backtrack.iter ()
2029 | hb_map (mapping));
2030
2031 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
2032 if (input_map) mapping = input_map;
2033 serialize_array (c, input.lenP1, + input.iter ()
2034 | hb_map (mapping));
2035
2036 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
2037 if (lookahead_map) mapping = lookahead_map;
2038 serialize_array (c, lookahead.len, + lookahead.iter ()
2039 | hb_map (mapping));
2040
2041 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
2042 c->copy (lookup);
2043
2044 return_trace (out);
2045 }
2046
2047 bool subset (hb_subset_context_t *c,
2048 const hb_map_t *backtrack_map = nullptr,
2049 const hb_map_t *input_map = nullptr,
2050 const hb_map_t *lookahead_map = nullptr) const
2051 {
2052 TRACE_SUBSET (this);
2053
2054 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
2055 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
2056
2057 if (!backtrack_map)
2058 {
2059 const hb_set_t &glyphset = *c->plan->glyphset ();
2060 if (!hb_all (backtrack, glyphset) ||
2061 !hb_all (input, glyphset) ||
2062 !hb_all (lookahead, glyphset))
2063 return_trace (false);
2064
2065 copy (c->serializer, c->plan->glyph_map);
2066 }
2067 else
2068 {
2069 if (!hb_all (backtrack, backtrack_map) ||
2070 !hb_all (input, input_map) ||
2071 !hb_all (lookahead, lookahead_map))
2072 return_trace (false);
2073
2074 copy (c->serializer, backtrack_map, input_map, lookahead_map);
2075 }
2076
2077 return_trace (true);
2078 }
2079
2080 bool sanitize (hb_sanitize_context_t *c) const
2081 {
2082 TRACE_SANITIZE (this);
2083 if (!backtrack.sanitize (c)) return_trace (false);
2084 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16>> (backtrack);
2085 if (!input.sanitize (c)) return_trace (false);
2086 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16>> (input);
2087 if (!lookahead.sanitize (c)) return_trace (false);
2088 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
2089 return_trace (lookup.sanitize (c));
2090 }
2091
2092 protected:
2093 ArrayOf<HBUINT16>
2094 backtrack; /* Array of backtracking values
2095 * (to be matched before the input
2096 * sequence) */
2097 HeadlessArrayOf<HBUINT16>
2098 inputX; /* Array of input values (start with
2099 * second glyph) */
2100 ArrayOf<HBUINT16>
2101 lookaheadX; /* Array of lookahead values's (to be
2102 * matched after the input sequence) */
2103 ArrayOf<LookupRecord>
2104 lookupX; /* Array of LookupRecords--in
2105 * design order) */
2106 public:
2107 DEFINE_SIZE_MIN (8);
2108};
2109
2110struct ChainRuleSet
2111{
2112 bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
2113 {
2114 return
2115 + hb_iter (rule)
2116 | hb_map (hb_add (this))
2117 | hb_map ([&] (const ChainRule &_) { return _.intersects (glyphs, lookup_context); })
2118 | hb_any
2119 ;
2120 }
2121 void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
2122 {
2123 return
2124 + hb_iter (rule)
2125 | hb_map (hb_add (this))
2126 | hb_apply ([&] (const ChainRule &_) { _.closure (c, lookup_context); })
2127 ;
2128 }
2129
2130 void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
2131 {
2132 return
2133 + hb_iter (rule)
2134 | hb_map (hb_add (this))
2135 | hb_apply ([&] (const ChainRule &_) { _.collect_glyphs (c, lookup_context); })
2136 ;
2137 }
2138
2139 bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
2140 {
2141 return
2142 + hb_iter (rule)
2143 | hb_map (hb_add (this))
2144 | hb_map ([&] (const ChainRule &_) { return _.would_apply (c, lookup_context); })
2145 | hb_any
2146 ;
2147 }
2148
2149 bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
2150 {
2151 TRACE_APPLY (this);
2152 return_trace (
2153 + hb_iter (rule)
2154 | hb_map (hb_add (this))
2155 | hb_map ([&] (const ChainRule &_) { return _.apply (c, lookup_context); })
2156 | hb_any
2157 )
2158 ;
2159 }
2160
2161 bool subset (hb_subset_context_t *c,
2162 const hb_map_t *backtrack_klass_map = nullptr,
2163 const hb_map_t *input_klass_map = nullptr,
2164 const hb_map_t *lookahead_klass_map = nullptr) const
2165 {
2166 TRACE_SUBSET (this);
2167
2168 auto snap = c->serializer->snapshot ();
2169 auto *out = c->serializer->start_embed (*this);
2170 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
2171
2172 for (const OffsetTo<ChainRule>& _ : rule)
2173 {
2174 if (!_) continue;
2175 auto *o = out->rule.serialize_append (c->serializer);
2176 if (unlikely (!o)) continue;
2177
2178 auto o_snap = c->serializer->snapshot ();
2179 if (!o->serialize_subset (c, _, this, out,
2180 backtrack_klass_map,
2181 input_klass_map,
2182 lookahead_klass_map))
2183 {
2184 out->rule.pop ();
2185 c->serializer->revert (o_snap);
2186 }
2187 }
2188
2189 bool ret = bool (out->rule);
2190 if (!ret) c->serializer->revert (snap);
2191
2192 return_trace (ret);
2193 }
2194
2195 bool sanitize (hb_sanitize_context_t *c) const
2196 {
2197 TRACE_SANITIZE (this);
2198 return_trace (rule.sanitize (c, this));
2199 }
2200
2201 protected:
2202 OffsetArrayOf<ChainRule>
2203 rule; /* Array of ChainRule tables
2204 * ordered by preference */
2205 public:
2206 DEFINE_SIZE_ARRAY (2, rule);
2207};
2208
2209struct ChainContextFormat1
2210{
2211 bool intersects (const hb_set_t *glyphs) const
2212 {
2213 struct ChainContextClosureLookupContext lookup_context = {
2214 {intersects_glyph},
2215 {nullptr, nullptr, nullptr}
2216 };
2217
2218 return
2219 + hb_zip (this+coverage, ruleSet)
2220 | hb_filter (*glyphs, hb_first)
2221 | hb_map (hb_second)
2222 | hb_map (hb_add (this))
2223 | hb_map ([&] (const ChainRuleSet &_) { return _.intersects (glyphs, lookup_context); })
2224 | hb_any
2225 ;
2226 }
2227
2228 void closure (hb_closure_context_t *c) const
2229 {
2230 struct ChainContextClosureLookupContext lookup_context = {
2231 {intersects_glyph},
2232 {nullptr, nullptr, nullptr}
2233 };
2234
2235 + hb_zip (this+coverage, ruleSet)
2236 | hb_filter (*c->glyphs, hb_first)
2237 | hb_map (hb_second)
2238 | hb_map (hb_add (this))
2239 | hb_apply ([&] (const ChainRuleSet &_) { _.closure (c, lookup_context); })
2240 ;
2241 }
2242
2243 void collect_glyphs (hb_collect_glyphs_context_t *c) const
2244 {
2245 (this+coverage).add_coverage (c->input);
2246
2247 struct ChainContextCollectGlyphsLookupContext lookup_context = {
2248 {collect_glyph},
2249 {nullptr, nullptr, nullptr}
2250 };
2251
2252 + hb_iter (ruleSet)
2253 | hb_map (hb_add (this))
2254 | hb_apply ([&] (const ChainRuleSet &_) { _.collect_glyphs (c, lookup_context); })
2255 ;
2256 }
2257
2258 bool would_apply (hb_would_apply_context_t *c) const
2259 {
2260 const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
2261 struct ChainContextApplyLookupContext lookup_context = {
2262 {match_glyph},
2263 {nullptr, nullptr, nullptr}
2264 };
2265 return rule_set.would_apply (c, lookup_context);
2266 }
2267
2268 const Coverage &get_coverage () const { return this+coverage; }
2269
2270 bool apply (hb_ot_apply_context_t *c) const
2271 {
2272 TRACE_APPLY (this);
2273 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
2274 if (likely (index == NOT_COVERED)) return_trace (false);
2275
2276 const ChainRuleSet &rule_set = this+ruleSet[index];
2277 struct ChainContextApplyLookupContext lookup_context = {
2278 {match_glyph},
2279 {nullptr, nullptr, nullptr}
2280 };
2281 return_trace (rule_set.apply (c, lookup_context));
2282 }
2283
2284 bool subset (hb_subset_context_t *c) const
2285 {
2286 TRACE_SUBSET (this);
2287 const hb_set_t &glyphset = *c->plan->glyphset ();
2288 const hb_map_t &glyph_map = *c->plan->glyph_map;
2289
2290 auto *out = c->serializer->start_embed (*this);
2291 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
2292 out->format = format;
2293
2294 hb_sorted_vector_t<hb_codepoint_t> new_coverage;
2295 + hb_zip (this+coverage, ruleSet)
2296 | hb_filter (glyphset, hb_first)
2297 | hb_filter (subset_offset_array (c, out->ruleSet, this, out), hb_second)
2298 | hb_map (hb_first)
2299 | hb_map (glyph_map)
2300 | hb_sink (new_coverage)
2301 ;
2302
2303 out->coverage.serialize (c->serializer, out)
2304 .serialize (c->serializer, new_coverage.iter ());
2305 return_trace (bool (new_coverage));
2306 }
2307
2308 bool sanitize (hb_sanitize_context_t *c) const
2309 {
2310 TRACE_SANITIZE (this);
2311 return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
2312 }
2313
2314 protected:
2315 HBUINT16 format; /* Format identifier--format = 1 */
2316 OffsetTo<Coverage>
2317 coverage; /* Offset to Coverage table--from
2318 * beginning of table */
2319 OffsetArrayOf<ChainRuleSet>
2320 ruleSet; /* Array of ChainRuleSet tables
2321 * ordered by Coverage Index */
2322 public:
2323 DEFINE_SIZE_ARRAY (6, ruleSet);
2324};
2325
2326struct ChainContextFormat2
2327{
2328 bool intersects (const hb_set_t *glyphs) const
2329 {
2330 if (!(this+coverage).intersects (glyphs))
2331 return false;
2332
2333 const ClassDef &backtrack_class_def = this+backtrackClassDef;
2334 const ClassDef &input_class_def = this+inputClassDef;
2335 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2336
2337 struct ChainContextClosureLookupContext lookup_context = {
2338 {intersects_class},
2339 {&backtrack_class_def,
2340 &input_class_def,
2341 &lookahead_class_def}
2342 };
2343
2344 return
2345 + hb_enumerate (ruleSet)
2346 | hb_map ([&] (const hb_pair_t<unsigned, const OffsetTo<ChainRuleSet> &> p)
2347 { return input_class_def.intersects_class (glyphs, p.first) &&
2348 (this+p.second).intersects (glyphs, lookup_context); })
2349 | hb_any
2350 ;
2351 }
2352 void closure (hb_closure_context_t *c) const
2353 {
2354 if (!(this+coverage).intersects (c->glyphs))
2355 return;
2356
2357 const ClassDef &backtrack_class_def = this+backtrackClassDef;
2358 const ClassDef &input_class_def = this+inputClassDef;
2359 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2360
2361 struct ChainContextClosureLookupContext lookup_context = {
2362 {intersects_class},
2363 {&backtrack_class_def,
2364 &input_class_def,
2365 &lookahead_class_def}
2366 };
2367
2368 return
2369 + hb_enumerate (ruleSet)
2370 | hb_filter ([&] (unsigned _)
2371 { return input_class_def.intersects_class (c->glyphs, _); },
2372 hb_first)
2373 | hb_map (hb_second)
2374 | hb_map (hb_add (this))
2375 | hb_apply ([&] (const ChainRuleSet &_) { _.closure (c, lookup_context); })
2376 ;
2377 }
2378
2379 void collect_glyphs (hb_collect_glyphs_context_t *c) const
2380 {
2381 (this+coverage).add_coverage (c->input);
2382
2383 const ClassDef &backtrack_class_def = this+backtrackClassDef;
2384 const ClassDef &input_class_def = this+inputClassDef;
2385 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2386
2387 struct ChainContextCollectGlyphsLookupContext lookup_context = {
2388 {collect_class},
2389 {&backtrack_class_def,
2390 &input_class_def,
2391 &lookahead_class_def}
2392 };
2393
2394 + hb_iter (ruleSet)
2395 | hb_map (hb_add (this))
2396 | hb_apply ([&] (const ChainRuleSet &_) { _.collect_glyphs (c, lookup_context); })
2397 ;
2398 }
2399
2400 bool would_apply (hb_would_apply_context_t *c) const
2401 {
2402 const ClassDef &backtrack_class_def = this+backtrackClassDef;
2403 const ClassDef &input_class_def = this+inputClassDef;
2404 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2405
2406 unsigned int index = input_class_def.get_class (c->glyphs[0]);
2407 const ChainRuleSet &rule_set = this+ruleSet[index];
2408 struct ChainContextApplyLookupContext lookup_context = {
2409 {match_class},
2410 {&backtrack_class_def,
2411 &input_class_def,
2412 &lookahead_class_def}
2413 };
2414 return rule_set.would_apply (c, lookup_context);
2415 }
2416
2417 const Coverage &get_coverage () const { return this+coverage; }
2418
2419 bool apply (hb_ot_apply_context_t *c) const
2420 {
2421 TRACE_APPLY (this);
2422 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
2423 if (likely (index == NOT_COVERED)) return_trace (false);
2424
2425 const ClassDef &backtrack_class_def = this+backtrackClassDef;
2426 const ClassDef &input_class_def = this+inputClassDef;
2427 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2428
2429 index = input_class_def.get_class (c->buffer->cur().codepoint);
2430 const ChainRuleSet &rule_set = this+ruleSet[index];
2431 struct ChainContextApplyLookupContext lookup_context = {
2432 {match_class},
2433 {&backtrack_class_def,
2434 &input_class_def,
2435 &lookahead_class_def}
2436 };
2437 return_trace (rule_set.apply (c, lookup_context));
2438 }
2439
2440 bool subset (hb_subset_context_t *c) const
2441 {
2442 TRACE_SUBSET (this);
2443 auto *out = c->serializer->start_embed (*this);
2444 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
2445 out->format = format;
2446 out->coverage.serialize_subset (c, coverage, this, out);
2447
2448 hb_map_t backtrack_klass_map;
2449 out->backtrackClassDef.serialize_subset (c, backtrackClassDef, this, out, &backtrack_klass_map);
2450
2451 // subset inputClassDef based on glyphs survived in Coverage subsetting
2452 hb_map_t input_klass_map;
2453 out->inputClassDef.serialize_subset (c, inputClassDef, this, out, &input_klass_map);
2454
2455 hb_map_t lookahead_klass_map;
2456 out->lookaheadClassDef.serialize_subset (c, lookaheadClassDef, this, out, &lookahead_klass_map);
2457
2458 hb_vector_t<unsigned> rulesets;
2459 bool ret = true;
2460 for (const OffsetTo<ChainRuleSet>& _ : + hb_enumerate (ruleSet)
2461 | hb_filter (input_klass_map, hb_first)
2462 | hb_map (hb_second))
2463 {
2464 auto *o = out->ruleSet.serialize_append (c->serializer);
2465 if (unlikely (!o))
2466 {
2467 ret = false;
2468 break;
2469 }
2470 if (!o->serialize_subset (c, _, this, out,
2471 &backtrack_klass_map,
2472 &input_klass_map,
2473 &lookahead_klass_map))
2474 {
2475 rulesets.push (0);
2476 }
2477 else rulesets.push (1);
2478 }
2479
2480 if (!ret) return_trace (ret);
2481
2482 //prune empty trailing ruleSets
2483 unsigned count = rulesets.length;
2484 while (count > 0 && rulesets[count-1] == 0)
2485 {
2486 out->ruleSet.pop ();
2487 count--;
2488 }
2489
2490 return_trace (bool (out->ruleSet));
2491 }
2492
2493 bool sanitize (hb_sanitize_context_t *c) const
2494 {
2495 TRACE_SANITIZE (this);
2496 return_trace (coverage.sanitize (c, this) &&
2497 backtrackClassDef.sanitize (c, this) &&
2498 inputClassDef.sanitize (c, this) &&
2499 lookaheadClassDef.sanitize (c, this) &&
2500 ruleSet.sanitize (c, this));
2501 }
2502
2503 protected:
2504 HBUINT16 format; /* Format identifier--format = 2 */
2505 OffsetTo<Coverage>
2506 coverage; /* Offset to Coverage table--from
2507 * beginning of table */
2508 OffsetTo<ClassDef>
2509 backtrackClassDef; /* Offset to glyph ClassDef table
2510 * containing backtrack sequence
2511 * data--from beginning of table */
2512 OffsetTo<ClassDef>
2513 inputClassDef; /* Offset to glyph ClassDef
2514 * table containing input sequence
2515 * data--from beginning of table */
2516 OffsetTo<ClassDef>
2517 lookaheadClassDef; /* Offset to glyph ClassDef table
2518 * containing lookahead sequence
2519 * data--from beginning of table */
2520 OffsetArrayOf<ChainRuleSet>
2521 ruleSet; /* Array of ChainRuleSet tables
2522 * ordered by class */
2523 public:
2524 DEFINE_SIZE_ARRAY (12, ruleSet);
2525};
2526
2527struct ChainContextFormat3
2528{
2529 bool intersects (const hb_set_t *glyphs) const
2530 {
2531 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
2532
2533 if (!(this+input[0]).intersects (glyphs))
2534 return false;
2535
2536 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
2537 struct ChainContextClosureLookupContext lookup_context = {
2538 {intersects_coverage},
2539 {this, this, this}
2540 };
2541 return chain_context_intersects (glyphs,
2542 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2543 input.len, (const HBUINT16 *) input.arrayZ + 1,
2544 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2545 lookup_context);
2546 }
2547
2548 void closure (hb_closure_context_t *c) const
2549 {
2550 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
2551
2552 if (!(this+input[0]).intersects (c->glyphs))
2553 return;
2554
2555 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
2556 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
2557 struct ChainContextClosureLookupContext lookup_context = {
2558 {intersects_coverage},
2559 {this, this, this}
2560 };
2561 chain_context_closure_lookup (c,
2562 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2563 input.len, (const HBUINT16 *) input.arrayZ + 1,
2564 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2565 lookup.len, lookup.arrayZ,
2566 lookup_context);
2567 }
2568
2569 void collect_glyphs (hb_collect_glyphs_context_t *c) const
2570 {
2571 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
2572
2573 (this+input[0]).add_coverage (c->input);
2574
2575 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
2576 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
2577 struct ChainContextCollectGlyphsLookupContext lookup_context = {
2578 {collect_coverage},
2579 {this, this, this}
2580 };
2581 chain_context_collect_glyphs_lookup (c,
2582 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2583 input.len, (const HBUINT16 *) input.arrayZ + 1,
2584 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2585 lookup.len, lookup.arrayZ,
2586 lookup_context);
2587 }
2588
2589 bool would_apply (hb_would_apply_context_t *c) const
2590 {
2591 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
2592 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
2593 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
2594 struct ChainContextApplyLookupContext lookup_context = {
2595 {match_coverage},
2596 {this, this, this}
2597 };
2598 return chain_context_would_apply_lookup (c,
2599 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2600 input.len, (const HBUINT16 *) input.arrayZ + 1,
2601 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2602 lookup.len, lookup.arrayZ, lookup_context);
2603 }
2604
2605 const Coverage &get_coverage () const
2606 {
2607 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
2608 return this+input[0];
2609 }
2610
2611 bool apply (hb_ot_apply_context_t *c) const
2612 {
2613 TRACE_APPLY (this);
2614 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
2615
2616 unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint);
2617 if (likely (index == NOT_COVERED)) return_trace (false);
2618
2619 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
2620 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
2621 struct ChainContextApplyLookupContext lookup_context = {
2622 {match_coverage},
2623 {this, this, this}
2624 };
2625 return_trace (chain_context_apply_lookup (c,
2626 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2627 input.len, (const HBUINT16 *) input.arrayZ + 1,
2628 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2629 lookup.len, lookup.arrayZ, lookup_context));
2630 }
2631
2632 template<typename Iterator,
2633 hb_requires (hb_is_iterator (Iterator))>
2634 bool serialize_coverage_offsets (hb_subset_context_t *c,
2635 Iterator it,
2636 const void* src_base,
2637 const void* dst_base) const
2638 {
2639 TRACE_SERIALIZE (this);
2640 auto *out = c->serializer->start_embed<OffsetArrayOf<Coverage>> ();
2641
2642 if (unlikely (!c->serializer->allocate_size<HBUINT16> (HBUINT16::static_size))) return_trace (false);
2643
2644 + it
2645 | hb_apply (subset_offset_array (c, *out, src_base, dst_base))
2646 ;
2647
2648 return_trace (out->len);
2649 }
2650
2651 bool subset (hb_subset_context_t *c) const
2652 {
2653 TRACE_SUBSET (this);
2654
2655 auto *out = c->serializer->start_embed (this);
2656 if (unlikely (!out)) return_trace (false);
2657 if (unlikely (!c->serializer->embed (this->format))) return_trace (false);
2658
2659 if (!serialize_coverage_offsets (c, backtrack.iter (), this, out))
2660 return_trace (false);
2661
2662 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
2663 if (!serialize_coverage_offsets (c, input.iter (), this, out))
2664 return_trace (false);
2665
2666 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
2667 if (!serialize_coverage_offsets (c, lookahead.iter (), this, out))
2668 return_trace (false);
2669
2670 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
2671 return_trace (c->serializer->copy (lookup));
2672 }
2673
2674 bool sanitize (hb_sanitize_context_t *c) const
2675 {
2676 TRACE_SANITIZE (this);
2677 if (!backtrack.sanitize (c, this)) return_trace (false);
2678 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
2679 if (!input.sanitize (c, this)) return_trace (false);
2680 if (!input.len) return_trace (false); /* To be consistent with Context. */
2681 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (input);
2682 if (!lookahead.sanitize (c, this)) return_trace (false);
2683 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord>> (lookahead);
2684 return_trace (lookup.sanitize (c));
2685 }
2686
2687 protected:
2688 HBUINT16 format; /* Format identifier--format = 3 */
2689 OffsetArrayOf<Coverage>
2690 backtrack; /* Array of coverage tables
2691 * in backtracking sequence, in glyph
2692 * sequence order */
2693 OffsetArrayOf<Coverage>
2694 inputX ; /* Array of coverage
2695 * tables in input sequence, in glyph
2696 * sequence order */
2697 OffsetArrayOf<Coverage>
2698 lookaheadX; /* Array of coverage tables
2699 * in lookahead sequence, in glyph
2700 * sequence order */
2701 ArrayOf<LookupRecord>
2702 lookupX; /* Array of LookupRecords--in
2703 * design order) */
2704 public:
2705 DEFINE_SIZE_MIN (10);
2706};
2707
2708struct ChainContext
2709{
2710 template <typename context_t, typename ...Ts>
2711 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
2712 {
2713 TRACE_DISPATCH (this, u.format);
2714 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
2715 switch (u.format) {
2716 case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
2717 case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
2718 case 3: return_trace (c->dispatch (u.format3, hb_forward<Ts> (ds)...));
2719 default:return_trace (c->default_return_value ());
2720 }
2721 }
2722
2723 protected:
2724 union {
2725 HBUINT16 format; /* Format identifier */
2726 ChainContextFormat1 format1;
2727 ChainContextFormat2 format2;
2728 ChainContextFormat3 format3;
2729 } u;
2730};
2731
2732
2733template <typename T>
2734struct ExtensionFormat1
2735{
2736 unsigned int get_type () const { return extensionLookupType; }
2737
2738 template <typename X>
2739 const X& get_subtable () const
2740 { return this + CastR<LOffsetTo<typename T::SubTable>> (extensionOffset); }
2741
2742 template <typename context_t, typename ...Ts>
2743 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
2744 {
2745 TRACE_DISPATCH (this, format);
2746 if (unlikely (!c->may_dispatch (this, this))) return_trace (c->no_dispatch_return_value ());
2747 return_trace (get_subtable<typename T::SubTable> ().dispatch (c, get_type (), hb_forward<Ts> (ds)...));
2748 }
2749
2750 /* This is called from may_dispatch() above with hb_sanitize_context_t. */
2751 bool sanitize (hb_sanitize_context_t *c) const
2752 {
2753 TRACE_SANITIZE (this);
2754 return_trace (c->check_struct (this) &&
2755 extensionLookupType != T::SubTable::Extension);
2756 }
2757
2758 protected:
2759 HBUINT16 format; /* Format identifier. Set to 1. */
2760 HBUINT16 extensionLookupType; /* Lookup type of subtable referenced
2761 * by ExtensionOffset (i.e. the
2762 * extension subtable). */
2763 Offset32 extensionOffset; /* Offset to the extension subtable,
2764 * of lookup type subtable. */
2765 public:
2766 DEFINE_SIZE_STATIC (8);
2767};
2768
2769template <typename T>
2770struct Extension
2771{
2772 unsigned int get_type () const
2773 {
2774 switch (u.format) {
2775 case 1: return u.format1.get_type ();
2776 default:return 0;
2777 }
2778 }
2779 template <typename X>
2780 const X& get_subtable () const
2781 {
2782 switch (u.format) {
2783 case 1: return u.format1.template get_subtable<typename T::SubTable> ();
2784 default:return Null(typename T::SubTable);
2785 }
2786 }
2787
2788 template <typename context_t, typename ...Ts>
2789 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
2790 {
2791 TRACE_DISPATCH (this, u.format);
2792 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
2793 switch (u.format) {
2794 case 1: return_trace (u.format1.dispatch (c, hb_forward<Ts> (ds)...));
2795 default:return_trace (c->default_return_value ());
2796 }
2797 }
2798
2799 protected:
2800 union {
2801 HBUINT16 format; /* Format identifier */
2802 ExtensionFormat1<T> format1;
2803 } u;
2804};
2805
2806
2807/*
2808 * GSUB/GPOS Common
2809 */
2810
2811struct hb_ot_layout_lookup_accelerator_t
2812{
2813 template <typename TLookup>
2814 void init (const TLookup &lookup)
2815 {
2816 digest.init ();
2817 lookup.add_coverage (&digest);
2818
2819 subtables.init ();
2820 OT::hb_get_subtables_context_t c_get_subtables (subtables);
2821 lookup.dispatch (&c_get_subtables);
2822 }
2823 void fini () { subtables.fini (); }
2824
2825 bool may_have (hb_codepoint_t g) const
2826 { return digest.may_have (g); }
2827
2828 bool apply (hb_ot_apply_context_t *c) const
2829 {
2830 for (unsigned int i = 0; i < subtables.length; i++)
2831 if (subtables[i].apply (c))
2832 return true;
2833 return false;
2834 }
2835
2836 private:
2837 hb_set_digest_t digest;
2838 hb_get_subtables_context_t::array_t subtables;
2839};
2840
2841struct GSUBGPOS
2842{
2843 bool has_data () const { return version.to_int (); }
2844 unsigned int get_script_count () const
2845 { return (this+scriptList).len; }
2846 const Tag& get_script_tag (unsigned int i) const
2847 { return (this+scriptList).get_tag (i); }
2848 unsigned int get_script_tags (unsigned int start_offset,
2849 unsigned int *script_count /* IN/OUT */,
2850 hb_tag_t *script_tags /* OUT */) const
2851 { return (this+scriptList).get_tags (start_offset, script_count, script_tags); }
2852 const Script& get_script (unsigned int i) const
2853 { return (this+scriptList)[i]; }
2854 bool find_script_index (hb_tag_t tag, unsigned int *index) const
2855 { return (this+scriptList).find_index (tag, index); }
2856
2857 unsigned int get_feature_count () const
2858 { return (this+featureList).len; }
2859 hb_tag_t get_feature_tag (unsigned int i) const
2860 { return i == Index::NOT_FOUND_INDEX ? HB_TAG_NONE : (this+featureList).get_tag (i); }
2861 unsigned int get_feature_tags (unsigned int start_offset,
2862 unsigned int *feature_count /* IN/OUT */,
2863 hb_tag_t *feature_tags /* OUT */) const
2864 { return (this+featureList).get_tags (start_offset, feature_count, feature_tags); }
2865 const Feature& get_feature (unsigned int i) const
2866 { return (this+featureList)[i]; }
2867 bool find_feature_index (hb_tag_t tag, unsigned int *index) const
2868 { return (this+featureList).find_index (tag, index); }
2869
2870 unsigned int get_lookup_count () const
2871 { return (this+lookupList).len; }
2872 const Lookup& get_lookup (unsigned int i) const
2873 { return (this+lookupList)[i]; }
2874
2875 bool find_variations_index (const int *coords, unsigned int num_coords,
2876 unsigned int *index) const
2877 {
2878#ifdef HB_NOVAR
2879 return false;
2880#endif
2881 return (version.to_int () >= 0x00010001u ? this+featureVars : Null(FeatureVariations))
2882 .find_index (coords, num_coords, index);
2883 }
2884 const Feature& get_feature_variation (unsigned int feature_index,
2885 unsigned int variations_index) const
2886 {
2887#ifndef HB_NO_VAR
2888 if (FeatureVariations::NOT_FOUND_INDEX != variations_index &&
2889 version.to_int () >= 0x00010001u)
2890 {
2891 const Feature *feature = (this+featureVars).find_substitute (variations_index,
2892 feature_index);
2893 if (feature)
2894 return *feature;
2895 }
2896#endif
2897 return get_feature (feature_index);
2898 }
2899
2900 template <typename TLookup>
2901 bool subset (hb_subset_context_t *c) const
2902 {
2903 TRACE_SUBSET (this);
2904 auto *out = c->serializer->embed (*this);
2905 if (unlikely (!out)) return_trace (false);
2906
2907 out->scriptList.serialize_subset (c, scriptList, this, out);
2908 out->featureList.serialize_subset (c, featureList, this, out);
2909
2910 typedef OffsetListOf<TLookup> TLookupList;
2911 /* TODO Use intersects() to count how many subtables survive? */
2912 CastR<OffsetTo<TLookupList>> (out->lookupList)
2913 .serialize_subset (c,
2914 CastR<OffsetTo<TLookupList>> (lookupList),
2915 this,
2916 out);
2917
2918#ifndef HB_NO_VAR
2919 if (version.to_int () >= 0x00010001u)
2920 out->featureVars.serialize_copy (c->serializer, featureVars, this, out);
2921#endif
2922
2923 return_trace (true);
2924 }
2925
2926 unsigned int get_size () const
2927 {
2928 return min_size +
2929 (version.to_int () >= 0x00010001u ? featureVars.static_size : 0);
2930 }
2931
2932 template <typename TLookup>
2933 bool sanitize (hb_sanitize_context_t *c) const
2934 {
2935 TRACE_SANITIZE (this);
2936 typedef OffsetListOf<TLookup> TLookupList;
2937 if (unlikely (!(version.sanitize (c) &&
2938 likely (version.major == 1) &&
2939 scriptList.sanitize (c, this) &&
2940 featureList.sanitize (c, this) &&
2941 CastR<OffsetTo<TLookupList>> (lookupList).sanitize (c, this))))
2942 return_trace (false);
2943
2944#ifndef HB_NO_VAR
2945 if (unlikely (!(version.to_int () < 0x00010001u || featureVars.sanitize (c, this))))
2946 return_trace (false);
2947#endif
2948
2949 return_trace (true);
2950 }
2951
2952 template <typename T>
2953 struct accelerator_t
2954 {
2955 void init (hb_face_t *face)
2956 {
2957 this->table = hb_sanitize_context_t().reference_table<T> (face);
2958 if (unlikely (this->table->is_blacklisted (this->table.get_blob (), face)))
2959 {
2960 hb_blob_destroy (this->table.get_blob ());
2961 this->table = hb_blob_get_empty ();
2962 }
2963
2964 this->lookup_count = table->get_lookup_count ();
2965
2966 this->accels = (hb_ot_layout_lookup_accelerator_t *) calloc (this->lookup_count, sizeof (hb_ot_layout_lookup_accelerator_t));
2967 if (unlikely (!this->accels))
2968 this->lookup_count = 0;
2969
2970 for (unsigned int i = 0; i < this->lookup_count; i++)
2971 this->accels[i].init (table->get_lookup (i));
2972 }
2973
2974 void fini ()
2975 {
2976 for (unsigned int i = 0; i < this->lookup_count; i++)
2977 this->accels[i].fini ();
2978 free (this->accels);
2979 this->table.destroy ();
2980 }
2981
2982 hb_blob_ptr_t<T> table;
2983 unsigned int lookup_count;
2984 hb_ot_layout_lookup_accelerator_t *accels;
2985 };
2986
2987 protected:
2988 FixedVersion<>version; /* Version of the GSUB/GPOS table--initially set
2989 * to 0x00010000u */
2990 OffsetTo<ScriptList>
2991 scriptList; /* ScriptList table */
2992 OffsetTo<FeatureList>
2993 featureList; /* FeatureList table */
2994 OffsetTo<LookupList>
2995 lookupList; /* LookupList table */
2996 LOffsetTo<FeatureVariations>
2997 featureVars; /* Offset to Feature Variations
2998 table--from beginning of table
2999 * (may be NULL). Introduced
3000 * in version 0x00010001. */
3001 public:
3002 DEFINE_SIZE_MIN (10);
3003};
3004
3005
3006} /* namespace OT */
3007
3008
3009#endif /* HB_OT_LAYOUT_GSUBGPOS_HH */
3010