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
41 namespace OT {
42
43
44 struct hb_intersects_context_t :
45 hb_dispatch_context_t<hb_intersects_context_t, bool, 0>
46 {
get_nameOT::hb_intersects_context_t47 const char *get_name () { return "INTERSECTS"; }
48 template <typename T>
dispatchOT::hb_intersects_context_t49 return_t dispatch (const T &obj) { return obj.intersects (this->glyphs); }
default_return_valueOT::hb_intersects_context_t50 static return_t default_return_value () { return false; }
stop_sublookup_iterationOT::hb_intersects_context_t51 bool stop_sublookup_iteration (return_t r) const { return r; }
52
53 const hb_set_t *glyphs;
54 unsigned int debug_depth;
55
hb_intersects_context_tOT::hb_intersects_context_t56 hb_intersects_context_t (const hb_set_t *glyphs_) :
57 glyphs (glyphs_),
58 debug_depth (0) {}
59 };
60
61 struct hb_closure_context_t :
62 hb_dispatch_context_t<hb_closure_context_t, hb_void_t, HB_DEBUG_CLOSURE>
63 {
get_nameOT::hb_closure_context_t64 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>
dispatchOT::hb_closure_context_t67 return_t dispatch (const T &obj) { obj.closure (this); return HB_VOID; }
default_return_valueOT::hb_closure_context_t68 static return_t default_return_value () { return HB_VOID; }
recurseOT::hb_closure_context_t69 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
should_visit_lookupOT::hb_closure_context_t79 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
is_lookup_doneOT::hb_closure_context_t87 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 out[1];
96 recurse_func_t recurse_func;
97 unsigned int nesting_level_left;
98 unsigned int debug_depth;
99
hb_closure_context_tOT::hb_closure_context_t100 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
~hb_closure_context_tOT::hb_closure_context_t111 ~hb_closure_context_t () { flush (); }
112
set_recurse_funcOT::hb_closure_context_t113 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
114
flushOT::hb_closure_context_t115 void flush ()
116 {
117 hb_set_union (glyphs, out);
118 hb_set_clear (out);
119 }
120
121 private:
122 hb_map_t *done_lookups;
123 };
124
125
126 struct hb_would_apply_context_t :
127 hb_dispatch_context_t<hb_would_apply_context_t, bool, HB_DEBUG_WOULD_APPLY>
128 {
get_nameOT::hb_would_apply_context_t129 const char *get_name () { return "WOULD_APPLY"; }
130 template <typename T>
dispatchOT::hb_would_apply_context_t131 return_t dispatch (const T &obj) { return obj.would_apply (this); }
default_return_valueOT::hb_would_apply_context_t132 static return_t default_return_value () { return false; }
stop_sublookup_iterationOT::hb_would_apply_context_t133 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
hb_would_apply_context_tOT::hb_would_apply_context_t141 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
153 struct hb_collect_glyphs_context_t :
154 hb_dispatch_context_t<hb_collect_glyphs_context_t, hb_void_t, HB_DEBUG_COLLECT_GLYPHS>
155 {
get_nameOT::hb_collect_glyphs_context_t156 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>
dispatchOT::hb_collect_glyphs_context_t159 return_t dispatch (const T &obj) { obj.collect_glyphs (this); return HB_VOID; }
default_return_valueOT::hb_collect_glyphs_context_t160 static return_t default_return_value () { return HB_VOID; }
recurseOT::hb_collect_glyphs_context_t161 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
hb_collect_glyphs_context_tOT::hb_collect_glyphs_context_t209 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) {}
~hb_collect_glyphs_context_tOT::hb_collect_glyphs_context_t224 ~hb_collect_glyphs_context_t () { hb_set_destroy (recursed_lookups); }
225
set_recurse_funcOT::hb_collect_glyphs_context_t226 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
227 };
228
229
230
231 template <typename set_t>
232 struct hb_add_coverage_context_t :
233 hb_dispatch_context_t<hb_add_coverage_context_t<set_t>, const Coverage &, HB_DEBUG_GET_COVERAGE>
234 {
get_nameOT::hb_add_coverage_context_t235 const char *get_name () { return "GET_COVERAGE"; }
236 typedef const Coverage &return_t;
237 template <typename T>
dispatchOT::hb_add_coverage_context_t238 return_t dispatch (const T &obj) { return obj.get_coverage (); }
default_return_valueOT::hb_add_coverage_context_t239 static return_t default_return_value () { return Null(Coverage); }
stop_sublookup_iterationOT::hb_add_coverage_context_t240 bool stop_sublookup_iteration (return_t r) const
241 {
242 r.add_coverage (set);
243 return false;
244 }
245
hb_add_coverage_context_tOT::hb_add_coverage_context_t246 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
255 struct 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 {
matcher_tOT::hb_ot_apply_context_t::matcher_t260 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
set_ignore_zwnjOT::hb_ot_apply_context_t::matcher_t273 void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; }
set_ignore_zwjOT::hb_ot_apply_context_t::matcher_t274 void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; }
set_lookup_propsOT::hb_ot_apply_context_t::matcher_t275 void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
set_maskOT::hb_ot_apply_context_t::matcher_t276 void set_mask (hb_mask_t mask_) { mask = mask_; }
set_syllableOT::hb_ot_apply_context_t::matcher_t277 void set_syllable (uint8_t syllable_) { syllable = syllable_; }
set_match_funcOT::hb_ot_apply_context_t::matcher_t278 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
may_matchOT::hb_ot_apply_context_t::matcher_t288 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
may_skipOT::hb_ot_apply_context_t::matcher_t307 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 {
initOT::hb_ot_apply_context_t::skipping_iterator_t333 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 }
set_lookup_propsOT::hb_ot_apply_context_t::skipping_iterator_t345 void set_lookup_props (unsigned int lookup_props)
346 {
347 matcher.set_lookup_props (lookup_props);
348 }
set_match_funcOT::hb_ot_apply_context_t::skipping_iterator_t349 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
resetOT::hb_ot_apply_context_t::skipping_iterator_t357 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
rejectOT::hb_ot_apply_context_t::skipping_iterator_t366 void reject () { num_items++; match_glyph_data--; }
367
368 matcher_t::may_skip_t
may_skipOT::hb_ot_apply_context_t::skipping_iterator_t369 may_skip (const hb_glyph_info_t &info) const
370 { return matcher.may_skip (c, info); }
371
nextOT::hb_ot_apply_context_t::skipping_iterator_t372 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 match_glyph_data++;
391 return true;
392 }
393
394 if (skip == matcher_t::SKIP_NO)
395 return false;
396 }
397 return false;
398 }
prevOT::hb_ot_apply_context_t::skipping_iterator_t399 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 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
get_nameOT::hb_ot_apply_context_t438 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>
dispatchOT::hb_ot_apply_context_t441 return_t dispatch (const T &obj) { return obj.apply (this); }
default_return_valueOT::hb_ot_apply_context_t442 static return_t default_return_value () { return false; }
stop_sublookup_iterationOT::hb_ot_apply_context_t443 bool stop_sublookup_iteration (return_t r) const { return r; }
recurseOT::hb_ot_apply_context_t444 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
hb_ot_apply_context_tOT::hb_ot_apply_context_t480 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 (*face->table.GDEF->table),
487 var_store (gdef.get_var_store ()),
488 direction (buffer_->props.direction),
489 lookup_mask (1),
490 table_index (table_index_),
491 lookup_index ((unsigned int) -1),
492 lookup_props (0),
493 nesting_level_left (HB_MAX_NESTING_LEVEL),
494 debug_depth (0),
495 has_glyph_classes (gdef.has_glyph_classes ()),
496 auto_zwnj (true),
497 auto_zwj (true),
498 random (false),
499 random_state (1) { init_iters (); }
500
init_itersOT::hb_ot_apply_context_t501 void init_iters ()
502 {
503 iter_input.init (this, false);
504 iter_context.init (this, true);
505 }
506
set_lookup_maskOT::hb_ot_apply_context_t507 void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; init_iters (); }
set_auto_zwjOT::hb_ot_apply_context_t508 void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; init_iters (); }
set_auto_zwnjOT::hb_ot_apply_context_t509 void set_auto_zwnj (bool auto_zwnj_) { auto_zwnj = auto_zwnj_; init_iters (); }
set_randomOT::hb_ot_apply_context_t510 void set_random (bool random_) { random = random_; }
set_recurse_funcOT::hb_ot_apply_context_t511 void set_recurse_func (recurse_func_t func) { recurse_func = func; }
set_lookup_indexOT::hb_ot_apply_context_t512 void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; }
set_lookup_propsOT::hb_ot_apply_context_t513 void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; init_iters (); }
514
random_numberOT::hb_ot_apply_context_t515 uint32_t random_number ()
516 {
517 /* http://www.cplusplus.com/reference/random/minstd_rand/ */
518 random_state = random_state * 48271 % 2147483647;
519 return random_state;
520 }
521
match_properties_markOT::hb_ot_apply_context_t522 bool match_properties_mark (hb_codepoint_t glyph,
523 unsigned int glyph_props,
524 unsigned int match_props) const
525 {
526 /* If using mark filtering sets, the high short of
527 * match_props has the set index.
528 */
529 if (match_props & LookupFlag::UseMarkFilteringSet)
530 return gdef.mark_set_covers (match_props >> 16, glyph);
531
532 /* The second byte of match_props has the meaning
533 * "ignore marks of attachment type different than
534 * the attachment type specified."
535 */
536 if (match_props & LookupFlag::MarkAttachmentType)
537 return (match_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType);
538
539 return true;
540 }
541
check_glyph_propertyOT::hb_ot_apply_context_t542 bool check_glyph_property (const hb_glyph_info_t *info,
543 unsigned int match_props) const
544 {
545 hb_codepoint_t glyph = info->codepoint;
546 unsigned int glyph_props = _hb_glyph_info_get_glyph_props (info);
547
548 /* Not covered, if, for example, glyph class is ligature and
549 * match_props includes LookupFlags::IgnoreLigatures
550 */
551 if (glyph_props & match_props & LookupFlag::IgnoreFlags)
552 return false;
553
554 if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK))
555 return match_properties_mark (glyph, glyph_props, match_props);
556
557 return true;
558 }
559
_set_glyph_propsOT::hb_ot_apply_context_t560 void _set_glyph_props (hb_codepoint_t glyph_index,
561 unsigned int class_guess = 0,
562 bool ligature = false,
563 bool component = false) const
564 {
565 unsigned int add_in = _hb_glyph_info_get_glyph_props (&buffer->cur()) &
566 HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE;
567 add_in |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED;
568 if (ligature)
569 {
570 add_in |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED;
571 /* In the only place that the MULTIPLIED bit is used, Uniscribe
572 * seems to only care about the "last" transformation between
573 * Ligature and Multiple substitutions. Ie. if you ligate, expand,
574 * and ligate again, it forgives the multiplication and acts as
575 * if only ligation happened. As such, clear MULTIPLIED bit.
576 */
577 add_in &= ~HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
578 }
579 if (component)
580 add_in |= HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED;
581 if (likely (has_glyph_classes))
582 _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | gdef.get_glyph_props (glyph_index));
583 else if (class_guess)
584 _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | class_guess);
585 }
586
replace_glyphOT::hb_ot_apply_context_t587 void replace_glyph (hb_codepoint_t glyph_index) const
588 {
589 _set_glyph_props (glyph_index);
590 buffer->replace_glyph (glyph_index);
591 }
replace_glyph_inplaceOT::hb_ot_apply_context_t592 void replace_glyph_inplace (hb_codepoint_t glyph_index) const
593 {
594 _set_glyph_props (glyph_index);
595 buffer->cur().codepoint = glyph_index;
596 }
replace_glyph_with_ligatureOT::hb_ot_apply_context_t597 void replace_glyph_with_ligature (hb_codepoint_t glyph_index,
598 unsigned int class_guess) const
599 {
600 _set_glyph_props (glyph_index, class_guess, true);
601 buffer->replace_glyph (glyph_index);
602 }
output_glyph_for_componentOT::hb_ot_apply_context_t603 void output_glyph_for_component (hb_codepoint_t glyph_index,
604 unsigned int class_guess) const
605 {
606 _set_glyph_props (glyph_index, class_guess, false, true);
607 buffer->output_glyph (glyph_index);
608 }
609 };
610
611
612 struct hb_get_subtables_context_t :
613 hb_dispatch_context_t<hb_get_subtables_context_t, hb_void_t, HB_DEBUG_APPLY>
614 {
615 template <typename Type>
apply_toOT::hb_get_subtables_context_t616 static bool apply_to (const void *obj, OT::hb_ot_apply_context_t *c)
617 {
618 const Type *typed_obj = (const Type *) obj;
619 return typed_obj->apply (c);
620 }
621
622 typedef bool (*hb_apply_func_t) (const void *obj, OT::hb_ot_apply_context_t *c);
623
624 struct hb_applicable_t
625 {
626 template <typename T>
initOT::hb_get_subtables_context_t::hb_applicable_t627 void init (const T &obj_, hb_apply_func_t apply_func_)
628 {
629 obj = &obj_;
630 apply_func = apply_func_;
631 digest.init ();
632 obj_.get_coverage ().add_coverage (&digest);
633 }
634
applyOT::hb_get_subtables_context_t::hb_applicable_t635 bool apply (OT::hb_ot_apply_context_t *c) const
636 {
637 return digest.may_have (c->buffer->cur().codepoint) && apply_func (obj, c);
638 }
639
640 private:
641 const void *obj;
642 hb_apply_func_t apply_func;
643 hb_set_digest_t digest;
644 };
645
646 typedef hb_vector_t<hb_applicable_t, 2> array_t;
647
648 /* Dispatch interface. */
get_nameOT::hb_get_subtables_context_t649 const char *get_name () { return "GET_SUBTABLES"; }
650 template <typename T>
dispatchOT::hb_get_subtables_context_t651 return_t dispatch (const T &obj)
652 {
653 hb_applicable_t *entry = array.push();
654 entry->init (obj, apply_to<T>);
655 return HB_VOID;
656 }
default_return_valueOT::hb_get_subtables_context_t657 static return_t default_return_value () { return HB_VOID; }
658
hb_get_subtables_context_tOT::hb_get_subtables_context_t659 hb_get_subtables_context_t (array_t &array_) :
660 array (array_),
661 debug_depth (0) {}
662
663 array_t &array;
664 unsigned int debug_depth;
665 };
666
667
668
669
670 typedef bool (*intersects_func_t) (const hb_set_t *glyphs, const HBUINT16 &value, const void *data);
671 typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const HBUINT16 &value, const void *data);
672 typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data);
673
674 struct ContextClosureFuncs
675 {
676 intersects_func_t intersects;
677 };
678 struct ContextCollectGlyphsFuncs
679 {
680 collect_glyphs_func_t collect;
681 };
682 struct ContextApplyFuncs
683 {
684 match_func_t match;
685 };
686
687
intersects_glyph(const hb_set_t * glyphs,const HBUINT16 & value,const void * data HB_UNUSED)688 static inline bool intersects_glyph (const hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
689 {
690 return glyphs->has (value);
691 }
intersects_class(const hb_set_t * glyphs,const HBUINT16 & value,const void * data)692 static inline bool intersects_class (const hb_set_t *glyphs, const HBUINT16 &value, const void *data)
693 {
694 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
695 return class_def.intersects_class (glyphs, value);
696 }
intersects_coverage(const hb_set_t * glyphs,const HBUINT16 & value,const void * data)697 static inline bool intersects_coverage (const hb_set_t *glyphs, const HBUINT16 &value, const void *data)
698 {
699 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
700 return (data+coverage).intersects (glyphs);
701 }
702
intersects_array(const hb_set_t * glyphs,unsigned int count,const HBUINT16 values[],intersects_func_t intersects_func,const void * intersects_data)703 static inline bool intersects_array (const hb_set_t *glyphs,
704 unsigned int count,
705 const HBUINT16 values[],
706 intersects_func_t intersects_func,
707 const void *intersects_data)
708 {
709 for (unsigned int i = 0; i < count; i++)
710 if (likely (!intersects_func (glyphs, values[i], intersects_data)))
711 return false;
712 return true;
713 }
714
715
collect_glyph(hb_set_t * glyphs,const HBUINT16 & value,const void * data HB_UNUSED)716 static inline void collect_glyph (hb_set_t *glyphs, const HBUINT16 &value, const void *data HB_UNUSED)
717 {
718 glyphs->add (value);
719 }
collect_class(hb_set_t * glyphs,const HBUINT16 & value,const void * data)720 static inline void collect_class (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
721 {
722 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
723 class_def.add_class (glyphs, value);
724 }
collect_coverage(hb_set_t * glyphs,const HBUINT16 & value,const void * data)725 static inline void collect_coverage (hb_set_t *glyphs, const HBUINT16 &value, const void *data)
726 {
727 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
728 (data+coverage).add_coverage (glyphs);
729 }
collect_array(hb_collect_glyphs_context_t * c HB_UNUSED,hb_set_t * glyphs,unsigned int count,const HBUINT16 values[],collect_glyphs_func_t collect_func,const void * collect_data)730 static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED,
731 hb_set_t *glyphs,
732 unsigned int count,
733 const HBUINT16 values[],
734 collect_glyphs_func_t collect_func,
735 const void *collect_data)
736 {
737 for (unsigned int i = 0; i < count; i++)
738 collect_func (glyphs, values[i], collect_data);
739 }
740
741
match_glyph(hb_codepoint_t glyph_id,const HBUINT16 & value,const void * data HB_UNUSED)742 static inline bool match_glyph (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data HB_UNUSED)
743 {
744 return glyph_id == value;
745 }
match_class(hb_codepoint_t glyph_id,const HBUINT16 & value,const void * data)746 static inline bool match_class (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data)
747 {
748 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data);
749 return class_def.get_class (glyph_id) == value;
750 }
match_coverage(hb_codepoint_t glyph_id,const HBUINT16 & value,const void * data)751 static inline bool match_coverage (hb_codepoint_t glyph_id, const HBUINT16 &value, const void *data)
752 {
753 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value;
754 return (data+coverage).get_coverage (glyph_id) != NOT_COVERED;
755 }
756
would_match_input(hb_would_apply_context_t * c,unsigned int count,const HBUINT16 input[],match_func_t match_func,const void * match_data)757 static inline bool would_match_input (hb_would_apply_context_t *c,
758 unsigned int count, /* Including the first glyph (not matched) */
759 const HBUINT16 input[], /* Array of input values--start with second glyph */
760 match_func_t match_func,
761 const void *match_data)
762 {
763 if (count != c->len)
764 return false;
765
766 for (unsigned int i = 1; i < count; i++)
767 if (likely (!match_func (c->glyphs[i], input[i - 1], match_data)))
768 return false;
769
770 return true;
771 }
match_input(hb_ot_apply_context_t * c,unsigned int count,const HBUINT16 input[],match_func_t match_func,const void * match_data,unsigned int * end_offset,unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],unsigned int * p_total_component_count=nullptr)772 static inline bool match_input (hb_ot_apply_context_t *c,
773 unsigned int count, /* Including the first glyph (not matched) */
774 const HBUINT16 input[], /* Array of input values--start with second glyph */
775 match_func_t match_func,
776 const void *match_data,
777 unsigned int *end_offset,
778 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],
779 unsigned int *p_total_component_count = nullptr)
780 {
781 TRACE_APPLY (nullptr);
782
783 if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return_trace (false);
784
785 hb_buffer_t *buffer = c->buffer;
786
787 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
788 skippy_iter.reset (buffer->idx, count - 1);
789 skippy_iter.set_match_func (match_func, match_data, input);
790
791 /*
792 * This is perhaps the trickiest part of OpenType... Remarks:
793 *
794 * - If all components of the ligature were marks, we call this a mark ligature.
795 *
796 * - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize
797 * it as a ligature glyph.
798 *
799 * - Ligatures cannot be formed across glyphs attached to different components
800 * of previous ligatures. Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and
801 * LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother.
802 * However, it would be wrong to ligate that SHADDA,FATHA sequence.
803 * There are a couple of exceptions to this:
804 *
805 * o If a ligature tries ligating with marks that belong to it itself, go ahead,
806 * assuming that the font designer knows what they are doing (otherwise it can
807 * break Indic stuff when a matra wants to ligate with a conjunct,
808 *
809 * o If two marks want to ligate and they belong to different components of the
810 * same ligature glyph, and said ligature glyph is to be ignored according to
811 * mark-filtering rules, then allow.
812 * https://github.com/harfbuzz/harfbuzz/issues/545
813 */
814
815 unsigned int total_component_count = 0;
816 total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur());
817
818 unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
819 unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
820
821 enum {
822 LIGBASE_NOT_CHECKED,
823 LIGBASE_MAY_NOT_SKIP,
824 LIGBASE_MAY_SKIP
825 } ligbase = LIGBASE_NOT_CHECKED;
826
827 match_positions[0] = buffer->idx;
828 for (unsigned int i = 1; i < count; i++)
829 {
830 if (!skippy_iter.next ()) return_trace (false);
831
832 match_positions[i] = skippy_iter.idx;
833
834 unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]);
835 unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]);
836
837 if (first_lig_id && first_lig_comp)
838 {
839 /* If first component was attached to a previous ligature component,
840 * all subsequent components should be attached to the same ligature
841 * component, otherwise we shouldn't ligate them... */
842 if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp)
843 {
844 /* ...unless, we are attached to a base ligature and that base
845 * ligature is ignorable. */
846 if (ligbase == LIGBASE_NOT_CHECKED)
847 {
848 bool found = false;
849 const hb_glyph_info_t *out = buffer->out_info;
850 unsigned int j = buffer->out_len;
851 while (j && _hb_glyph_info_get_lig_id (&out[j - 1]) == first_lig_id)
852 {
853 if (_hb_glyph_info_get_lig_comp (&out[j - 1]) == 0)
854 {
855 j--;
856 found = true;
857 break;
858 }
859 j--;
860 }
861
862 if (found && skippy_iter.may_skip (out[j]) == hb_ot_apply_context_t::matcher_t::SKIP_YES)
863 ligbase = LIGBASE_MAY_SKIP;
864 else
865 ligbase = LIGBASE_MAY_NOT_SKIP;
866 }
867
868 if (ligbase == LIGBASE_MAY_NOT_SKIP)
869 return_trace (false);
870 }
871 }
872 else
873 {
874 /* If first component was NOT attached to a previous ligature component,
875 * all subsequent components should also NOT be attached to any ligature
876 * component, unless they are attached to the first component itself! */
877 if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id))
878 return_trace (false);
879 }
880
881 total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]);
882 }
883
884 *end_offset = skippy_iter.idx - buffer->idx + 1;
885
886 if (p_total_component_count)
887 *p_total_component_count = total_component_count;
888
889 return_trace (true);
890 }
ligate_input(hb_ot_apply_context_t * c,unsigned int count,const unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],unsigned int match_length,hb_codepoint_t lig_glyph,unsigned int total_component_count)891 static inline bool ligate_input (hb_ot_apply_context_t *c,
892 unsigned int count, /* Including the first glyph */
893 const unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
894 unsigned int match_length,
895 hb_codepoint_t lig_glyph,
896 unsigned int total_component_count)
897 {
898 TRACE_APPLY (nullptr);
899
900 hb_buffer_t *buffer = c->buffer;
901
902 buffer->merge_clusters (buffer->idx, buffer->idx + match_length);
903
904 /* - If a base and one or more marks ligate, consider that as a base, NOT
905 * ligature, such that all following marks can still attach to it.
906 * https://github.com/harfbuzz/harfbuzz/issues/1109
907 *
908 * - If all components of the ligature were marks, we call this a mark ligature.
909 * If it *is* a mark ligature, we don't allocate a new ligature id, and leave
910 * the ligature to keep its old ligature id. This will allow it to attach to
911 * a base ligature in GPOS. Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH,
912 * and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA with a
913 * ligature id and component value of 2. Then if SHADDA,FATHA form a ligature
914 * later, we don't want them to lose their ligature id/component, otherwise
915 * GPOS will fail to correctly position the mark ligature on top of the
916 * LAM,LAM,HEH ligature. See:
917 * https://bugzilla.gnome.org/show_bug.cgi?id=676343
918 *
919 * - If a ligature is formed of components that some of which are also ligatures
920 * themselves, and those ligature components had marks attached to *their*
921 * components, we have to attach the marks to the new ligature component
922 * positions! Now *that*'s tricky! And these marks may be following the
923 * last component of the whole sequence, so we should loop forward looking
924 * for them and update them.
925 *
926 * Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a
927 * 'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature
928 * id and component == 1. Now, during 'liga', the LAM and the LAM-HEH ligature
929 * form a LAM-LAM-HEH ligature. We need to reassign the SHADDA and FATHA to
930 * the new ligature with a component value of 2.
931 *
932 * This in fact happened to a font... See:
933 * https://bugzilla.gnome.org/show_bug.cgi?id=437633
934 */
935
936 bool is_base_ligature = _hb_glyph_info_is_base_glyph (&buffer->info[match_positions[0]]);
937 bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->info[match_positions[0]]);
938 for (unsigned int i = 1; i < count; i++)
939 if (!_hb_glyph_info_is_mark (&buffer->info[match_positions[i]]))
940 {
941 is_base_ligature = false;
942 is_mark_ligature = false;
943 break;
944 }
945 bool is_ligature = !is_base_ligature && !is_mark_ligature;
946
947 unsigned int klass = is_ligature ? HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE : 0;
948 unsigned int lig_id = is_ligature ? _hb_allocate_lig_id (buffer) : 0;
949 unsigned int last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
950 unsigned int last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
951 unsigned int components_so_far = last_num_components;
952
953 if (is_ligature)
954 {
955 _hb_glyph_info_set_lig_props_for_ligature (&buffer->cur(), lig_id, total_component_count);
956 if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK)
957 {
958 _hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER);
959 }
960 }
961 c->replace_glyph_with_ligature (lig_glyph, klass);
962
963 for (unsigned int i = 1; i < count; i++)
964 {
965 while (buffer->idx < match_positions[i] && buffer->successful)
966 {
967 if (is_ligature)
968 {
969 unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
970 if (this_comp == 0)
971 this_comp = last_num_components;
972 unsigned int new_lig_comp = components_so_far - last_num_components +
973 MIN (this_comp, last_num_components);
974 _hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp);
975 }
976 buffer->next_glyph ();
977 }
978
979 last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur());
980 last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur());
981 components_so_far += last_num_components;
982
983 /* Skip the base glyph */
984 buffer->idx++;
985 }
986
987 if (!is_mark_ligature && last_lig_id) {
988 /* Re-adjust components for any marks following. */
989 for (unsigned int i = buffer->idx; i < buffer->len; i++) {
990 if (last_lig_id == _hb_glyph_info_get_lig_id (&buffer->info[i])) {
991 unsigned int this_comp = _hb_glyph_info_get_lig_comp (&buffer->info[i]);
992 if (!this_comp)
993 break;
994 unsigned int new_lig_comp = components_so_far - last_num_components +
995 MIN (this_comp, last_num_components);
996 _hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp);
997 } else
998 break;
999 }
1000 }
1001 return_trace (true);
1002 }
1003
match_backtrack(hb_ot_apply_context_t * c,unsigned int count,const HBUINT16 backtrack[],match_func_t match_func,const void * match_data,unsigned int * match_start)1004 static inline bool match_backtrack (hb_ot_apply_context_t *c,
1005 unsigned int count,
1006 const HBUINT16 backtrack[],
1007 match_func_t match_func,
1008 const void *match_data,
1009 unsigned int *match_start)
1010 {
1011 TRACE_APPLY (nullptr);
1012
1013 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
1014 skippy_iter.reset (c->buffer->backtrack_len (), count);
1015 skippy_iter.set_match_func (match_func, match_data, backtrack);
1016
1017 for (unsigned int i = 0; i < count; i++)
1018 if (!skippy_iter.prev ())
1019 return_trace (false);
1020
1021 *match_start = skippy_iter.idx;
1022
1023 return_trace (true);
1024 }
1025
match_lookahead(hb_ot_apply_context_t * c,unsigned int count,const HBUINT16 lookahead[],match_func_t match_func,const void * match_data,unsigned int offset,unsigned int * end_index)1026 static inline bool match_lookahead (hb_ot_apply_context_t *c,
1027 unsigned int count,
1028 const HBUINT16 lookahead[],
1029 match_func_t match_func,
1030 const void *match_data,
1031 unsigned int offset,
1032 unsigned int *end_index)
1033 {
1034 TRACE_APPLY (nullptr);
1035
1036 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
1037 skippy_iter.reset (c->buffer->idx + offset - 1, count);
1038 skippy_iter.set_match_func (match_func, match_data, lookahead);
1039
1040 for (unsigned int i = 0; i < count; i++)
1041 if (!skippy_iter.next ())
1042 return_trace (false);
1043
1044 *end_index = skippy_iter.idx + 1;
1045
1046 return_trace (true);
1047 }
1048
1049
1050
1051 struct LookupRecord
1052 {
sanitizeOT::LookupRecord1053 bool sanitize (hb_sanitize_context_t *c) const
1054 {
1055 TRACE_SANITIZE (this);
1056 return_trace (c->check_struct (this));
1057 }
1058
1059 HBUINT16 sequenceIndex; /* Index into current glyph
1060 * sequence--first glyph = 0 */
1061 HBUINT16 lookupListIndex; /* Lookup to apply to that
1062 * position--zero--based */
1063 public:
1064 DEFINE_SIZE_STATIC (4);
1065 };
1066
1067 template <typename context_t>
recurse_lookups(context_t * c,unsigned int lookupCount,const LookupRecord lookupRecord[])1068 static inline void recurse_lookups (context_t *c,
1069 unsigned int lookupCount,
1070 const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */)
1071 {
1072 for (unsigned int i = 0; i < lookupCount; i++)
1073 c->recurse (lookupRecord[i].lookupListIndex);
1074 }
1075
apply_lookup(hb_ot_apply_context_t * c,unsigned int count,unsigned int match_positions[HB_MAX_CONTEXT_LENGTH],unsigned int lookupCount,const LookupRecord lookupRecord[],unsigned int match_length)1076 static inline bool apply_lookup (hb_ot_apply_context_t *c,
1077 unsigned int count, /* Including the first glyph */
1078 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */
1079 unsigned int lookupCount,
1080 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */
1081 unsigned int match_length)
1082 {
1083 TRACE_APPLY (nullptr);
1084
1085 hb_buffer_t *buffer = c->buffer;
1086 int end;
1087
1088 /* All positions are distance from beginning of *output* buffer.
1089 * Adjust. */
1090 {
1091 unsigned int bl = buffer->backtrack_len ();
1092 end = bl + match_length;
1093
1094 int delta = bl - buffer->idx;
1095 /* Convert positions to new indexing. */
1096 for (unsigned int j = 0; j < count; j++)
1097 match_positions[j] += delta;
1098 }
1099
1100 for (unsigned int i = 0; i < lookupCount && buffer->successful; i++)
1101 {
1102 unsigned int idx = lookupRecord[i].sequenceIndex;
1103 if (idx >= count)
1104 continue;
1105
1106 /* Don't recurse to ourself at same position.
1107 * Note that this test is too naive, it doesn't catch longer loops. */
1108 if (idx == 0 && lookupRecord[i].lookupListIndex == c->lookup_index)
1109 continue;
1110
1111 if (unlikely (!buffer->move_to (match_positions[idx])))
1112 break;
1113
1114 if (unlikely (buffer->max_ops <= 0))
1115 break;
1116
1117 unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len ();
1118 if (!c->recurse (lookupRecord[i].lookupListIndex))
1119 continue;
1120
1121 unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len ();
1122 int delta = new_len - orig_len;
1123
1124 if (!delta)
1125 continue;
1126
1127 /* Recursed lookup changed buffer len. Adjust.
1128 *
1129 * TODO:
1130 *
1131 * Right now, if buffer length increased by n, we assume n new glyphs
1132 * were added right after the current position, and if buffer length
1133 * was decreased by n, we assume n match positions after the current
1134 * one where removed. The former (buffer length increased) case is
1135 * fine, but the decrease case can be improved in at least two ways,
1136 * both of which are significant:
1137 *
1138 * - If recursed-to lookup is MultipleSubst and buffer length
1139 * decreased, then it's current match position that was deleted,
1140 * NOT the one after it.
1141 *
1142 * - If buffer length was decreased by n, it does not necessarily
1143 * mean that n match positions where removed, as there might
1144 * have been marks and default-ignorables in the sequence. We
1145 * should instead drop match positions between current-position
1146 * and current-position + n instead.
1147 *
1148 * It should be possible to construct tests for both of these cases.
1149 */
1150
1151 end += delta;
1152 if (end <= int (match_positions[idx]))
1153 {
1154 /* End might end up being smaller than match_positions[idx] if the recursed
1155 * lookup ended up removing many items, more than we have had matched.
1156 * Just never rewind end back and get out of here.
1157 * https://bugs.chromium.org/p/chromium/issues/detail?id=659496 */
1158 end = match_positions[idx];
1159 /* There can't be any further changes. */
1160 break;
1161 }
1162
1163 unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */
1164
1165 if (delta > 0)
1166 {
1167 if (unlikely (delta + count > HB_MAX_CONTEXT_LENGTH))
1168 break;
1169 }
1170 else
1171 {
1172 /* NOTE: delta is negative. */
1173 delta = MAX (delta, (int) next - (int) count);
1174 next -= delta;
1175 }
1176
1177 /* Shift! */
1178 memmove (match_positions + next + delta, match_positions + next,
1179 (count - next) * sizeof (match_positions[0]));
1180 next += delta;
1181 count += delta;
1182
1183 /* Fill in new entries. */
1184 for (unsigned int j = idx + 1; j < next; j++)
1185 match_positions[j] = match_positions[j - 1] + 1;
1186
1187 /* And fixup the rest. */
1188 for (; next < count; next++)
1189 match_positions[next] += delta;
1190 }
1191
1192 buffer->move_to (end);
1193
1194 return_trace (true);
1195 }
1196
1197
1198
1199 /* Contextual lookups */
1200
1201 struct ContextClosureLookupContext
1202 {
1203 ContextClosureFuncs funcs;
1204 const void *intersects_data;
1205 };
1206
1207 struct ContextCollectGlyphsLookupContext
1208 {
1209 ContextCollectGlyphsFuncs funcs;
1210 const void *collect_data;
1211 };
1212
1213 struct ContextApplyLookupContext
1214 {
1215 ContextApplyFuncs funcs;
1216 const void *match_data;
1217 };
1218
context_intersects(const hb_set_t * glyphs,unsigned int inputCount,const HBUINT16 input[],ContextClosureLookupContext & lookup_context)1219 static inline bool context_intersects (const hb_set_t *glyphs,
1220 unsigned int inputCount, /* Including the first glyph (not matched) */
1221 const HBUINT16 input[], /* Array of input values--start with second glyph */
1222 ContextClosureLookupContext &lookup_context)
1223 {
1224 return intersects_array (glyphs,
1225 inputCount ? inputCount - 1 : 0, input,
1226 lookup_context.funcs.intersects, lookup_context.intersects_data);
1227 }
1228
context_closure_lookup(hb_closure_context_t * c,unsigned int inputCount,const HBUINT16 input[],unsigned int lookupCount,const LookupRecord lookupRecord[],ContextClosureLookupContext & lookup_context)1229 static inline void context_closure_lookup (hb_closure_context_t *c,
1230 unsigned int inputCount, /* Including the first glyph (not matched) */
1231 const HBUINT16 input[], /* Array of input values--start with second glyph */
1232 unsigned int lookupCount,
1233 const LookupRecord lookupRecord[],
1234 ContextClosureLookupContext &lookup_context)
1235 {
1236 if (context_intersects (c->glyphs,
1237 inputCount, input,
1238 lookup_context))
1239 recurse_lookups (c,
1240 lookupCount, lookupRecord);
1241 }
1242
context_collect_glyphs_lookup(hb_collect_glyphs_context_t * c,unsigned int inputCount,const HBUINT16 input[],unsigned int lookupCount,const LookupRecord lookupRecord[],ContextCollectGlyphsLookupContext & lookup_context)1243 static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
1244 unsigned int inputCount, /* Including the first glyph (not matched) */
1245 const HBUINT16 input[], /* Array of input values--start with second glyph */
1246 unsigned int lookupCount,
1247 const LookupRecord lookupRecord[],
1248 ContextCollectGlyphsLookupContext &lookup_context)
1249 {
1250 collect_array (c, c->input,
1251 inputCount ? inputCount - 1 : 0, input,
1252 lookup_context.funcs.collect, lookup_context.collect_data);
1253 recurse_lookups (c,
1254 lookupCount, lookupRecord);
1255 }
1256
context_would_apply_lookup(hb_would_apply_context_t * c,unsigned int inputCount,const HBUINT16 input[],unsigned int lookupCount HB_UNUSED,const LookupRecord lookupRecord[]HB_UNUSED,ContextApplyLookupContext & lookup_context)1257 static inline bool context_would_apply_lookup (hb_would_apply_context_t *c,
1258 unsigned int inputCount, /* Including the first glyph (not matched) */
1259 const HBUINT16 input[], /* Array of input values--start with second glyph */
1260 unsigned int lookupCount HB_UNUSED,
1261 const LookupRecord lookupRecord[] HB_UNUSED,
1262 ContextApplyLookupContext &lookup_context)
1263 {
1264 return would_match_input (c,
1265 inputCount, input,
1266 lookup_context.funcs.match, lookup_context.match_data);
1267 }
context_apply_lookup(hb_ot_apply_context_t * c,unsigned int inputCount,const HBUINT16 input[],unsigned int lookupCount,const LookupRecord lookupRecord[],ContextApplyLookupContext & lookup_context)1268 static inline bool context_apply_lookup (hb_ot_apply_context_t *c,
1269 unsigned int inputCount, /* Including the first glyph (not matched) */
1270 const HBUINT16 input[], /* Array of input values--start with second glyph */
1271 unsigned int lookupCount,
1272 const LookupRecord lookupRecord[],
1273 ContextApplyLookupContext &lookup_context)
1274 {
1275 unsigned int match_length = 0;
1276 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
1277 return match_input (c,
1278 inputCount, input,
1279 lookup_context.funcs.match, lookup_context.match_data,
1280 &match_length, match_positions)
1281 && (c->buffer->unsafe_to_break (c->buffer->idx, c->buffer->idx + match_length),
1282 apply_lookup (c,
1283 inputCount, match_positions,
1284 lookupCount, lookupRecord,
1285 match_length));
1286 }
1287
1288 struct Rule
1289 {
intersectsOT::Rule1290 bool intersects (const hb_set_t *glyphs, ContextClosureLookupContext &lookup_context) const
1291 {
1292 return context_intersects (glyphs,
1293 inputCount, inputZ.arrayZ,
1294 lookup_context);
1295 }
1296
closureOT::Rule1297 void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const
1298 {
1299 TRACE_CLOSURE (this);
1300 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord> >
1301 (inputZ.as_array ((inputCount ? inputCount - 1 : 0)));
1302 context_closure_lookup (c,
1303 inputCount, inputZ.arrayZ,
1304 lookupCount, lookupRecord.arrayZ,
1305 lookup_context);
1306 }
1307
collect_glyphsOT::Rule1308 void collect_glyphs (hb_collect_glyphs_context_t *c,
1309 ContextCollectGlyphsLookupContext &lookup_context) const
1310 {
1311 TRACE_COLLECT_GLYPHS (this);
1312 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord> >
1313 (inputZ.as_array (inputCount ? inputCount - 1 : 0));
1314 context_collect_glyphs_lookup (c,
1315 inputCount, inputZ.arrayZ,
1316 lookupCount, lookupRecord.arrayZ,
1317 lookup_context);
1318 }
1319
would_applyOT::Rule1320 bool would_apply (hb_would_apply_context_t *c,
1321 ContextApplyLookupContext &lookup_context) const
1322 {
1323 TRACE_WOULD_APPLY (this);
1324 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord> >
1325 (inputZ.as_array (inputCount ? inputCount - 1 : 0));
1326 return_trace (context_would_apply_lookup (c, inputCount, inputZ.arrayZ, lookupCount, lookupRecord.arrayZ, lookup_context));
1327 }
1328
applyOT::Rule1329 bool apply (hb_ot_apply_context_t *c,
1330 ContextApplyLookupContext &lookup_context) const
1331 {
1332 TRACE_APPLY (this);
1333 const UnsizedArrayOf<LookupRecord> &lookupRecord = StructAfter<UnsizedArrayOf<LookupRecord> >
1334 (inputZ.as_array (inputCount ? inputCount - 1 : 0));
1335 return_trace (context_apply_lookup (c, inputCount, inputZ.arrayZ, lookupCount, lookupRecord.arrayZ, lookup_context));
1336 }
1337
1338 public:
sanitizeOT::Rule1339 bool sanitize (hb_sanitize_context_t *c) const
1340 {
1341 TRACE_SANITIZE (this);
1342 return_trace (inputCount.sanitize (c) &&
1343 lookupCount.sanitize (c) &&
1344 c->check_range (inputZ.arrayZ,
1345 inputZ.item_size * (inputCount ? inputCount - 1 : 0) +
1346 LookupRecord::static_size * lookupCount));
1347 }
1348
1349 protected:
1350 HBUINT16 inputCount; /* Total number of glyphs in input
1351 * glyph sequence--includes the first
1352 * glyph */
1353 HBUINT16 lookupCount; /* Number of LookupRecords */
1354 UnsizedArrayOf<HBUINT16>
1355 inputZ; /* Array of match inputs--start with
1356 * second glyph */
1357 /*UnsizedArrayOf<LookupRecord>
1358 lookupRecordX;*/ /* Array of LookupRecords--in
1359 * design order */
1360 public:
1361 DEFINE_SIZE_ARRAY (4, inputZ);
1362 };
1363
1364 struct RuleSet
1365 {
intersectsOT::RuleSet1366 bool intersects (const hb_set_t *glyphs,
1367 ContextClosureLookupContext &lookup_context) const
1368 {
1369 unsigned int num_rules = rule.len;
1370 for (unsigned int i = 0; i < num_rules; i++)
1371 if ((this+rule[i]).intersects (glyphs, lookup_context))
1372 return true;
1373 return false;
1374 }
1375
closureOT::RuleSet1376 void closure (hb_closure_context_t *c,
1377 ContextClosureLookupContext &lookup_context) const
1378 {
1379 TRACE_CLOSURE (this);
1380 unsigned int num_rules = rule.len;
1381 for (unsigned int i = 0; i < num_rules; i++)
1382 (this+rule[i]).closure (c, lookup_context);
1383 }
1384
collect_glyphsOT::RuleSet1385 void collect_glyphs (hb_collect_glyphs_context_t *c,
1386 ContextCollectGlyphsLookupContext &lookup_context) const
1387 {
1388 TRACE_COLLECT_GLYPHS (this);
1389 unsigned int num_rules = rule.len;
1390 for (unsigned int i = 0; i < num_rules; i++)
1391 (this+rule[i]).collect_glyphs (c, lookup_context);
1392 }
1393
would_applyOT::RuleSet1394 bool would_apply (hb_would_apply_context_t *c,
1395 ContextApplyLookupContext &lookup_context) const
1396 {
1397 TRACE_WOULD_APPLY (this);
1398 unsigned int num_rules = rule.len;
1399 for (unsigned int i = 0; i < num_rules; i++)
1400 {
1401 if ((this+rule[i]).would_apply (c, lookup_context))
1402 return_trace (true);
1403 }
1404 return_trace (false);
1405 }
1406
applyOT::RuleSet1407 bool apply (hb_ot_apply_context_t *c,
1408 ContextApplyLookupContext &lookup_context) const
1409 {
1410 TRACE_APPLY (this);
1411 unsigned int num_rules = rule.len;
1412 for (unsigned int i = 0; i < num_rules; i++)
1413 {
1414 if ((this+rule[i]).apply (c, lookup_context))
1415 return_trace (true);
1416 }
1417 return_trace (false);
1418 }
1419
sanitizeOT::RuleSet1420 bool sanitize (hb_sanitize_context_t *c) const
1421 {
1422 TRACE_SANITIZE (this);
1423 return_trace (rule.sanitize (c, this));
1424 }
1425
1426 protected:
1427 OffsetArrayOf<Rule>
1428 rule; /* Array of Rule tables
1429 * ordered by preference */
1430 public:
1431 DEFINE_SIZE_ARRAY (2, rule);
1432 };
1433
1434
1435 struct ContextFormat1
1436 {
intersectsOT::ContextFormat11437 bool intersects (const hb_set_t *glyphs) const
1438 {
1439 struct ContextClosureLookupContext lookup_context = {
1440 {intersects_glyph},
1441 nullptr
1442 };
1443
1444 unsigned int count = ruleSet.len;
1445 for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
1446 {
1447 if (unlikely (iter.get_coverage () >= count))
1448 break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
1449 if (glyphs->has (iter.get_glyph ()) &&
1450 (this+ruleSet[iter.get_coverage ()]).intersects (glyphs, lookup_context))
1451 return true;
1452 }
1453 return false;
1454 }
1455
closureOT::ContextFormat11456 void closure (hb_closure_context_t *c) const
1457 {
1458 TRACE_CLOSURE (this);
1459
1460 struct ContextClosureLookupContext lookup_context = {
1461 {intersects_glyph},
1462 nullptr
1463 };
1464
1465 unsigned int count = ruleSet.len;
1466 for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
1467 {
1468 if (unlikely (iter.get_coverage () >= count))
1469 break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
1470 if (c->glyphs->has (iter.get_glyph ()))
1471 (this+ruleSet[iter.get_coverage ()]).closure (c, lookup_context);
1472 }
1473 }
1474
collect_glyphsOT::ContextFormat11475 void collect_glyphs (hb_collect_glyphs_context_t *c) const
1476 {
1477 TRACE_COLLECT_GLYPHS (this);
1478 (this+coverage).add_coverage (c->input);
1479
1480 struct ContextCollectGlyphsLookupContext lookup_context = {
1481 {collect_glyph},
1482 nullptr
1483 };
1484
1485 unsigned int count = ruleSet.len;
1486 for (unsigned int i = 0; i < count; i++)
1487 (this+ruleSet[i]).collect_glyphs (c, lookup_context);
1488 }
1489
would_applyOT::ContextFormat11490 bool would_apply (hb_would_apply_context_t *c) const
1491 {
1492 TRACE_WOULD_APPLY (this);
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_trace (rule_set.would_apply (c, lookup_context));
1500 }
1501
get_coverageOT::ContextFormat11502 const Coverage &get_coverage () const { return this+coverage; }
1503
applyOT::ContextFormat11504 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
subsetOT::ContextFormat11519 bool subset (hb_subset_context_t *c) const
1520 {
1521 TRACE_SUBSET (this);
1522 // TODO(subset)
1523 return_trace (false);
1524 }
1525
sanitizeOT::ContextFormat11526 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
1545 struct ContextFormat2
1546 {
intersectsOT::ContextFormat21547 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 unsigned int count = ruleSet.len;
1560 for (unsigned int i = 0; i < count; i++)
1561 if (class_def.intersects_class (glyphs, i) &&
1562 (this+ruleSet[i]).intersects (glyphs, lookup_context))
1563 return true;
1564
1565 return false;
1566 }
1567
closureOT::ContextFormat21568 void closure (hb_closure_context_t *c) const
1569 {
1570 TRACE_CLOSURE (this);
1571 if (!(this+coverage).intersects (c->glyphs))
1572 return;
1573
1574 const ClassDef &class_def = this+classDef;
1575
1576 struct ContextClosureLookupContext lookup_context = {
1577 {intersects_class},
1578 &class_def
1579 };
1580
1581 unsigned int count = ruleSet.len;
1582 for (unsigned int i = 0; i < count; i++)
1583 if (class_def.intersects_class (c->glyphs, i)) {
1584 const RuleSet &rule_set = this+ruleSet[i];
1585 rule_set.closure (c, lookup_context);
1586 }
1587 }
1588
collect_glyphsOT::ContextFormat21589 void collect_glyphs (hb_collect_glyphs_context_t *c) const
1590 {
1591 TRACE_COLLECT_GLYPHS (this);
1592 (this+coverage).add_coverage (c->input);
1593
1594 const ClassDef &class_def = this+classDef;
1595 struct ContextCollectGlyphsLookupContext lookup_context = {
1596 {collect_class},
1597 &class_def
1598 };
1599
1600 unsigned int count = ruleSet.len;
1601 for (unsigned int i = 0; i < count; i++)
1602 (this+ruleSet[i]).collect_glyphs (c, lookup_context);
1603 }
1604
would_applyOT::ContextFormat21605 bool would_apply (hb_would_apply_context_t *c) const
1606 {
1607 TRACE_WOULD_APPLY (this);
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_trace (rule_set.would_apply (c, lookup_context));
1617 }
1618
get_coverageOT::ContextFormat21619 const Coverage &get_coverage () const { return this+coverage; }
1620
applyOT::ContextFormat21621 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
subsetOT::ContextFormat21637 bool subset (hb_subset_context_t *c) const
1638 {
1639 TRACE_SUBSET (this);
1640 // TODO(subset)
1641 return_trace (false);
1642 }
1643
sanitizeOT::ContextFormat21644 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
1666 struct ContextFormat3
1667 {
intersectsOT::ContextFormat31668 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
closureOT::ContextFormat31682 void closure (hb_closure_context_t *c) const
1683 {
1684 TRACE_CLOSURE (this);
1685 if (!(this+coverageZ[0]).intersects (c->glyphs))
1686 return;
1687
1688 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
1689 struct ContextClosureLookupContext lookup_context = {
1690 {intersects_coverage},
1691 this
1692 };
1693 context_closure_lookup (c,
1694 glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
1695 lookupCount, lookupRecord,
1696 lookup_context);
1697 }
1698
collect_glyphsOT::ContextFormat31699 void collect_glyphs (hb_collect_glyphs_context_t *c) const
1700 {
1701 TRACE_COLLECT_GLYPHS (this);
1702 (this+coverageZ[0]).add_coverage (c->input);
1703
1704 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
1705 struct ContextCollectGlyphsLookupContext lookup_context = {
1706 {collect_coverage},
1707 this
1708 };
1709
1710 context_collect_glyphs_lookup (c,
1711 glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1),
1712 lookupCount, lookupRecord,
1713 lookup_context);
1714 }
1715
would_applyOT::ContextFormat31716 bool would_apply (hb_would_apply_context_t *c) const
1717 {
1718 TRACE_WOULD_APPLY (this);
1719
1720 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
1721 struct ContextApplyLookupContext lookup_context = {
1722 {match_coverage},
1723 this
1724 };
1725 return_trace (context_would_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, lookup_context));
1726 }
1727
get_coverageOT::ContextFormat31728 const Coverage &get_coverage () const { return this+coverageZ[0]; }
1729
applyOT::ContextFormat31730 bool apply (hb_ot_apply_context_t *c) const
1731 {
1732 TRACE_APPLY (this);
1733 unsigned int index = (this+coverageZ[0]).get_coverage (c->buffer->cur().codepoint);
1734 if (likely (index == NOT_COVERED)) return_trace (false);
1735
1736 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
1737 struct ContextApplyLookupContext lookup_context = {
1738 {match_coverage},
1739 this
1740 };
1741 return_trace (context_apply_lookup (c, glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, lookup_context));
1742 }
1743
subsetOT::ContextFormat31744 bool subset (hb_subset_context_t *c) const
1745 {
1746 TRACE_SUBSET (this);
1747 // TODO(subset)
1748 return_trace (false);
1749 }
1750
sanitizeOT::ContextFormat31751 bool sanitize (hb_sanitize_context_t *c) const
1752 {
1753 TRACE_SANITIZE (this);
1754 if (!c->check_struct (this)) return_trace (false);
1755 unsigned int count = glyphCount;
1756 if (!count) return_trace (false); /* We want to access coverageZ[0] freely. */
1757 if (!c->check_array (coverageZ.arrayZ, count)) return_trace (false);
1758 for (unsigned int i = 0; i < count; i++)
1759 if (!coverageZ[i].sanitize (c, this)) return_trace (false);
1760 const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount));
1761 return_trace (c->check_array (lookupRecord, lookupCount));
1762 }
1763
1764 protected:
1765 HBUINT16 format; /* Format identifier--format = 3 */
1766 HBUINT16 glyphCount; /* Number of glyphs in the input glyph
1767 * sequence */
1768 HBUINT16 lookupCount; /* Number of LookupRecords */
1769 UnsizedArrayOf<OffsetTo<Coverage> >
1770 coverageZ; /* Array of offsets to Coverage
1771 * table in glyph sequence order */
1772 /*UnsizedArrayOf<LookupRecord>
1773 lookupRecordX;*/ /* Array of LookupRecords--in
1774 * design order */
1775 public:
1776 DEFINE_SIZE_ARRAY (6, coverageZ);
1777 };
1778
1779 struct Context
1780 {
1781 template <typename context_t>
dispatchOT::Context1782 typename context_t::return_t dispatch (context_t *c) const
1783 {
1784 TRACE_DISPATCH (this, u.format);
1785 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
1786 switch (u.format) {
1787 case 1: return_trace (c->dispatch (u.format1));
1788 case 2: return_trace (c->dispatch (u.format2));
1789 case 3: return_trace (c->dispatch (u.format3));
1790 default:return_trace (c->default_return_value ());
1791 }
1792 }
1793
1794 protected:
1795 union {
1796 HBUINT16 format; /* Format identifier */
1797 ContextFormat1 format1;
1798 ContextFormat2 format2;
1799 ContextFormat3 format3;
1800 } u;
1801 };
1802
1803
1804 /* Chaining Contextual lookups */
1805
1806 struct ChainContextClosureLookupContext
1807 {
1808 ContextClosureFuncs funcs;
1809 const void *intersects_data[3];
1810 };
1811
1812 struct ChainContextCollectGlyphsLookupContext
1813 {
1814 ContextCollectGlyphsFuncs funcs;
1815 const void *collect_data[3];
1816 };
1817
1818 struct ChainContextApplyLookupContext
1819 {
1820 ContextApplyFuncs funcs;
1821 const void *match_data[3];
1822 };
1823
chain_context_intersects(const hb_set_t * glyphs,unsigned int backtrackCount,const HBUINT16 backtrack[],unsigned int inputCount,const HBUINT16 input[],unsigned int lookaheadCount,const HBUINT16 lookahead[],ChainContextClosureLookupContext & lookup_context)1824 static inline bool chain_context_intersects (const hb_set_t *glyphs,
1825 unsigned int backtrackCount,
1826 const HBUINT16 backtrack[],
1827 unsigned int inputCount, /* Including the first glyph (not matched) */
1828 const HBUINT16 input[], /* Array of input values--start with second glyph */
1829 unsigned int lookaheadCount,
1830 const HBUINT16 lookahead[],
1831 ChainContextClosureLookupContext &lookup_context)
1832 {
1833 return intersects_array (glyphs,
1834 backtrackCount, backtrack,
1835 lookup_context.funcs.intersects, lookup_context.intersects_data[0])
1836 && intersects_array (glyphs,
1837 inputCount ? inputCount - 1 : 0, input,
1838 lookup_context.funcs.intersects, lookup_context.intersects_data[1])
1839 && intersects_array (glyphs,
1840 lookaheadCount, lookahead,
1841 lookup_context.funcs.intersects, lookup_context.intersects_data[2]);
1842 }
1843
chain_context_closure_lookup(hb_closure_context_t * c,unsigned int backtrackCount,const HBUINT16 backtrack[],unsigned int inputCount,const HBUINT16 input[],unsigned int lookaheadCount,const HBUINT16 lookahead[],unsigned int lookupCount,const LookupRecord lookupRecord[],ChainContextClosureLookupContext & lookup_context)1844 static inline void chain_context_closure_lookup (hb_closure_context_t *c,
1845 unsigned int backtrackCount,
1846 const HBUINT16 backtrack[],
1847 unsigned int inputCount, /* Including the first glyph (not matched) */
1848 const HBUINT16 input[], /* Array of input values--start with second glyph */
1849 unsigned int lookaheadCount,
1850 const HBUINT16 lookahead[],
1851 unsigned int lookupCount,
1852 const LookupRecord lookupRecord[],
1853 ChainContextClosureLookupContext &lookup_context)
1854 {
1855 if (chain_context_intersects (c->glyphs,
1856 backtrackCount, backtrack,
1857 inputCount, input,
1858 lookaheadCount, lookahead,
1859 lookup_context))
1860 recurse_lookups (c,
1861 lookupCount, lookupRecord);
1862 }
1863
chain_context_collect_glyphs_lookup(hb_collect_glyphs_context_t * c,unsigned int backtrackCount,const HBUINT16 backtrack[],unsigned int inputCount,const HBUINT16 input[],unsigned int lookaheadCount,const HBUINT16 lookahead[],unsigned int lookupCount,const LookupRecord lookupRecord[],ChainContextCollectGlyphsLookupContext & lookup_context)1864 static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c,
1865 unsigned int backtrackCount,
1866 const HBUINT16 backtrack[],
1867 unsigned int inputCount, /* Including the first glyph (not matched) */
1868 const HBUINT16 input[], /* Array of input values--start with second glyph */
1869 unsigned int lookaheadCount,
1870 const HBUINT16 lookahead[],
1871 unsigned int lookupCount,
1872 const LookupRecord lookupRecord[],
1873 ChainContextCollectGlyphsLookupContext &lookup_context)
1874 {
1875 collect_array (c, c->before,
1876 backtrackCount, backtrack,
1877 lookup_context.funcs.collect, lookup_context.collect_data[0]);
1878 collect_array (c, c->input,
1879 inputCount ? inputCount - 1 : 0, input,
1880 lookup_context.funcs.collect, lookup_context.collect_data[1]);
1881 collect_array (c, c->after,
1882 lookaheadCount, lookahead,
1883 lookup_context.funcs.collect, lookup_context.collect_data[2]);
1884 recurse_lookups (c,
1885 lookupCount, lookupRecord);
1886 }
1887
chain_context_would_apply_lookup(hb_would_apply_context_t * c,unsigned int backtrackCount,const HBUINT16 backtrack[]HB_UNUSED,unsigned int inputCount,const HBUINT16 input[],unsigned int lookaheadCount,const HBUINT16 lookahead[]HB_UNUSED,unsigned int lookupCount HB_UNUSED,const LookupRecord lookupRecord[]HB_UNUSED,ChainContextApplyLookupContext & lookup_context)1888 static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c,
1889 unsigned int backtrackCount,
1890 const HBUINT16 backtrack[] HB_UNUSED,
1891 unsigned int inputCount, /* Including the first glyph (not matched) */
1892 const HBUINT16 input[], /* Array of input values--start with second glyph */
1893 unsigned int lookaheadCount,
1894 const HBUINT16 lookahead[] HB_UNUSED,
1895 unsigned int lookupCount HB_UNUSED,
1896 const LookupRecord lookupRecord[] HB_UNUSED,
1897 ChainContextApplyLookupContext &lookup_context)
1898 {
1899 return (c->zero_context ? !backtrackCount && !lookaheadCount : true)
1900 && would_match_input (c,
1901 inputCount, input,
1902 lookup_context.funcs.match, lookup_context.match_data[1]);
1903 }
1904
chain_context_apply_lookup(hb_ot_apply_context_t * c,unsigned int backtrackCount,const HBUINT16 backtrack[],unsigned int inputCount,const HBUINT16 input[],unsigned int lookaheadCount,const HBUINT16 lookahead[],unsigned int lookupCount,const LookupRecord lookupRecord[],ChainContextApplyLookupContext & lookup_context)1905 static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c,
1906 unsigned int backtrackCount,
1907 const HBUINT16 backtrack[],
1908 unsigned int inputCount, /* Including the first glyph (not matched) */
1909 const HBUINT16 input[], /* Array of input values--start with second glyph */
1910 unsigned int lookaheadCount,
1911 const HBUINT16 lookahead[],
1912 unsigned int lookupCount,
1913 const LookupRecord lookupRecord[],
1914 ChainContextApplyLookupContext &lookup_context)
1915 {
1916 unsigned int start_index = 0, match_length = 0, end_index = 0;
1917 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
1918 return match_input (c,
1919 inputCount, input,
1920 lookup_context.funcs.match, lookup_context.match_data[1],
1921 &match_length, match_positions)
1922 && match_backtrack (c,
1923 backtrackCount, backtrack,
1924 lookup_context.funcs.match, lookup_context.match_data[0],
1925 &start_index)
1926 && match_lookahead (c,
1927 lookaheadCount, lookahead,
1928 lookup_context.funcs.match, lookup_context.match_data[2],
1929 match_length, &end_index)
1930 && (c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index),
1931 apply_lookup (c,
1932 inputCount, match_positions,
1933 lookupCount, lookupRecord,
1934 match_length));
1935 }
1936
1937 struct ChainRule
1938 {
intersectsOT::ChainRule1939 bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
1940 {
1941 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
1942 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
1943 return chain_context_intersects (glyphs,
1944 backtrack.len, backtrack.arrayZ,
1945 input.lenP1, input.arrayZ,
1946 lookahead.len, lookahead.arrayZ,
1947 lookup_context);
1948 }
1949
closureOT::ChainRule1950 void closure (hb_closure_context_t *c,
1951 ChainContextClosureLookupContext &lookup_context) const
1952 {
1953 TRACE_CLOSURE (this);
1954 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
1955 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
1956 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1957 chain_context_closure_lookup (c,
1958 backtrack.len, backtrack.arrayZ,
1959 input.lenP1, input.arrayZ,
1960 lookahead.len, lookahead.arrayZ,
1961 lookup.len, lookup.arrayZ,
1962 lookup_context);
1963 }
1964
collect_glyphsOT::ChainRule1965 void collect_glyphs (hb_collect_glyphs_context_t *c,
1966 ChainContextCollectGlyphsLookupContext &lookup_context) const
1967 {
1968 TRACE_COLLECT_GLYPHS (this);
1969 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
1970 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
1971 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1972 chain_context_collect_glyphs_lookup (c,
1973 backtrack.len, backtrack.arrayZ,
1974 input.lenP1, input.arrayZ,
1975 lookahead.len, lookahead.arrayZ,
1976 lookup.len, lookup.arrayZ,
1977 lookup_context);
1978 }
1979
would_applyOT::ChainRule1980 bool would_apply (hb_would_apply_context_t *c,
1981 ChainContextApplyLookupContext &lookup_context) const
1982 {
1983 TRACE_WOULD_APPLY (this);
1984 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
1985 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
1986 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
1987 return_trace (chain_context_would_apply_lookup (c,
1988 backtrack.len, backtrack.arrayZ,
1989 input.lenP1, input.arrayZ,
1990 lookahead.len, lookahead.arrayZ, lookup.len,
1991 lookup.arrayZ, lookup_context));
1992 }
1993
applyOT::ChainRule1994 bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
1995 {
1996 TRACE_APPLY (this);
1997 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
1998 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
1999 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2000 return_trace (chain_context_apply_lookup (c,
2001 backtrack.len, backtrack.arrayZ,
2002 input.lenP1, input.arrayZ,
2003 lookahead.len, lookahead.arrayZ, lookup.len,
2004 lookup.arrayZ, lookup_context));
2005 }
2006
sanitizeOT::ChainRule2007 bool sanitize (hb_sanitize_context_t *c) const
2008 {
2009 TRACE_SANITIZE (this);
2010 if (!backtrack.sanitize (c)) return_trace (false);
2011 const HeadlessArrayOf<HBUINT16> &input = StructAfter<HeadlessArrayOf<HBUINT16> > (backtrack);
2012 if (!input.sanitize (c)) return_trace (false);
2013 const ArrayOf<HBUINT16> &lookahead = StructAfter<ArrayOf<HBUINT16> > (input);
2014 if (!lookahead.sanitize (c)) return_trace (false);
2015 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2016 return_trace (lookup.sanitize (c));
2017 }
2018
2019 protected:
2020 ArrayOf<HBUINT16>
2021 backtrack; /* Array of backtracking values
2022 * (to be matched before the input
2023 * sequence) */
2024 HeadlessArrayOf<HBUINT16>
2025 inputX; /* Array of input values (start with
2026 * second glyph) */
2027 ArrayOf<HBUINT16>
2028 lookaheadX; /* Array of lookahead values's (to be
2029 * matched after the input sequence) */
2030 ArrayOf<LookupRecord>
2031 lookupX; /* Array of LookupRecords--in
2032 * design order) */
2033 public:
2034 DEFINE_SIZE_MIN (8);
2035 };
2036
2037 struct ChainRuleSet
2038 {
intersectsOT::ChainRuleSet2039 bool intersects (const hb_set_t *glyphs, ChainContextClosureLookupContext &lookup_context) const
2040 {
2041 unsigned int num_rules = rule.len;
2042 for (unsigned int i = 0; i < num_rules; i++)
2043 if ((this+rule[i]).intersects (glyphs, lookup_context))
2044 return true;
2045 return false;
2046 }
closureOT::ChainRuleSet2047 void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const
2048 {
2049 TRACE_CLOSURE (this);
2050 unsigned int num_rules = rule.len;
2051 for (unsigned int i = 0; i < num_rules; i++)
2052 (this+rule[i]).closure (c, lookup_context);
2053 }
2054
collect_glyphsOT::ChainRuleSet2055 void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const
2056 {
2057 TRACE_COLLECT_GLYPHS (this);
2058 unsigned int num_rules = rule.len;
2059 for (unsigned int i = 0; i < num_rules; i++)
2060 (this+rule[i]).collect_glyphs (c, lookup_context);
2061 }
2062
would_applyOT::ChainRuleSet2063 bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
2064 {
2065 TRACE_WOULD_APPLY (this);
2066 unsigned int num_rules = rule.len;
2067 for (unsigned int i = 0; i < num_rules; i++)
2068 if ((this+rule[i]).would_apply (c, lookup_context))
2069 return_trace (true);
2070
2071 return_trace (false);
2072 }
2073
applyOT::ChainRuleSet2074 bool apply (hb_ot_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const
2075 {
2076 TRACE_APPLY (this);
2077 unsigned int num_rules = rule.len;
2078 for (unsigned int i = 0; i < num_rules; i++)
2079 if ((this+rule[i]).apply (c, lookup_context))
2080 return_trace (true);
2081
2082 return_trace (false);
2083 }
2084
sanitizeOT::ChainRuleSet2085 bool sanitize (hb_sanitize_context_t *c) const
2086 {
2087 TRACE_SANITIZE (this);
2088 return_trace (rule.sanitize (c, this));
2089 }
2090
2091 protected:
2092 OffsetArrayOf<ChainRule>
2093 rule; /* Array of ChainRule tables
2094 * ordered by preference */
2095 public:
2096 DEFINE_SIZE_ARRAY (2, rule);
2097 };
2098
2099 struct ChainContextFormat1
2100 {
intersectsOT::ChainContextFormat12101 bool intersects (const hb_set_t *glyphs) const
2102 {
2103 struct ChainContextClosureLookupContext lookup_context = {
2104 {intersects_glyph},
2105 {nullptr, nullptr, nullptr}
2106 };
2107
2108 unsigned int count = ruleSet.len;
2109 for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
2110 {
2111 if (unlikely (iter.get_coverage () >= count))
2112 break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
2113 if (glyphs->has (iter.get_glyph ()) &&
2114 (this+ruleSet[iter.get_coverage ()]).intersects (glyphs, lookup_context))
2115 return true;
2116 }
2117 return false;
2118 }
2119
closureOT::ChainContextFormat12120 void closure (hb_closure_context_t *c) const
2121 {
2122 TRACE_CLOSURE (this);
2123
2124 struct ChainContextClosureLookupContext lookup_context = {
2125 {intersects_glyph},
2126 {nullptr, nullptr, nullptr}
2127 };
2128
2129 unsigned int count = ruleSet.len;
2130 for (Coverage::Iter iter (this+coverage); iter.more (); iter.next ())
2131 {
2132 if (unlikely (iter.get_coverage () >= count))
2133 break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
2134 if (c->glyphs->has (iter.get_glyph ()))
2135 (this+ruleSet[iter.get_coverage ()]).closure (c, lookup_context);
2136 }
2137 }
2138
collect_glyphsOT::ChainContextFormat12139 void collect_glyphs (hb_collect_glyphs_context_t *c) const
2140 {
2141 TRACE_COLLECT_GLYPHS (this);
2142 (this+coverage).add_coverage (c->input);
2143
2144 struct ChainContextCollectGlyphsLookupContext lookup_context = {
2145 {collect_glyph},
2146 {nullptr, nullptr, nullptr}
2147 };
2148
2149 unsigned int count = ruleSet.len;
2150 for (unsigned int i = 0; i < count; i++)
2151 (this+ruleSet[i]).collect_glyphs (c, lookup_context);
2152 }
2153
would_applyOT::ChainContextFormat12154 bool would_apply (hb_would_apply_context_t *c) const
2155 {
2156 TRACE_WOULD_APPLY (this);
2157
2158 const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])];
2159 struct ChainContextApplyLookupContext lookup_context = {
2160 {match_glyph},
2161 {nullptr, nullptr, nullptr}
2162 };
2163 return_trace (rule_set.would_apply (c, lookup_context));
2164 }
2165
get_coverageOT::ChainContextFormat12166 const Coverage &get_coverage () const { return this+coverage; }
2167
applyOT::ChainContextFormat12168 bool apply (hb_ot_apply_context_t *c) const
2169 {
2170 TRACE_APPLY (this);
2171 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
2172 if (likely (index == NOT_COVERED)) return_trace (false);
2173
2174 const ChainRuleSet &rule_set = this+ruleSet[index];
2175 struct ChainContextApplyLookupContext lookup_context = {
2176 {match_glyph},
2177 {nullptr, nullptr, nullptr}
2178 };
2179 return_trace (rule_set.apply (c, lookup_context));
2180 }
2181
subsetOT::ChainContextFormat12182 bool subset (hb_subset_context_t *c) const
2183 {
2184 TRACE_SUBSET (this);
2185 // TODO(subset)
2186 return_trace (false);
2187 }
2188
sanitizeOT::ChainContextFormat12189 bool sanitize (hb_sanitize_context_t *c) const
2190 {
2191 TRACE_SANITIZE (this);
2192 return_trace (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
2193 }
2194
2195 protected:
2196 HBUINT16 format; /* Format identifier--format = 1 */
2197 OffsetTo<Coverage>
2198 coverage; /* Offset to Coverage table--from
2199 * beginning of table */
2200 OffsetArrayOf<ChainRuleSet>
2201 ruleSet; /* Array of ChainRuleSet tables
2202 * ordered by Coverage Index */
2203 public:
2204 DEFINE_SIZE_ARRAY (6, ruleSet);
2205 };
2206
2207 struct ChainContextFormat2
2208 {
intersectsOT::ChainContextFormat22209 bool intersects (const hb_set_t *glyphs) const
2210 {
2211 if (!(this+coverage).intersects (glyphs))
2212 return false;
2213
2214 const ClassDef &backtrack_class_def = this+backtrackClassDef;
2215 const ClassDef &input_class_def = this+inputClassDef;
2216 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2217
2218 struct ChainContextClosureLookupContext lookup_context = {
2219 {intersects_class},
2220 {&backtrack_class_def,
2221 &input_class_def,
2222 &lookahead_class_def}
2223 };
2224
2225 unsigned int count = ruleSet.len;
2226 for (unsigned int i = 0; i < count; i++)
2227 if (input_class_def.intersects_class (glyphs, i) &&
2228 (this+ruleSet[i]).intersects (glyphs, lookup_context))
2229 return true;
2230
2231 return false;
2232 }
closureOT::ChainContextFormat22233 void closure (hb_closure_context_t *c) const
2234 {
2235 TRACE_CLOSURE (this);
2236 if (!(this+coverage).intersects (c->glyphs))
2237 return;
2238
2239 const ClassDef &backtrack_class_def = this+backtrackClassDef;
2240 const ClassDef &input_class_def = this+inputClassDef;
2241 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2242
2243 struct ChainContextClosureLookupContext lookup_context = {
2244 {intersects_class},
2245 {&backtrack_class_def,
2246 &input_class_def,
2247 &lookahead_class_def}
2248 };
2249
2250 unsigned int count = ruleSet.len;
2251 for (unsigned int i = 0; i < count; i++)
2252 if (input_class_def.intersects_class (c->glyphs, i)) {
2253 const ChainRuleSet &rule_set = this+ruleSet[i];
2254 rule_set.closure (c, lookup_context);
2255 }
2256 }
2257
collect_glyphsOT::ChainContextFormat22258 void collect_glyphs (hb_collect_glyphs_context_t *c) const
2259 {
2260 TRACE_COLLECT_GLYPHS (this);
2261 (this+coverage).add_coverage (c->input);
2262
2263 const ClassDef &backtrack_class_def = this+backtrackClassDef;
2264 const ClassDef &input_class_def = this+inputClassDef;
2265 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2266
2267 struct ChainContextCollectGlyphsLookupContext lookup_context = {
2268 {collect_class},
2269 {&backtrack_class_def,
2270 &input_class_def,
2271 &lookahead_class_def}
2272 };
2273
2274 unsigned int count = ruleSet.len;
2275 for (unsigned int i = 0; i < count; i++)
2276 (this+ruleSet[i]).collect_glyphs (c, lookup_context);
2277 }
2278
would_applyOT::ChainContextFormat22279 bool would_apply (hb_would_apply_context_t *c) const
2280 {
2281 TRACE_WOULD_APPLY (this);
2282
2283 const ClassDef &backtrack_class_def = this+backtrackClassDef;
2284 const ClassDef &input_class_def = this+inputClassDef;
2285 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2286
2287 unsigned int index = input_class_def.get_class (c->glyphs[0]);
2288 const ChainRuleSet &rule_set = this+ruleSet[index];
2289 struct ChainContextApplyLookupContext lookup_context = {
2290 {match_class},
2291 {&backtrack_class_def,
2292 &input_class_def,
2293 &lookahead_class_def}
2294 };
2295 return_trace (rule_set.would_apply (c, lookup_context));
2296 }
2297
get_coverageOT::ChainContextFormat22298 const Coverage &get_coverage () const { return this+coverage; }
2299
applyOT::ChainContextFormat22300 bool apply (hb_ot_apply_context_t *c) const
2301 {
2302 TRACE_APPLY (this);
2303 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint);
2304 if (likely (index == NOT_COVERED)) return_trace (false);
2305
2306 const ClassDef &backtrack_class_def = this+backtrackClassDef;
2307 const ClassDef &input_class_def = this+inputClassDef;
2308 const ClassDef &lookahead_class_def = this+lookaheadClassDef;
2309
2310 index = input_class_def.get_class (c->buffer->cur().codepoint);
2311 const ChainRuleSet &rule_set = this+ruleSet[index];
2312 struct ChainContextApplyLookupContext lookup_context = {
2313 {match_class},
2314 {&backtrack_class_def,
2315 &input_class_def,
2316 &lookahead_class_def}
2317 };
2318 return_trace (rule_set.apply (c, lookup_context));
2319 }
2320
subsetOT::ChainContextFormat22321 bool subset (hb_subset_context_t *c) const
2322 {
2323 TRACE_SUBSET (this);
2324 // TODO(subset)
2325 return_trace (false);
2326 }
2327
sanitizeOT::ChainContextFormat22328 bool sanitize (hb_sanitize_context_t *c) const
2329 {
2330 TRACE_SANITIZE (this);
2331 return_trace (coverage.sanitize (c, this) &&
2332 backtrackClassDef.sanitize (c, this) &&
2333 inputClassDef.sanitize (c, this) &&
2334 lookaheadClassDef.sanitize (c, this) &&
2335 ruleSet.sanitize (c, this));
2336 }
2337
2338 protected:
2339 HBUINT16 format; /* Format identifier--format = 2 */
2340 OffsetTo<Coverage>
2341 coverage; /* Offset to Coverage table--from
2342 * beginning of table */
2343 OffsetTo<ClassDef>
2344 backtrackClassDef; /* Offset to glyph ClassDef table
2345 * containing backtrack sequence
2346 * data--from beginning of table */
2347 OffsetTo<ClassDef>
2348 inputClassDef; /* Offset to glyph ClassDef
2349 * table containing input sequence
2350 * data--from beginning of table */
2351 OffsetTo<ClassDef>
2352 lookaheadClassDef; /* Offset to glyph ClassDef table
2353 * containing lookahead sequence
2354 * data--from beginning of table */
2355 OffsetArrayOf<ChainRuleSet>
2356 ruleSet; /* Array of ChainRuleSet tables
2357 * ordered by class */
2358 public:
2359 DEFINE_SIZE_ARRAY (12, ruleSet);
2360 };
2361
2362 struct ChainContextFormat3
2363 {
intersectsOT::ChainContextFormat32364 bool intersects (const hb_set_t *glyphs) const
2365 {
2366 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2367
2368 if (!(this+input[0]).intersects (glyphs))
2369 return false;
2370
2371 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2372 struct ChainContextClosureLookupContext lookup_context = {
2373 {intersects_coverage},
2374 {this, this, this}
2375 };
2376 return chain_context_intersects (glyphs,
2377 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2378 input.len, (const HBUINT16 *) input.arrayZ + 1,
2379 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2380 lookup_context);
2381 }
2382
closureOT::ChainContextFormat32383 void closure (hb_closure_context_t *c) const
2384 {
2385 TRACE_CLOSURE (this);
2386 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2387
2388 if (!(this+input[0]).intersects (c->glyphs))
2389 return;
2390
2391 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2392 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2393 struct ChainContextClosureLookupContext lookup_context = {
2394 {intersects_coverage},
2395 {this, this, this}
2396 };
2397 chain_context_closure_lookup (c,
2398 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2399 input.len, (const HBUINT16 *) input.arrayZ + 1,
2400 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2401 lookup.len, lookup.arrayZ,
2402 lookup_context);
2403 }
2404
collect_glyphsOT::ChainContextFormat32405 void collect_glyphs (hb_collect_glyphs_context_t *c) const
2406 {
2407 TRACE_COLLECT_GLYPHS (this);
2408 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2409
2410 (this+input[0]).add_coverage (c->input);
2411
2412 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2413 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2414 struct ChainContextCollectGlyphsLookupContext lookup_context = {
2415 {collect_coverage},
2416 {this, this, this}
2417 };
2418 chain_context_collect_glyphs_lookup (c,
2419 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2420 input.len, (const HBUINT16 *) input.arrayZ + 1,
2421 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2422 lookup.len, lookup.arrayZ,
2423 lookup_context);
2424 }
2425
would_applyOT::ChainContextFormat32426 bool would_apply (hb_would_apply_context_t *c) const
2427 {
2428 TRACE_WOULD_APPLY (this);
2429
2430 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2431 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2432 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2433 struct ChainContextApplyLookupContext lookup_context = {
2434 {match_coverage},
2435 {this, this, this}
2436 };
2437 return_trace (chain_context_would_apply_lookup (c,
2438 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2439 input.len, (const HBUINT16 *) input.arrayZ + 1,
2440 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2441 lookup.len, lookup.arrayZ, lookup_context));
2442 }
2443
get_coverageOT::ChainContextFormat32444 const Coverage &get_coverage () const
2445 {
2446 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2447 return this+input[0];
2448 }
2449
applyOT::ChainContextFormat32450 bool apply (hb_ot_apply_context_t *c) const
2451 {
2452 TRACE_APPLY (this);
2453 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2454
2455 unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint);
2456 if (likely (index == NOT_COVERED)) return_trace (false);
2457
2458 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2459 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2460 struct ChainContextApplyLookupContext lookup_context = {
2461 {match_coverage},
2462 {this, this, this}
2463 };
2464 return_trace (chain_context_apply_lookup (c,
2465 backtrack.len, (const HBUINT16 *) backtrack.arrayZ,
2466 input.len, (const HBUINT16 *) input.arrayZ + 1,
2467 lookahead.len, (const HBUINT16 *) lookahead.arrayZ,
2468 lookup.len, lookup.arrayZ, lookup_context));
2469 }
2470
subsetOT::ChainContextFormat32471 bool subset (hb_subset_context_t *c) const
2472 {
2473 TRACE_SUBSET (this);
2474 // TODO(subset)
2475 return_trace (false);
2476 }
2477
sanitizeOT::ChainContextFormat32478 bool sanitize (hb_sanitize_context_t *c) const
2479 {
2480 TRACE_SANITIZE (this);
2481 if (!backtrack.sanitize (c, this)) return_trace (false);
2482 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
2483 if (!input.sanitize (c, this)) return_trace (false);
2484 if (!input.len) return_trace (false); /* To be consistent with Context. */
2485 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
2486 if (!lookahead.sanitize (c, this)) return_trace (false);
2487 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
2488 return_trace (lookup.sanitize (c));
2489 }
2490
2491 protected:
2492 HBUINT16 format; /* Format identifier--format = 3 */
2493 OffsetArrayOf<Coverage>
2494 backtrack; /* Array of coverage tables
2495 * in backtracking sequence, in glyph
2496 * sequence order */
2497 OffsetArrayOf<Coverage>
2498 inputX ; /* Array of coverage
2499 * tables in input sequence, in glyph
2500 * sequence order */
2501 OffsetArrayOf<Coverage>
2502 lookaheadX; /* Array of coverage tables
2503 * in lookahead sequence, in glyph
2504 * sequence order */
2505 ArrayOf<LookupRecord>
2506 lookupX; /* Array of LookupRecords--in
2507 * design order) */
2508 public:
2509 DEFINE_SIZE_MIN (10);
2510 };
2511
2512 struct ChainContext
2513 {
2514 template <typename context_t>
dispatchOT::ChainContext2515 typename context_t::return_t dispatch (context_t *c) const
2516 {
2517 TRACE_DISPATCH (this, u.format);
2518 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
2519 switch (u.format) {
2520 case 1: return_trace (c->dispatch (u.format1));
2521 case 2: return_trace (c->dispatch (u.format2));
2522 case 3: return_trace (c->dispatch (u.format3));
2523 default:return_trace (c->default_return_value ());
2524 }
2525 }
2526
2527 protected:
2528 union {
2529 HBUINT16 format; /* Format identifier */
2530 ChainContextFormat1 format1;
2531 ChainContextFormat2 format2;
2532 ChainContextFormat3 format3;
2533 } u;
2534 };
2535
2536
2537 template <typename T>
2538 struct ExtensionFormat1
2539 {
get_typeOT::ExtensionFormat12540 unsigned int get_type () const { return extensionLookupType; }
2541
2542 template <typename X>
get_subtableOT::ExtensionFormat12543 const X& get_subtable () const
2544 {
2545 unsigned int offset = extensionOffset;
2546 if (unlikely (!offset)) return Null(typename T::SubTable);
2547 return StructAtOffset<typename T::SubTable> (this, offset);
2548 }
2549
2550 template <typename context_t>
dispatchOT::ExtensionFormat12551 typename context_t::return_t dispatch (context_t *c) const
2552 {
2553 TRACE_DISPATCH (this, format);
2554 if (unlikely (!c->may_dispatch (this, this))) return_trace (c->no_dispatch_return_value ());
2555 return_trace (get_subtable<typename T::SubTable> ().dispatch (c, get_type ()));
2556 }
2557
2558 /* This is called from may_dispatch() above with hb_sanitize_context_t. */
sanitizeOT::ExtensionFormat12559 bool sanitize (hb_sanitize_context_t *c) const
2560 {
2561 TRACE_SANITIZE (this);
2562 return_trace (c->check_struct (this) &&
2563 extensionOffset != 0 &&
2564 extensionLookupType != T::SubTable::Extension);
2565 }
2566
2567 protected:
2568 HBUINT16 format; /* Format identifier. Set to 1. */
2569 HBUINT16 extensionLookupType; /* Lookup type of subtable referenced
2570 * by ExtensionOffset (i.e. the
2571 * extension subtable). */
2572 HBUINT32 extensionOffset; /* Offset to the extension subtable,
2573 * of lookup type subtable. */
2574 public:
2575 DEFINE_SIZE_STATIC (8);
2576 };
2577
2578 template <typename T>
2579 struct Extension
2580 {
get_typeOT::Extension2581 unsigned int get_type () const
2582 {
2583 switch (u.format) {
2584 case 1: return u.format1.get_type ();
2585 default:return 0;
2586 }
2587 }
2588 template <typename X>
get_subtableOT::Extension2589 const X& get_subtable () const
2590 {
2591 switch (u.format) {
2592 case 1: return u.format1.template get_subtable<typename T::SubTable> ();
2593 default:return Null(typename T::SubTable);
2594 }
2595 }
2596
2597 template <typename context_t>
dispatchOT::Extension2598 typename context_t::return_t dispatch (context_t *c) const
2599 {
2600 TRACE_DISPATCH (this, u.format);
2601 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
2602 switch (u.format) {
2603 case 1: return_trace (u.format1.dispatch (c));
2604 default:return_trace (c->default_return_value ());
2605 }
2606 }
2607
2608 protected:
2609 union {
2610 HBUINT16 format; /* Format identifier */
2611 ExtensionFormat1<T> format1;
2612 } u;
2613 };
2614
2615
2616 /*
2617 * GSUB/GPOS Common
2618 */
2619
2620 struct hb_ot_layout_lookup_accelerator_t
2621 {
2622 template <typename TLookup>
initOT::hb_ot_layout_lookup_accelerator_t2623 void init (const TLookup &lookup)
2624 {
2625 digest.init ();
2626 lookup.add_coverage (&digest);
2627
2628 subtables.init ();
2629 OT::hb_get_subtables_context_t c_get_subtables (subtables);
2630 lookup.dispatch (&c_get_subtables);
2631 }
finiOT::hb_ot_layout_lookup_accelerator_t2632 void fini () { subtables.fini (); }
2633
may_haveOT::hb_ot_layout_lookup_accelerator_t2634 bool may_have (hb_codepoint_t g) const
2635 { return digest.may_have (g); }
2636
applyOT::hb_ot_layout_lookup_accelerator_t2637 bool apply (hb_ot_apply_context_t *c) const
2638 {
2639 for (unsigned int i = 0; i < subtables.len; i++)
2640 if (subtables[i].apply (c))
2641 return true;
2642 return false;
2643 }
2644
2645 private:
2646 hb_set_digest_t digest;
2647 hb_get_subtables_context_t::array_t subtables;
2648 };
2649
2650 struct GSUBGPOS
2651 {
has_dataOT::GSUBGPOS2652 bool has_data () const { return version.to_int (); }
get_script_countOT::GSUBGPOS2653 unsigned int get_script_count () const
2654 { return (this+scriptList).len; }
get_script_tagOT::GSUBGPOS2655 const Tag& get_script_tag (unsigned int i) const
2656 { return (this+scriptList).get_tag (i); }
get_script_tagsOT::GSUBGPOS2657 unsigned int get_script_tags (unsigned int start_offset,
2658 unsigned int *script_count /* IN/OUT */,
2659 hb_tag_t *script_tags /* OUT */) const
2660 { return (this+scriptList).get_tags (start_offset, script_count, script_tags); }
get_scriptOT::GSUBGPOS2661 const Script& get_script (unsigned int i) const
2662 { return (this+scriptList)[i]; }
find_script_indexOT::GSUBGPOS2663 bool find_script_index (hb_tag_t tag, unsigned int *index) const
2664 { return (this+scriptList).find_index (tag, index); }
2665
get_feature_countOT::GSUBGPOS2666 unsigned int get_feature_count () const
2667 { return (this+featureList).len; }
get_feature_tagOT::GSUBGPOS2668 hb_tag_t get_feature_tag (unsigned int i) const
2669 { return i == Index::NOT_FOUND_INDEX ? HB_TAG_NONE : (this+featureList).get_tag (i); }
get_feature_tagsOT::GSUBGPOS2670 unsigned int get_feature_tags (unsigned int start_offset,
2671 unsigned int *feature_count /* IN/OUT */,
2672 hb_tag_t *feature_tags /* OUT */) const
2673 { return (this+featureList).get_tags (start_offset, feature_count, feature_tags); }
get_featureOT::GSUBGPOS2674 const Feature& get_feature (unsigned int i) const
2675 { return (this+featureList)[i]; }
find_feature_indexOT::GSUBGPOS2676 bool find_feature_index (hb_tag_t tag, unsigned int *index) const
2677 { return (this+featureList).find_index (tag, index); }
2678
get_lookup_countOT::GSUBGPOS2679 unsigned int get_lookup_count () const
2680 { return (this+lookupList).len; }
get_lookupOT::GSUBGPOS2681 const Lookup& get_lookup (unsigned int i) const
2682 { return (this+lookupList)[i]; }
2683
find_variations_indexOT::GSUBGPOS2684 bool find_variations_index (const int *coords, unsigned int num_coords,
2685 unsigned int *index) const
2686 { return (version.to_int () >= 0x00010001u ? this+featureVars : Null(FeatureVariations))
2687 .find_index (coords, num_coords, index); }
get_feature_variationOT::GSUBGPOS2688 const Feature& get_feature_variation (unsigned int feature_index,
2689 unsigned int variations_index) const
2690 {
2691 if (FeatureVariations::NOT_FOUND_INDEX != variations_index &&
2692 version.to_int () >= 0x00010001u)
2693 {
2694 const Feature *feature = (this+featureVars).find_substitute (variations_index,
2695 feature_index);
2696 if (feature)
2697 return *feature;
2698 }
2699 return get_feature (feature_index);
2700 }
2701
2702 template <typename TLookup>
subsetOT::GSUBGPOS2703 bool subset (hb_subset_context_t *c) const
2704 {
2705 TRACE_SUBSET (this);
2706 struct GSUBGPOS *out = c->serializer->embed (*this);
2707 if (unlikely (!out)) return_trace (false);
2708
2709 out->scriptList.serialize_subset (c, this+scriptList, out);
2710 out->featureList.serialize_subset (c, this+featureList, out);
2711
2712 typedef OffsetListOf<TLookup> TLookupList;
2713 /* TODO Use intersects() to count how many subtables survive? */
2714 CastR<OffsetTo<TLookupList> > (out->lookupList)
2715 .serialize_subset (c,
2716 this+CastR<const OffsetTo<TLookupList> > (lookupList),
2717 out);
2718
2719 if (version.to_int () >= 0x00010001u)
2720 out->featureVars.serialize_subset (c, this+featureVars, out);
2721
2722 return_trace (true);
2723 }
2724
get_sizeOT::GSUBGPOS2725 unsigned int get_size () const
2726 {
2727 return min_size +
2728 (version.to_int () >= 0x00010001u ? featureVars.static_size : 0);
2729 }
2730
2731 template <typename TLookup>
sanitizeOT::GSUBGPOS2732 bool sanitize (hb_sanitize_context_t *c) const
2733 {
2734 TRACE_SANITIZE (this);
2735 typedef OffsetListOf<TLookup> TLookupList;
2736 return_trace (version.sanitize (c) &&
2737 likely (version.major == 1) &&
2738 scriptList.sanitize (c, this) &&
2739 featureList.sanitize (c, this) &&
2740 CastR<OffsetTo<TLookupList> > (lookupList).sanitize (c, this) &&
2741 (version.to_int () < 0x00010001u || featureVars.sanitize (c, this)));
2742 }
2743
2744 template <typename T>
2745 struct accelerator_t
2746 {
initOT::GSUBGPOS::accelerator_t2747 void init (hb_face_t *face)
2748 {
2749 this->table = hb_sanitize_context_t().reference_table<T> (face);
2750 if (unlikely (this->table->is_blacklisted (this->table.get_blob (), face)))
2751 {
2752 hb_blob_destroy (this->table.get_blob ());
2753 this->table = hb_blob_get_empty ();
2754 }
2755
2756 this->lookup_count = table->get_lookup_count ();
2757
2758 this->accels = (hb_ot_layout_lookup_accelerator_t *) calloc (this->lookup_count, sizeof (hb_ot_layout_lookup_accelerator_t));
2759 if (unlikely (!this->accels))
2760 this->lookup_count = 0;
2761
2762 for (unsigned int i = 0; i < this->lookup_count; i++)
2763 this->accels[i].init (table->get_lookup (i));
2764 }
2765
finiOT::GSUBGPOS::accelerator_t2766 void fini ()
2767 {
2768 for (unsigned int i = 0; i < this->lookup_count; i++)
2769 this->accels[i].fini ();
2770 free (this->accels);
2771 this->table.destroy ();
2772 }
2773
2774 hb_blob_ptr_t<T> table;
2775 unsigned int lookup_count;
2776 hb_ot_layout_lookup_accelerator_t *accels;
2777 };
2778
2779 protected:
2780 FixedVersion<>version; /* Version of the GSUB/GPOS table--initially set
2781 * to 0x00010000u */
2782 OffsetTo<ScriptList>
2783 scriptList; /* ScriptList table */
2784 OffsetTo<FeatureList>
2785 featureList; /* FeatureList table */
2786 OffsetTo<LookupList>
2787 lookupList; /* LookupList table */
2788 LOffsetTo<FeatureVariations>
2789 featureVars; /* Offset to Feature Variations
2790 table--from beginning of table
2791 * (may be NULL). Introduced
2792 * in version 0x00010001. */
2793 public:
2794 DEFINE_SIZE_MIN (10);
2795 };
2796
2797
2798 } /* namespace OT */
2799
2800
2801 #endif /* HB_OT_LAYOUT_GSUBGPOS_HH */
2802