1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/harfbuzz/src/hb-ot-layout-gsubgpos-private.hh Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,2297 @@ 1.4 +/* 1.5 + * Copyright © 2007,2008,2009,2010 Red Hat, Inc. 1.6 + * Copyright © 2010,2012 Google, Inc. 1.7 + * 1.8 + * This is part of HarfBuzz, a text shaping library. 1.9 + * 1.10 + * Permission is hereby granted, without written agreement and without 1.11 + * license or royalty fees, to use, copy, modify, and distribute this 1.12 + * software and its documentation for any purpose, provided that the 1.13 + * above copyright notice and the following two paragraphs appear in 1.14 + * all copies of this software. 1.15 + * 1.16 + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 1.17 + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 1.18 + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 1.19 + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 1.20 + * DAMAGE. 1.21 + * 1.22 + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 1.23 + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 1.24 + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 1.25 + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 1.26 + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 1.27 + * 1.28 + * Red Hat Author(s): Behdad Esfahbod 1.29 + * Google Author(s): Behdad Esfahbod 1.30 + */ 1.31 + 1.32 +#ifndef HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH 1.33 +#define HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH 1.34 + 1.35 +#include "hb-buffer-private.hh" 1.36 +#include "hb-ot-layout-gdef-table.hh" 1.37 +#include "hb-set-private.hh" 1.38 + 1.39 + 1.40 +namespace OT { 1.41 + 1.42 + 1.43 + 1.44 +#define TRACE_DISPATCH(this) \ 1.45 + hb_auto_trace_t<context_t::max_debug_depth, typename context_t::return_t> trace \ 1.46 + (&c->debug_depth, c->get_name (), this, HB_FUNC, \ 1.47 + ""); 1.48 + 1.49 +#ifndef HB_DEBUG_CLOSURE 1.50 +#define HB_DEBUG_CLOSURE (HB_DEBUG+0) 1.51 +#endif 1.52 + 1.53 +#define TRACE_CLOSURE(this) \ 1.54 + hb_auto_trace_t<HB_DEBUG_CLOSURE, hb_void_t> trace \ 1.55 + (&c->debug_depth, c->get_name (), this, HB_FUNC, \ 1.56 + ""); 1.57 + 1.58 +struct hb_closure_context_t 1.59 +{ 1.60 + inline const char *get_name (void) { return "CLOSURE"; } 1.61 + static const unsigned int max_debug_depth = HB_DEBUG_CLOSURE; 1.62 + typedef hb_void_t return_t; 1.63 + typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index); 1.64 + template <typename T> 1.65 + inline return_t dispatch (const T &obj) { obj.closure (this); return HB_VOID; } 1.66 + static return_t default_return_value (void) { return HB_VOID; } 1.67 + bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; } 1.68 + return_t recurse (unsigned int lookup_index) 1.69 + { 1.70 + if (unlikely (nesting_level_left == 0 || !recurse_func)) 1.71 + return default_return_value (); 1.72 + 1.73 + nesting_level_left--; 1.74 + recurse_func (this, lookup_index); 1.75 + nesting_level_left++; 1.76 + return HB_VOID; 1.77 + } 1.78 + 1.79 + hb_face_t *face; 1.80 + hb_set_t *glyphs; 1.81 + recurse_func_t recurse_func; 1.82 + unsigned int nesting_level_left; 1.83 + unsigned int debug_depth; 1.84 + 1.85 + hb_closure_context_t (hb_face_t *face_, 1.86 + hb_set_t *glyphs_, 1.87 + unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) : 1.88 + face (face_), 1.89 + glyphs (glyphs_), 1.90 + recurse_func (NULL), 1.91 + nesting_level_left (nesting_level_left_), 1.92 + debug_depth (0) {} 1.93 + 1.94 + void set_recurse_func (recurse_func_t func) { recurse_func = func; } 1.95 +}; 1.96 + 1.97 + 1.98 + 1.99 +#ifndef HB_DEBUG_WOULD_APPLY 1.100 +#define HB_DEBUG_WOULD_APPLY (HB_DEBUG+0) 1.101 +#endif 1.102 + 1.103 +#define TRACE_WOULD_APPLY(this) \ 1.104 + hb_auto_trace_t<HB_DEBUG_WOULD_APPLY, bool> trace \ 1.105 + (&c->debug_depth, c->get_name (), this, HB_FUNC, \ 1.106 + "%d glyphs", c->len); 1.107 + 1.108 +struct hb_would_apply_context_t 1.109 +{ 1.110 + inline const char *get_name (void) { return "WOULD_APPLY"; } 1.111 + static const unsigned int max_debug_depth = HB_DEBUG_WOULD_APPLY; 1.112 + typedef bool return_t; 1.113 + template <typename T> 1.114 + inline return_t dispatch (const T &obj) { return obj.would_apply (this); } 1.115 + static return_t default_return_value (void) { return false; } 1.116 + bool stop_sublookup_iteration (return_t r) const { return r; } 1.117 + 1.118 + hb_face_t *face; 1.119 + const hb_codepoint_t *glyphs; 1.120 + unsigned int len; 1.121 + bool zero_context; 1.122 + unsigned int debug_depth; 1.123 + 1.124 + hb_would_apply_context_t (hb_face_t *face_, 1.125 + const hb_codepoint_t *glyphs_, 1.126 + unsigned int len_, 1.127 + bool zero_context_) : 1.128 + face (face_), 1.129 + glyphs (glyphs_), 1.130 + len (len_), 1.131 + zero_context (zero_context_), 1.132 + debug_depth (0) {} 1.133 +}; 1.134 + 1.135 + 1.136 + 1.137 +#ifndef HB_DEBUG_COLLECT_GLYPHS 1.138 +#define HB_DEBUG_COLLECT_GLYPHS (HB_DEBUG+0) 1.139 +#endif 1.140 + 1.141 +#define TRACE_COLLECT_GLYPHS(this) \ 1.142 + hb_auto_trace_t<HB_DEBUG_COLLECT_GLYPHS, hb_void_t> trace \ 1.143 + (&c->debug_depth, c->get_name (), this, HB_FUNC, \ 1.144 + ""); 1.145 + 1.146 +struct hb_collect_glyphs_context_t 1.147 +{ 1.148 + inline const char *get_name (void) { return "COLLECT_GLYPHS"; } 1.149 + static const unsigned int max_debug_depth = HB_DEBUG_COLLECT_GLYPHS; 1.150 + typedef hb_void_t return_t; 1.151 + typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index); 1.152 + template <typename T> 1.153 + inline return_t dispatch (const T &obj) { obj.collect_glyphs (this); return HB_VOID; } 1.154 + static return_t default_return_value (void) { return HB_VOID; } 1.155 + bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; } 1.156 + return_t recurse (unsigned int lookup_index) 1.157 + { 1.158 + if (unlikely (nesting_level_left == 0 || !recurse_func)) 1.159 + return default_return_value (); 1.160 + 1.161 + /* Note that GPOS sets recurse_func to NULL already, so it doesn't get 1.162 + * past the previous check. For GSUB, we only want to collect the output 1.163 + * glyphs in the recursion. If output is not requested, we can go home now. 1.164 + * 1.165 + * Note further, that the above is not exactly correct. A recursed lookup 1.166 + * is allowed to match input that is not matched in the context, but that's 1.167 + * not how most fonts are built. It's possible to relax that and recurse 1.168 + * with all sets here if it proves to be an issue. 1.169 + */ 1.170 + 1.171 + if (output == hb_set_get_empty ()) 1.172 + return HB_VOID; 1.173 + 1.174 + hb_set_t *old_before = before; 1.175 + hb_set_t *old_input = input; 1.176 + hb_set_t *old_after = after; 1.177 + before = input = after = hb_set_get_empty (); 1.178 + 1.179 + nesting_level_left--; 1.180 + recurse_func (this, lookup_index); 1.181 + nesting_level_left++; 1.182 + 1.183 + before = old_before; 1.184 + input = old_input; 1.185 + after = old_after; 1.186 + 1.187 + return HB_VOID; 1.188 + } 1.189 + 1.190 + hb_face_t *face; 1.191 + hb_set_t *before; 1.192 + hb_set_t *input; 1.193 + hb_set_t *after; 1.194 + hb_set_t *output; 1.195 + recurse_func_t recurse_func; 1.196 + unsigned int nesting_level_left; 1.197 + unsigned int debug_depth; 1.198 + 1.199 + hb_collect_glyphs_context_t (hb_face_t *face_, 1.200 + hb_set_t *glyphs_before, /* OUT. May be NULL */ 1.201 + hb_set_t *glyphs_input, /* OUT. May be NULL */ 1.202 + hb_set_t *glyphs_after, /* OUT. May be NULL */ 1.203 + hb_set_t *glyphs_output, /* OUT. May be NULL */ 1.204 + unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) : 1.205 + face (face_), 1.206 + before (glyphs_before ? glyphs_before : hb_set_get_empty ()), 1.207 + input (glyphs_input ? glyphs_input : hb_set_get_empty ()), 1.208 + after (glyphs_after ? glyphs_after : hb_set_get_empty ()), 1.209 + output (glyphs_output ? glyphs_output : hb_set_get_empty ()), 1.210 + recurse_func (NULL), 1.211 + nesting_level_left (nesting_level_left_), 1.212 + debug_depth (0) {} 1.213 + 1.214 + void set_recurse_func (recurse_func_t func) { recurse_func = func; } 1.215 +}; 1.216 + 1.217 + 1.218 + 1.219 +struct hb_get_coverage_context_t 1.220 +{ 1.221 + inline const char *get_name (void) { return "GET_COVERAGE"; } 1.222 + static const unsigned int max_debug_depth = 0; 1.223 + typedef const Coverage &return_t; 1.224 + template <typename T> 1.225 + inline return_t dispatch (const T &obj) { return obj.get_coverage (); } 1.226 + static return_t default_return_value (void) { return Null(Coverage); } 1.227 + 1.228 + hb_get_coverage_context_t (void) : 1.229 + debug_depth (0) {} 1.230 + 1.231 + unsigned int debug_depth; 1.232 +}; 1.233 + 1.234 + 1.235 + 1.236 +#ifndef HB_DEBUG_APPLY 1.237 +#define HB_DEBUG_APPLY (HB_DEBUG+0) 1.238 +#endif 1.239 + 1.240 +#define TRACE_APPLY(this) \ 1.241 + hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace \ 1.242 + (&c->debug_depth, c->get_name (), this, HB_FUNC, \ 1.243 + "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint); 1.244 + 1.245 +struct hb_apply_context_t 1.246 +{ 1.247 + inline const char *get_name (void) { return "APPLY"; } 1.248 + static const unsigned int max_debug_depth = HB_DEBUG_APPLY; 1.249 + typedef bool return_t; 1.250 + typedef return_t (*recurse_func_t) (hb_apply_context_t *c, unsigned int lookup_index); 1.251 + template <typename T> 1.252 + inline return_t dispatch (const T &obj) { return obj.apply (this); } 1.253 + static return_t default_return_value (void) { return false; } 1.254 + bool stop_sublookup_iteration (return_t r) const { return r; } 1.255 + return_t recurse (unsigned int lookup_index) 1.256 + { 1.257 + if (unlikely (nesting_level_left == 0 || !recurse_func)) 1.258 + return default_return_value (); 1.259 + 1.260 + nesting_level_left--; 1.261 + bool ret = recurse_func (this, lookup_index); 1.262 + nesting_level_left++; 1.263 + return ret; 1.264 + } 1.265 + 1.266 + unsigned int table_index; /* GSUB/GPOS */ 1.267 + hb_font_t *font; 1.268 + hb_face_t *face; 1.269 + hb_buffer_t *buffer; 1.270 + hb_direction_t direction; 1.271 + hb_mask_t lookup_mask; 1.272 + bool auto_zwj; 1.273 + recurse_func_t recurse_func; 1.274 + unsigned int nesting_level_left; 1.275 + unsigned int lookup_props; 1.276 + const GDEF &gdef; 1.277 + bool has_glyph_classes; 1.278 + unsigned int debug_depth; 1.279 + 1.280 + 1.281 + hb_apply_context_t (unsigned int table_index_, 1.282 + hb_font_t *font_, 1.283 + hb_buffer_t *buffer_) : 1.284 + table_index (table_index_), 1.285 + font (font_), face (font->face), buffer (buffer_), 1.286 + direction (buffer_->props.direction), 1.287 + lookup_mask (1), 1.288 + auto_zwj (true), 1.289 + recurse_func (NULL), 1.290 + nesting_level_left (MAX_NESTING_LEVEL), 1.291 + lookup_props (0), 1.292 + gdef (*hb_ot_layout_from_face (face)->gdef), 1.293 + has_glyph_classes (gdef.has_glyph_classes ()), 1.294 + debug_depth (0) {} 1.295 + 1.296 + inline void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; } 1.297 + inline void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; } 1.298 + inline void set_recurse_func (recurse_func_t func) { recurse_func = func; } 1.299 + inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; } 1.300 + inline void set_lookup (const Lookup &l) { lookup_props = l.get_props (); } 1.301 + 1.302 + struct matcher_t 1.303 + { 1.304 + inline matcher_t (void) : 1.305 + lookup_props (0), 1.306 + ignore_zwnj (false), 1.307 + ignore_zwj (false), 1.308 + mask (-1), 1.309 +#define arg1(arg) (arg) /* Remove the macro to see why it's needed! */ 1.310 + syllable arg1(0), 1.311 +#undef arg1 1.312 + match_func (NULL), 1.313 + match_data (NULL) {}; 1.314 + 1.315 + typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data); 1.316 + 1.317 + inline void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; } 1.318 + inline void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; } 1.319 + inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; } 1.320 + inline void set_mask (hb_mask_t mask_) { mask = mask_; } 1.321 + inline void set_syllable (uint8_t syllable_) { syllable = syllable_; } 1.322 + inline void set_match_func (match_func_t match_func_, 1.323 + const void *match_data_) 1.324 + { match_func = match_func_; match_data = match_data_; } 1.325 + 1.326 + enum may_match_t { 1.327 + MATCH_NO, 1.328 + MATCH_YES, 1.329 + MATCH_MAYBE 1.330 + }; 1.331 + 1.332 + inline may_match_t may_match (const hb_glyph_info_t &info, 1.333 + const USHORT *glyph_data) const 1.334 + { 1.335 + if (!(info.mask & mask) || 1.336 + (syllable && syllable != info.syllable ())) 1.337 + return MATCH_NO; 1.338 + 1.339 + if (match_func) 1.340 + return match_func (info.codepoint, *glyph_data, match_data) ? MATCH_YES : MATCH_NO; 1.341 + 1.342 + return MATCH_MAYBE; 1.343 + } 1.344 + 1.345 + enum may_skip_t { 1.346 + SKIP_NO, 1.347 + SKIP_YES, 1.348 + SKIP_MAYBE 1.349 + }; 1.350 + 1.351 + inline may_skip_t 1.352 + may_skip (const hb_apply_context_t *c, 1.353 + const hb_glyph_info_t &info) const 1.354 + { 1.355 + unsigned int property; 1.356 + 1.357 + property = _hb_glyph_info_get_glyph_props (&info); 1.358 + 1.359 + if (!c->match_properties (info.codepoint, property, lookup_props)) 1.360 + return SKIP_YES; 1.361 + 1.362 + if (unlikely (_hb_glyph_info_is_default_ignorable (&info) && 1.363 + (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) && 1.364 + (ignore_zwj || !_hb_glyph_info_is_zwj (&info)) && 1.365 + !_hb_glyph_info_ligated (&info))) 1.366 + return SKIP_MAYBE; 1.367 + 1.368 + return SKIP_NO; 1.369 + } 1.370 + 1.371 + protected: 1.372 + unsigned int lookup_props; 1.373 + bool ignore_zwnj; 1.374 + bool ignore_zwj; 1.375 + hb_mask_t mask; 1.376 + uint8_t syllable; 1.377 + match_func_t match_func; 1.378 + const void *match_data; 1.379 + }; 1.380 + 1.381 + struct skipping_forward_iterator_t 1.382 + { 1.383 + inline skipping_forward_iterator_t (hb_apply_context_t *c_, 1.384 + unsigned int start_index_, 1.385 + unsigned int num_items_, 1.386 + bool context_match = false) : 1.387 + idx (start_index_), 1.388 + c (c_), 1.389 + match_glyph_data (NULL), 1.390 + num_items (num_items_), 1.391 + end (c->buffer->len) 1.392 + { 1.393 + matcher.set_lookup_props (c->lookup_props); 1.394 + /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */ 1.395 + matcher.set_ignore_zwnj (context_match || c->table_index == 1); 1.396 + /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */ 1.397 + matcher.set_ignore_zwj (context_match || c->table_index == 1 || c->auto_zwj); 1.398 + if (!context_match) 1.399 + matcher.set_mask (c->lookup_mask); 1.400 + matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0); 1.401 + } 1.402 + inline void set_lookup_props (unsigned int lookup_props) { matcher.set_lookup_props (lookup_props); } 1.403 + inline void set_syllable (unsigned int syllable) { matcher.set_syllable (syllable); } 1.404 + inline void set_match_func (matcher_t::match_func_t match_func, 1.405 + const void *match_data, 1.406 + const USHORT glyph_data[]) 1.407 + { 1.408 + matcher.set_match_func (match_func, match_data); 1.409 + match_glyph_data = glyph_data; 1.410 + } 1.411 + 1.412 + inline bool has_no_chance (void) const { return unlikely (num_items && idx + num_items >= end); } 1.413 + inline void reject (void) { num_items++; match_glyph_data--; } 1.414 + inline bool next (void) 1.415 + { 1.416 + assert (num_items > 0); 1.417 + while (!has_no_chance ()) 1.418 + { 1.419 + idx++; 1.420 + const hb_glyph_info_t &info = c->buffer->info[idx]; 1.421 + 1.422 + matcher_t::may_skip_t skip = matcher.may_skip (c, info); 1.423 + if (unlikely (skip == matcher_t::SKIP_YES)) 1.424 + continue; 1.425 + 1.426 + matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data); 1.427 + if (match == matcher_t::MATCH_YES || 1.428 + (match == matcher_t::MATCH_MAYBE && 1.429 + skip == matcher_t::SKIP_NO)) 1.430 + { 1.431 + num_items--; 1.432 + match_glyph_data++; 1.433 + return true; 1.434 + } 1.435 + 1.436 + if (skip == matcher_t::SKIP_NO) 1.437 + return false; 1.438 + } 1.439 + return false; 1.440 + } 1.441 + 1.442 + unsigned int idx; 1.443 + protected: 1.444 + hb_apply_context_t *c; 1.445 + matcher_t matcher; 1.446 + const USHORT *match_glyph_data; 1.447 + 1.448 + unsigned int num_items; 1.449 + unsigned int end; 1.450 + }; 1.451 + 1.452 + struct skipping_backward_iterator_t 1.453 + { 1.454 + inline skipping_backward_iterator_t (hb_apply_context_t *c_, 1.455 + unsigned int start_index_, 1.456 + unsigned int num_items_, 1.457 + bool context_match = false) : 1.458 + idx (start_index_), 1.459 + c (c_), 1.460 + match_glyph_data (NULL), 1.461 + num_items (num_items_) 1.462 + { 1.463 + matcher.set_lookup_props (c->lookup_props); 1.464 + /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */ 1.465 + matcher.set_ignore_zwnj (context_match || c->table_index == 1); 1.466 + /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */ 1.467 + matcher.set_ignore_zwj (context_match || c->table_index == 1 || c->auto_zwj); 1.468 + if (!context_match) 1.469 + matcher.set_mask (c->lookup_mask); 1.470 + matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0); 1.471 + } 1.472 + inline void set_lookup_props (unsigned int lookup_props) { matcher.set_lookup_props (lookup_props); } 1.473 + inline void set_syllable (unsigned int syllable) { matcher.set_syllable (syllable); } 1.474 + inline void set_match_func (matcher_t::match_func_t match_func, 1.475 + const void *match_data, 1.476 + const USHORT glyph_data[]) 1.477 + { 1.478 + matcher.set_match_func (match_func, match_data); 1.479 + match_glyph_data = glyph_data; 1.480 + } 1.481 + 1.482 + inline bool has_no_chance (void) const { return unlikely (idx < num_items); } 1.483 + inline void reject (void) { num_items++; } 1.484 + inline bool prev (void) 1.485 + { 1.486 + assert (num_items > 0); 1.487 + while (!has_no_chance ()) 1.488 + { 1.489 + idx--; 1.490 + const hb_glyph_info_t &info = c->buffer->out_info[idx]; 1.491 + 1.492 + matcher_t::may_skip_t skip = matcher.may_skip (c, info); 1.493 + 1.494 + if (unlikely (skip == matcher_t::SKIP_YES)) 1.495 + continue; 1.496 + 1.497 + matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data); 1.498 + if (match == matcher_t::MATCH_YES || 1.499 + (match == matcher_t::MATCH_MAYBE && 1.500 + skip == matcher_t::SKIP_NO)) 1.501 + { 1.502 + num_items--; 1.503 + match_glyph_data++; 1.504 + return true; 1.505 + } 1.506 + 1.507 + if (skip == matcher_t::SKIP_NO) 1.508 + return false; 1.509 + } 1.510 + return false; 1.511 + } 1.512 + 1.513 + unsigned int idx; 1.514 + protected: 1.515 + hb_apply_context_t *c; 1.516 + matcher_t matcher; 1.517 + const USHORT *match_glyph_data; 1.518 + 1.519 + unsigned int num_items; 1.520 + }; 1.521 + 1.522 + inline bool 1.523 + match_properties_mark (hb_codepoint_t glyph, 1.524 + unsigned int glyph_props, 1.525 + unsigned int lookup_props) const 1.526 + { 1.527 + /* If using mark filtering sets, the high short of 1.528 + * lookup_props has the set index. 1.529 + */ 1.530 + if (lookup_props & LookupFlag::UseMarkFilteringSet) 1.531 + return gdef.mark_set_covers (lookup_props >> 16, glyph); 1.532 + 1.533 + /* The second byte of lookup_props has the meaning 1.534 + * "ignore marks of attachment type different than 1.535 + * the attachment type specified." 1.536 + */ 1.537 + if (lookup_props & LookupFlag::MarkAttachmentType) 1.538 + return (lookup_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType); 1.539 + 1.540 + return true; 1.541 + } 1.542 + 1.543 + inline bool 1.544 + match_properties (hb_codepoint_t glyph, 1.545 + unsigned int glyph_props, 1.546 + unsigned int lookup_props) const 1.547 + { 1.548 + /* Not covered, if, for example, glyph class is ligature and 1.549 + * lookup_props includes LookupFlags::IgnoreLigatures 1.550 + */ 1.551 + if (glyph_props & lookup_props & LookupFlag::IgnoreFlags) 1.552 + return false; 1.553 + 1.554 + if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK)) 1.555 + return match_properties_mark (glyph, glyph_props, lookup_props); 1.556 + 1.557 + return true; 1.558 + } 1.559 + 1.560 + inline bool 1.561 + check_glyph_property (hb_glyph_info_t *info, 1.562 + unsigned int lookup_props) const 1.563 + { 1.564 + unsigned int property; 1.565 + 1.566 + property = _hb_glyph_info_get_glyph_props (info); 1.567 + 1.568 + return match_properties (info->codepoint, property, lookup_props); 1.569 + } 1.570 + 1.571 + inline void _set_glyph_props (hb_codepoint_t glyph_index, 1.572 + unsigned int class_guess = 0, 1.573 + bool ligature = false) const 1.574 + { 1.575 + unsigned int add_in = _hb_glyph_info_get_glyph_props (&buffer->cur()) & 1.576 + HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE; 1.577 + add_in |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED; 1.578 + if (ligature) 1.579 + add_in |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED; 1.580 + if (likely (has_glyph_classes)) 1.581 + _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | gdef.get_glyph_props (glyph_index)); 1.582 + else if (class_guess) 1.583 + _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | class_guess); 1.584 + } 1.585 + 1.586 + inline void replace_glyph (hb_codepoint_t glyph_index) const 1.587 + { 1.588 + _set_glyph_props (glyph_index); 1.589 + buffer->replace_glyph (glyph_index); 1.590 + } 1.591 + inline void replace_glyph_inplace (hb_codepoint_t glyph_index) const 1.592 + { 1.593 + _set_glyph_props (glyph_index); 1.594 + buffer->cur().codepoint = glyph_index; 1.595 + } 1.596 + inline void replace_glyph_with_ligature (hb_codepoint_t glyph_index, 1.597 + unsigned int class_guess) const 1.598 + { 1.599 + _set_glyph_props (glyph_index, class_guess, true); 1.600 + buffer->replace_glyph (glyph_index); 1.601 + } 1.602 + inline void output_glyph (hb_codepoint_t glyph_index, 1.603 + unsigned int class_guess) const 1.604 + { 1.605 + _set_glyph_props (glyph_index, class_guess); 1.606 + buffer->output_glyph (glyph_index); 1.607 + } 1.608 +}; 1.609 + 1.610 + 1.611 + 1.612 +typedef bool (*intersects_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data); 1.613 +typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data); 1.614 +typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data); 1.615 + 1.616 +struct ContextClosureFuncs 1.617 +{ 1.618 + intersects_func_t intersects; 1.619 +}; 1.620 +struct ContextCollectGlyphsFuncs 1.621 +{ 1.622 + collect_glyphs_func_t collect; 1.623 +}; 1.624 +struct ContextApplyFuncs 1.625 +{ 1.626 + match_func_t match; 1.627 +}; 1.628 + 1.629 + 1.630 +static inline bool intersects_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED) 1.631 +{ 1.632 + return glyphs->has (value); 1.633 +} 1.634 +static inline bool intersects_class (hb_set_t *glyphs, const USHORT &value, const void *data) 1.635 +{ 1.636 + const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data); 1.637 + return class_def.intersects_class (glyphs, value); 1.638 +} 1.639 +static inline bool intersects_coverage (hb_set_t *glyphs, const USHORT &value, const void *data) 1.640 +{ 1.641 + const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value; 1.642 + return (data+coverage).intersects (glyphs); 1.643 +} 1.644 + 1.645 +static inline bool intersects_array (hb_closure_context_t *c, 1.646 + unsigned int count, 1.647 + const USHORT values[], 1.648 + intersects_func_t intersects_func, 1.649 + const void *intersects_data) 1.650 +{ 1.651 + for (unsigned int i = 0; i < count; i++) 1.652 + if (likely (!intersects_func (c->glyphs, values[i], intersects_data))) 1.653 + return false; 1.654 + return true; 1.655 +} 1.656 + 1.657 + 1.658 +static inline void collect_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED) 1.659 +{ 1.660 + glyphs->add (value); 1.661 +} 1.662 +static inline void collect_class (hb_set_t *glyphs, const USHORT &value, const void *data) 1.663 +{ 1.664 + const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data); 1.665 + class_def.add_class (glyphs, value); 1.666 +} 1.667 +static inline void collect_coverage (hb_set_t *glyphs, const USHORT &value, const void *data) 1.668 +{ 1.669 + const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value; 1.670 + (data+coverage).add_coverage (glyphs); 1.671 +} 1.672 +static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED, 1.673 + hb_set_t *glyphs, 1.674 + unsigned int count, 1.675 + const USHORT values[], 1.676 + collect_glyphs_func_t collect_func, 1.677 + const void *collect_data) 1.678 +{ 1.679 + for (unsigned int i = 0; i < count; i++) 1.680 + collect_func (glyphs, values[i], collect_data); 1.681 +} 1.682 + 1.683 + 1.684 +static inline bool match_glyph (hb_codepoint_t glyph_id, const USHORT &value, const void *data HB_UNUSED) 1.685 +{ 1.686 + return glyph_id == value; 1.687 +} 1.688 +static inline bool match_class (hb_codepoint_t glyph_id, const USHORT &value, const void *data) 1.689 +{ 1.690 + const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data); 1.691 + return class_def.get_class (glyph_id) == value; 1.692 +} 1.693 +static inline bool match_coverage (hb_codepoint_t glyph_id, const USHORT &value, const void *data) 1.694 +{ 1.695 + const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value; 1.696 + return (data+coverage).get_coverage (glyph_id) != NOT_COVERED; 1.697 +} 1.698 + 1.699 +static inline bool would_match_input (hb_would_apply_context_t *c, 1.700 + unsigned int count, /* Including the first glyph (not matched) */ 1.701 + const USHORT input[], /* Array of input values--start with second glyph */ 1.702 + match_func_t match_func, 1.703 + const void *match_data) 1.704 +{ 1.705 + if (count != c->len) 1.706 + return false; 1.707 + 1.708 + for (unsigned int i = 1; i < count; i++) 1.709 + if (likely (!match_func (c->glyphs[i], input[i - 1], match_data))) 1.710 + return false; 1.711 + 1.712 + return true; 1.713 +} 1.714 +static inline bool match_input (hb_apply_context_t *c, 1.715 + unsigned int count, /* Including the first glyph (not matched) */ 1.716 + const USHORT input[], /* Array of input values--start with second glyph */ 1.717 + match_func_t match_func, 1.718 + const void *match_data, 1.719 + unsigned int *end_offset, 1.720 + unsigned int match_positions[MAX_CONTEXT_LENGTH], 1.721 + bool *p_is_mark_ligature = NULL, 1.722 + unsigned int *p_total_component_count = NULL) 1.723 +{ 1.724 + TRACE_APPLY (NULL); 1.725 + 1.726 + if (unlikely (count > MAX_CONTEXT_LENGTH)) TRACE_RETURN (false); 1.727 + 1.728 + hb_buffer_t *buffer = c->buffer; 1.729 + 1.730 + hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, buffer->idx, count - 1); 1.731 + skippy_iter.set_match_func (match_func, match_data, input); 1.732 + if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false); 1.733 + 1.734 + /* 1.735 + * This is perhaps the trickiest part of OpenType... Remarks: 1.736 + * 1.737 + * - If all components of the ligature were marks, we call this a mark ligature. 1.738 + * 1.739 + * - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize 1.740 + * it as a ligature glyph. 1.741 + * 1.742 + * - Ligatures cannot be formed across glyphs attached to different components 1.743 + * of previous ligatures. Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and 1.744 + * LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother. 1.745 + * However, it would be wrong to ligate that SHADDA,FATHA sequence.o 1.746 + * There is an exception to this: If a ligature tries ligating with marks that 1.747 + * belong to it itself, go ahead, assuming that the font designer knows what 1.748 + * they are doing (otherwise it can break Indic stuff when a matra wants to 1.749 + * ligate with a conjunct...) 1.750 + */ 1.751 + 1.752 + bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->cur()); 1.753 + 1.754 + unsigned int total_component_count = 0; 1.755 + total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur()); 1.756 + 1.757 + unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur()); 1.758 + unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur()); 1.759 + 1.760 + match_positions[0] = buffer->idx; 1.761 + for (unsigned int i = 1; i < count; i++) 1.762 + { 1.763 + if (!skippy_iter.next ()) return TRACE_RETURN (false); 1.764 + 1.765 + match_positions[i] = skippy_iter.idx; 1.766 + 1.767 + unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]); 1.768 + unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]); 1.769 + 1.770 + if (first_lig_id && first_lig_comp) { 1.771 + /* If first component was attached to a previous ligature component, 1.772 + * all subsequent components should be attached to the same ligature 1.773 + * component, otherwise we shouldn't ligate them. */ 1.774 + if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp) 1.775 + return TRACE_RETURN (false); 1.776 + } else { 1.777 + /* If first component was NOT attached to a previous ligature component, 1.778 + * all subsequent components should also NOT be attached to any ligature 1.779 + * component, unless they are attached to the first component itself! */ 1.780 + if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id)) 1.781 + return TRACE_RETURN (false); 1.782 + } 1.783 + 1.784 + is_mark_ligature = is_mark_ligature && _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx]); 1.785 + total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]); 1.786 + } 1.787 + 1.788 + *end_offset = skippy_iter.idx - buffer->idx + 1; 1.789 + 1.790 + if (p_is_mark_ligature) 1.791 + *p_is_mark_ligature = is_mark_ligature; 1.792 + 1.793 + if (p_total_component_count) 1.794 + *p_total_component_count = total_component_count; 1.795 + 1.796 + return TRACE_RETURN (true); 1.797 +} 1.798 +static inline void ligate_input (hb_apply_context_t *c, 1.799 + unsigned int count, /* Including the first glyph */ 1.800 + unsigned int match_positions[MAX_CONTEXT_LENGTH], /* Including the first glyph */ 1.801 + unsigned int match_length, 1.802 + hb_codepoint_t lig_glyph, 1.803 + bool is_mark_ligature, 1.804 + unsigned int total_component_count) 1.805 +{ 1.806 + TRACE_APPLY (NULL); 1.807 + 1.808 + hb_buffer_t *buffer = c->buffer; 1.809 + 1.810 + buffer->merge_clusters (buffer->idx, buffer->idx + match_length); 1.811 + 1.812 + /* 1.813 + * - If it *is* a mark ligature, we don't allocate a new ligature id, and leave 1.814 + * the ligature to keep its old ligature id. This will allow it to attach to 1.815 + * a base ligature in GPOS. Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH, 1.816 + * and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA wit a 1.817 + * ligature id and component value of 2. Then if SHADDA,FATHA form a ligature 1.818 + * later, we don't want them to lose their ligature id/component, otherwise 1.819 + * GPOS will fail to correctly position the mark ligature on top of the 1.820 + * LAM,LAM,HEH ligature. See: 1.821 + * https://bugzilla.gnome.org/show_bug.cgi?id=676343 1.822 + * 1.823 + * - If a ligature is formed of components that some of which are also ligatures 1.824 + * themselves, and those ligature components had marks attached to *their* 1.825 + * components, we have to attach the marks to the new ligature component 1.826 + * positions! Now *that*'s tricky! And these marks may be following the 1.827 + * last component of the whole sequence, so we should loop forward looking 1.828 + * for them and update them. 1.829 + * 1.830 + * Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a 1.831 + * 'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature 1.832 + * id and component == 1. Now, during 'liga', the LAM and the LAM-HEH ligature 1.833 + * form a LAM-LAM-HEH ligature. We need to reassign the SHADDA and FATHA to 1.834 + * the new ligature with a component value of 2. 1.835 + * 1.836 + * This in fact happened to a font... See: 1.837 + * https://bugzilla.gnome.org/show_bug.cgi?id=437633 1.838 + */ 1.839 + 1.840 + unsigned int klass = is_mark_ligature ? 0 : HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE; 1.841 + unsigned int lig_id = is_mark_ligature ? 0 : _hb_allocate_lig_id (buffer); 1.842 + unsigned int last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur()); 1.843 + unsigned int last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur()); 1.844 + unsigned int components_so_far = last_num_components; 1.845 + 1.846 + if (!is_mark_ligature) 1.847 + { 1.848 + _hb_glyph_info_set_lig_props_for_ligature (&buffer->cur(), lig_id, total_component_count); 1.849 + if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) 1.850 + { 1.851 + _hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER); 1.852 + _hb_glyph_info_set_modified_combining_class (&buffer->cur(), 0); 1.853 + } 1.854 + } 1.855 + c->replace_glyph_with_ligature (lig_glyph, klass); 1.856 + 1.857 + for (unsigned int i = 1; i < count; i++) 1.858 + { 1.859 + while (buffer->idx < match_positions[i]) 1.860 + { 1.861 + if (!is_mark_ligature) { 1.862 + unsigned int new_lig_comp = components_so_far - last_num_components + 1.863 + MIN (MAX (_hb_glyph_info_get_lig_comp (&buffer->cur()), 1u), last_num_components); 1.864 + _hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp); 1.865 + } 1.866 + buffer->next_glyph (); 1.867 + } 1.868 + 1.869 + last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur()); 1.870 + last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur()); 1.871 + components_so_far += last_num_components; 1.872 + 1.873 + /* Skip the base glyph */ 1.874 + buffer->idx++; 1.875 + } 1.876 + 1.877 + if (!is_mark_ligature && last_lig_id) { 1.878 + /* Re-adjust components for any marks following. */ 1.879 + for (unsigned int i = buffer->idx; i < buffer->len; i++) { 1.880 + if (last_lig_id == _hb_glyph_info_get_lig_id (&buffer->info[i])) { 1.881 + unsigned int new_lig_comp = components_so_far - last_num_components + 1.882 + MIN (MAX (_hb_glyph_info_get_lig_comp (&buffer->info[i]), 1u), last_num_components); 1.883 + _hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp); 1.884 + } else 1.885 + break; 1.886 + } 1.887 + } 1.888 +} 1.889 + 1.890 +static inline bool match_backtrack (hb_apply_context_t *c, 1.891 + unsigned int count, 1.892 + const USHORT backtrack[], 1.893 + match_func_t match_func, 1.894 + const void *match_data) 1.895 +{ 1.896 + TRACE_APPLY (NULL); 1.897 + 1.898 + hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, c->buffer->backtrack_len (), count, true); 1.899 + skippy_iter.set_match_func (match_func, match_data, backtrack); 1.900 + if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false); 1.901 + 1.902 + for (unsigned int i = 0; i < count; i++) 1.903 + if (!skippy_iter.prev ()) 1.904 + return TRACE_RETURN (false); 1.905 + 1.906 + return TRACE_RETURN (true); 1.907 +} 1.908 + 1.909 +static inline bool match_lookahead (hb_apply_context_t *c, 1.910 + unsigned int count, 1.911 + const USHORT lookahead[], 1.912 + match_func_t match_func, 1.913 + const void *match_data, 1.914 + unsigned int offset) 1.915 +{ 1.916 + TRACE_APPLY (NULL); 1.917 + 1.918 + hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx + offset - 1, count, true); 1.919 + skippy_iter.set_match_func (match_func, match_data, lookahead); 1.920 + if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false); 1.921 + 1.922 + for (unsigned int i = 0; i < count; i++) 1.923 + if (!skippy_iter.next ()) 1.924 + return TRACE_RETURN (false); 1.925 + 1.926 + return TRACE_RETURN (true); 1.927 +} 1.928 + 1.929 + 1.930 + 1.931 +struct LookupRecord 1.932 +{ 1.933 + inline bool sanitize (hb_sanitize_context_t *c) { 1.934 + TRACE_SANITIZE (this); 1.935 + return TRACE_RETURN (c->check_struct (this)); 1.936 + } 1.937 + 1.938 + USHORT sequenceIndex; /* Index into current glyph 1.939 + * sequence--first glyph = 0 */ 1.940 + USHORT lookupListIndex; /* Lookup to apply to that 1.941 + * position--zero--based */ 1.942 + public: 1.943 + DEFINE_SIZE_STATIC (4); 1.944 +}; 1.945 + 1.946 + 1.947 +template <typename context_t> 1.948 +static inline void recurse_lookups (context_t *c, 1.949 + unsigned int lookupCount, 1.950 + const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */) 1.951 +{ 1.952 + for (unsigned int i = 0; i < lookupCount; i++) 1.953 + c->recurse (lookupRecord[i].lookupListIndex); 1.954 +} 1.955 + 1.956 +static inline bool apply_lookup (hb_apply_context_t *c, 1.957 + unsigned int count, /* Including the first glyph */ 1.958 + unsigned int match_positions[MAX_CONTEXT_LENGTH], /* Including the first glyph */ 1.959 + unsigned int lookupCount, 1.960 + const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */ 1.961 + unsigned int match_length) 1.962 +{ 1.963 + TRACE_APPLY (NULL); 1.964 + 1.965 + hb_buffer_t *buffer = c->buffer; 1.966 + unsigned int end; 1.967 + 1.968 + /* All positions are distance from beginning of *output* buffer. 1.969 + * Adjust. */ 1.970 + { 1.971 + unsigned int bl = buffer->backtrack_len (); 1.972 + end = bl + match_length; 1.973 + 1.974 + int delta = bl - buffer->idx; 1.975 + /* Convert positions to new indexing. */ 1.976 + for (unsigned int j = 0; j < count; j++) 1.977 + match_positions[j] += delta; 1.978 + } 1.979 + 1.980 + for (unsigned int i = 0; i < lookupCount; i++) 1.981 + { 1.982 + unsigned int idx = lookupRecord[i].sequenceIndex; 1.983 + if (idx >= count) 1.984 + continue; 1.985 + 1.986 + buffer->move_to (match_positions[idx]); 1.987 + 1.988 + unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len (); 1.989 + if (!c->recurse (lookupRecord[i].lookupListIndex)) 1.990 + continue; 1.991 + 1.992 + unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len (); 1.993 + int delta = new_len - orig_len; 1.994 + 1.995 + if (!delta) 1.996 + continue; 1.997 + 1.998 + /* Recursed lookup changed buffer len. Adjust. */ 1.999 + 1.1000 + /* end can't go back past the current match position. */ 1.1001 + end = MAX ((int) match_positions[idx] + 1, int (end) + delta); 1.1002 + 1.1003 + unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */ 1.1004 + 1.1005 + if (delta > 0) 1.1006 + { 1.1007 + if (unlikely (delta + count > MAX_CONTEXT_LENGTH)) 1.1008 + break; 1.1009 + } 1.1010 + else 1.1011 + { 1.1012 + /* NOTE: delta is negative. */ 1.1013 + delta = MAX (delta, (int) next - (int) count); 1.1014 + next -= delta; 1.1015 + } 1.1016 + 1.1017 + /* Shift! */ 1.1018 + memmove (match_positions + next + delta, match_positions + next, 1.1019 + (count - next) * sizeof (match_positions[0])); 1.1020 + next += delta; 1.1021 + count += delta; 1.1022 + 1.1023 + /* Fill in new entries. */ 1.1024 + for (unsigned int j = idx + 1; j < next; j++) 1.1025 + match_positions[j] = match_positions[j - 1] + 1; 1.1026 + 1.1027 + /* And fixup the rest. */ 1.1028 + for (; next < count; next++) 1.1029 + match_positions[next] += delta; 1.1030 + } 1.1031 + 1.1032 + buffer->move_to (end); 1.1033 + 1.1034 + return TRACE_RETURN (true); 1.1035 +} 1.1036 + 1.1037 + 1.1038 + 1.1039 +/* Contextual lookups */ 1.1040 + 1.1041 +struct ContextClosureLookupContext 1.1042 +{ 1.1043 + ContextClosureFuncs funcs; 1.1044 + const void *intersects_data; 1.1045 +}; 1.1046 + 1.1047 +struct ContextCollectGlyphsLookupContext 1.1048 +{ 1.1049 + ContextCollectGlyphsFuncs funcs; 1.1050 + const void *collect_data; 1.1051 +}; 1.1052 + 1.1053 +struct ContextApplyLookupContext 1.1054 +{ 1.1055 + ContextApplyFuncs funcs; 1.1056 + const void *match_data; 1.1057 +}; 1.1058 + 1.1059 +static inline void context_closure_lookup (hb_closure_context_t *c, 1.1060 + unsigned int inputCount, /* Including the first glyph (not matched) */ 1.1061 + const USHORT input[], /* Array of input values--start with second glyph */ 1.1062 + unsigned int lookupCount, 1.1063 + const LookupRecord lookupRecord[], 1.1064 + ContextClosureLookupContext &lookup_context) 1.1065 +{ 1.1066 + if (intersects_array (c, 1.1067 + inputCount ? inputCount - 1 : 0, input, 1.1068 + lookup_context.funcs.intersects, lookup_context.intersects_data)) 1.1069 + recurse_lookups (c, 1.1070 + lookupCount, lookupRecord); 1.1071 +} 1.1072 + 1.1073 +static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c, 1.1074 + unsigned int inputCount, /* Including the first glyph (not matched) */ 1.1075 + const USHORT input[], /* Array of input values--start with second glyph */ 1.1076 + unsigned int lookupCount, 1.1077 + const LookupRecord lookupRecord[], 1.1078 + ContextCollectGlyphsLookupContext &lookup_context) 1.1079 +{ 1.1080 + collect_array (c, c->input, 1.1081 + inputCount ? inputCount - 1 : 0, input, 1.1082 + lookup_context.funcs.collect, lookup_context.collect_data); 1.1083 + recurse_lookups (c, 1.1084 + lookupCount, lookupRecord); 1.1085 +} 1.1086 + 1.1087 +static inline bool context_would_apply_lookup (hb_would_apply_context_t *c, 1.1088 + unsigned int inputCount, /* Including the first glyph (not matched) */ 1.1089 + const USHORT input[], /* Array of input values--start with second glyph */ 1.1090 + unsigned int lookupCount HB_UNUSED, 1.1091 + const LookupRecord lookupRecord[] HB_UNUSED, 1.1092 + ContextApplyLookupContext &lookup_context) 1.1093 +{ 1.1094 + return would_match_input (c, 1.1095 + inputCount, input, 1.1096 + lookup_context.funcs.match, lookup_context.match_data); 1.1097 +} 1.1098 +static inline bool context_apply_lookup (hb_apply_context_t *c, 1.1099 + unsigned int inputCount, /* Including the first glyph (not matched) */ 1.1100 + const USHORT input[], /* Array of input values--start with second glyph */ 1.1101 + unsigned int lookupCount, 1.1102 + const LookupRecord lookupRecord[], 1.1103 + ContextApplyLookupContext &lookup_context) 1.1104 +{ 1.1105 + unsigned int match_length = 0; 1.1106 + unsigned int match_positions[MAX_CONTEXT_LENGTH]; 1.1107 + return match_input (c, 1.1108 + inputCount, input, 1.1109 + lookup_context.funcs.match, lookup_context.match_data, 1.1110 + &match_length, match_positions) 1.1111 + && apply_lookup (c, 1.1112 + inputCount, match_positions, 1.1113 + lookupCount, lookupRecord, 1.1114 + match_length); 1.1115 +} 1.1116 + 1.1117 +struct Rule 1.1118 +{ 1.1119 + inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const 1.1120 + { 1.1121 + TRACE_CLOSURE (this); 1.1122 + const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0)); 1.1123 + context_closure_lookup (c, 1.1124 + inputCount, input, 1.1125 + lookupCount, lookupRecord, 1.1126 + lookup_context); 1.1127 + } 1.1128 + 1.1129 + inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const 1.1130 + { 1.1131 + TRACE_COLLECT_GLYPHS (this); 1.1132 + const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0)); 1.1133 + context_collect_glyphs_lookup (c, 1.1134 + inputCount, input, 1.1135 + lookupCount, lookupRecord, 1.1136 + lookup_context); 1.1137 + } 1.1138 + 1.1139 + inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const 1.1140 + { 1.1141 + TRACE_WOULD_APPLY (this); 1.1142 + const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0)); 1.1143 + return TRACE_RETURN (context_would_apply_lookup (c, inputCount, input, lookupCount, lookupRecord, lookup_context)); 1.1144 + } 1.1145 + 1.1146 + inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const 1.1147 + { 1.1148 + TRACE_APPLY (this); 1.1149 + const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0)); 1.1150 + return TRACE_RETURN (context_apply_lookup (c, inputCount, input, lookupCount, lookupRecord, lookup_context)); 1.1151 + } 1.1152 + 1.1153 + public: 1.1154 + inline bool sanitize (hb_sanitize_context_t *c) { 1.1155 + TRACE_SANITIZE (this); 1.1156 + return inputCount.sanitize (c) 1.1157 + && lookupCount.sanitize (c) 1.1158 + && c->check_range (input, 1.1159 + input[0].static_size * inputCount 1.1160 + + lookupRecordX[0].static_size * lookupCount); 1.1161 + } 1.1162 + 1.1163 + protected: 1.1164 + USHORT inputCount; /* Total number of glyphs in input 1.1165 + * glyph sequence--includes the first 1.1166 + * glyph */ 1.1167 + USHORT lookupCount; /* Number of LookupRecords */ 1.1168 + USHORT input[VAR]; /* Array of match inputs--start with 1.1169 + * second glyph */ 1.1170 + LookupRecord lookupRecordX[VAR]; /* Array of LookupRecords--in 1.1171 + * design order */ 1.1172 + public: 1.1173 + DEFINE_SIZE_ARRAY2 (4, input, lookupRecordX); 1.1174 +}; 1.1175 + 1.1176 +struct RuleSet 1.1177 +{ 1.1178 + inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const 1.1179 + { 1.1180 + TRACE_CLOSURE (this); 1.1181 + unsigned int num_rules = rule.len; 1.1182 + for (unsigned int i = 0; i < num_rules; i++) 1.1183 + (this+rule[i]).closure (c, lookup_context); 1.1184 + } 1.1185 + 1.1186 + inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const 1.1187 + { 1.1188 + TRACE_COLLECT_GLYPHS (this); 1.1189 + unsigned int num_rules = rule.len; 1.1190 + for (unsigned int i = 0; i < num_rules; i++) 1.1191 + (this+rule[i]).collect_glyphs (c, lookup_context); 1.1192 + } 1.1193 + 1.1194 + inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const 1.1195 + { 1.1196 + TRACE_WOULD_APPLY (this); 1.1197 + unsigned int num_rules = rule.len; 1.1198 + for (unsigned int i = 0; i < num_rules; i++) 1.1199 + { 1.1200 + if ((this+rule[i]).would_apply (c, lookup_context)) 1.1201 + return TRACE_RETURN (true); 1.1202 + } 1.1203 + return TRACE_RETURN (false); 1.1204 + } 1.1205 + 1.1206 + inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const 1.1207 + { 1.1208 + TRACE_APPLY (this); 1.1209 + unsigned int num_rules = rule.len; 1.1210 + for (unsigned int i = 0; i < num_rules; i++) 1.1211 + { 1.1212 + if ((this+rule[i]).apply (c, lookup_context)) 1.1213 + return TRACE_RETURN (true); 1.1214 + } 1.1215 + return TRACE_RETURN (false); 1.1216 + } 1.1217 + 1.1218 + inline bool sanitize (hb_sanitize_context_t *c) { 1.1219 + TRACE_SANITIZE (this); 1.1220 + return TRACE_RETURN (rule.sanitize (c, this)); 1.1221 + } 1.1222 + 1.1223 + protected: 1.1224 + OffsetArrayOf<Rule> 1.1225 + rule; /* Array of Rule tables 1.1226 + * ordered by preference */ 1.1227 + public: 1.1228 + DEFINE_SIZE_ARRAY (2, rule); 1.1229 +}; 1.1230 + 1.1231 + 1.1232 +struct ContextFormat1 1.1233 +{ 1.1234 + inline void closure (hb_closure_context_t *c) const 1.1235 + { 1.1236 + TRACE_CLOSURE (this); 1.1237 + 1.1238 + const Coverage &cov = (this+coverage); 1.1239 + 1.1240 + struct ContextClosureLookupContext lookup_context = { 1.1241 + {intersects_glyph}, 1.1242 + NULL 1.1243 + }; 1.1244 + 1.1245 + unsigned int count = ruleSet.len; 1.1246 + for (unsigned int i = 0; i < count; i++) 1.1247 + if (cov.intersects_coverage (c->glyphs, i)) { 1.1248 + const RuleSet &rule_set = this+ruleSet[i]; 1.1249 + rule_set.closure (c, lookup_context); 1.1250 + } 1.1251 + } 1.1252 + 1.1253 + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 1.1254 + { 1.1255 + TRACE_COLLECT_GLYPHS (this); 1.1256 + (this+coverage).add_coverage (c->input); 1.1257 + 1.1258 + struct ContextCollectGlyphsLookupContext lookup_context = { 1.1259 + {collect_glyph}, 1.1260 + NULL 1.1261 + }; 1.1262 + 1.1263 + unsigned int count = ruleSet.len; 1.1264 + for (unsigned int i = 0; i < count; i++) 1.1265 + (this+ruleSet[i]).collect_glyphs (c, lookup_context); 1.1266 + } 1.1267 + 1.1268 + inline bool would_apply (hb_would_apply_context_t *c) const 1.1269 + { 1.1270 + TRACE_WOULD_APPLY (this); 1.1271 + 1.1272 + const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])]; 1.1273 + struct ContextApplyLookupContext lookup_context = { 1.1274 + {match_glyph}, 1.1275 + NULL 1.1276 + }; 1.1277 + return TRACE_RETURN (rule_set.would_apply (c, lookup_context)); 1.1278 + } 1.1279 + 1.1280 + inline const Coverage &get_coverage (void) const 1.1281 + { 1.1282 + return this+coverage; 1.1283 + } 1.1284 + 1.1285 + inline bool apply (hb_apply_context_t *c) const 1.1286 + { 1.1287 + TRACE_APPLY (this); 1.1288 + unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); 1.1289 + if (likely (index == NOT_COVERED)) 1.1290 + return TRACE_RETURN (false); 1.1291 + 1.1292 + const RuleSet &rule_set = this+ruleSet[index]; 1.1293 + struct ContextApplyLookupContext lookup_context = { 1.1294 + {match_glyph}, 1.1295 + NULL 1.1296 + }; 1.1297 + return TRACE_RETURN (rule_set.apply (c, lookup_context)); 1.1298 + } 1.1299 + 1.1300 + inline bool sanitize (hb_sanitize_context_t *c) { 1.1301 + TRACE_SANITIZE (this); 1.1302 + return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this)); 1.1303 + } 1.1304 + 1.1305 + protected: 1.1306 + USHORT format; /* Format identifier--format = 1 */ 1.1307 + OffsetTo<Coverage> 1.1308 + coverage; /* Offset to Coverage table--from 1.1309 + * beginning of table */ 1.1310 + OffsetArrayOf<RuleSet> 1.1311 + ruleSet; /* Array of RuleSet tables 1.1312 + * ordered by Coverage Index */ 1.1313 + public: 1.1314 + DEFINE_SIZE_ARRAY (6, ruleSet); 1.1315 +}; 1.1316 + 1.1317 + 1.1318 +struct ContextFormat2 1.1319 +{ 1.1320 + inline void closure (hb_closure_context_t *c) const 1.1321 + { 1.1322 + TRACE_CLOSURE (this); 1.1323 + if (!(this+coverage).intersects (c->glyphs)) 1.1324 + return; 1.1325 + 1.1326 + const ClassDef &class_def = this+classDef; 1.1327 + 1.1328 + struct ContextClosureLookupContext lookup_context = { 1.1329 + {intersects_class}, 1.1330 + &class_def 1.1331 + }; 1.1332 + 1.1333 + unsigned int count = ruleSet.len; 1.1334 + for (unsigned int i = 0; i < count; i++) 1.1335 + if (class_def.intersects_class (c->glyphs, i)) { 1.1336 + const RuleSet &rule_set = this+ruleSet[i]; 1.1337 + rule_set.closure (c, lookup_context); 1.1338 + } 1.1339 + } 1.1340 + 1.1341 + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 1.1342 + { 1.1343 + TRACE_COLLECT_GLYPHS (this); 1.1344 + (this+coverage).add_coverage (c->input); 1.1345 + 1.1346 + const ClassDef &class_def = this+classDef; 1.1347 + struct ContextCollectGlyphsLookupContext lookup_context = { 1.1348 + {collect_class}, 1.1349 + &class_def 1.1350 + }; 1.1351 + 1.1352 + unsigned int count = ruleSet.len; 1.1353 + for (unsigned int i = 0; i < count; i++) 1.1354 + (this+ruleSet[i]).collect_glyphs (c, lookup_context); 1.1355 + } 1.1356 + 1.1357 + inline bool would_apply (hb_would_apply_context_t *c) const 1.1358 + { 1.1359 + TRACE_WOULD_APPLY (this); 1.1360 + 1.1361 + const ClassDef &class_def = this+classDef; 1.1362 + unsigned int index = class_def.get_class (c->glyphs[0]); 1.1363 + const RuleSet &rule_set = this+ruleSet[index]; 1.1364 + struct ContextApplyLookupContext lookup_context = { 1.1365 + {match_class}, 1.1366 + &class_def 1.1367 + }; 1.1368 + return TRACE_RETURN (rule_set.would_apply (c, lookup_context)); 1.1369 + } 1.1370 + 1.1371 + inline const Coverage &get_coverage (void) const 1.1372 + { 1.1373 + return this+coverage; 1.1374 + } 1.1375 + 1.1376 + inline bool apply (hb_apply_context_t *c) const 1.1377 + { 1.1378 + TRACE_APPLY (this); 1.1379 + unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); 1.1380 + if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); 1.1381 + 1.1382 + const ClassDef &class_def = this+classDef; 1.1383 + index = class_def.get_class (c->buffer->cur().codepoint); 1.1384 + const RuleSet &rule_set = this+ruleSet[index]; 1.1385 + struct ContextApplyLookupContext lookup_context = { 1.1386 + {match_class}, 1.1387 + &class_def 1.1388 + }; 1.1389 + return TRACE_RETURN (rule_set.apply (c, lookup_context)); 1.1390 + } 1.1391 + 1.1392 + inline bool sanitize (hb_sanitize_context_t *c) { 1.1393 + TRACE_SANITIZE (this); 1.1394 + return TRACE_RETURN (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this)); 1.1395 + } 1.1396 + 1.1397 + protected: 1.1398 + USHORT format; /* Format identifier--format = 2 */ 1.1399 + OffsetTo<Coverage> 1.1400 + coverage; /* Offset to Coverage table--from 1.1401 + * beginning of table */ 1.1402 + OffsetTo<ClassDef> 1.1403 + classDef; /* Offset to glyph ClassDef table--from 1.1404 + * beginning of table */ 1.1405 + OffsetArrayOf<RuleSet> 1.1406 + ruleSet; /* Array of RuleSet tables 1.1407 + * ordered by class */ 1.1408 + public: 1.1409 + DEFINE_SIZE_ARRAY (8, ruleSet); 1.1410 +}; 1.1411 + 1.1412 + 1.1413 +struct ContextFormat3 1.1414 +{ 1.1415 + inline void closure (hb_closure_context_t *c) const 1.1416 + { 1.1417 + TRACE_CLOSURE (this); 1.1418 + if (!(this+coverage[0]).intersects (c->glyphs)) 1.1419 + return; 1.1420 + 1.1421 + const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount); 1.1422 + struct ContextClosureLookupContext lookup_context = { 1.1423 + {intersects_coverage}, 1.1424 + this 1.1425 + }; 1.1426 + context_closure_lookup (c, 1.1427 + glyphCount, (const USHORT *) (coverage + 1), 1.1428 + lookupCount, lookupRecord, 1.1429 + lookup_context); 1.1430 + } 1.1431 + 1.1432 + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 1.1433 + { 1.1434 + TRACE_COLLECT_GLYPHS (this); 1.1435 + (this+coverage[0]).add_coverage (c->input); 1.1436 + 1.1437 + const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount); 1.1438 + struct ContextCollectGlyphsLookupContext lookup_context = { 1.1439 + {collect_coverage}, 1.1440 + this 1.1441 + }; 1.1442 + 1.1443 + context_collect_glyphs_lookup (c, 1.1444 + glyphCount, (const USHORT *) (coverage + 1), 1.1445 + lookupCount, lookupRecord, 1.1446 + lookup_context); 1.1447 + } 1.1448 + 1.1449 + inline bool would_apply (hb_would_apply_context_t *c) const 1.1450 + { 1.1451 + TRACE_WOULD_APPLY (this); 1.1452 + 1.1453 + const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount); 1.1454 + struct ContextApplyLookupContext lookup_context = { 1.1455 + {match_coverage}, 1.1456 + this 1.1457 + }; 1.1458 + return TRACE_RETURN (context_would_apply_lookup (c, glyphCount, (const USHORT *) (coverage + 1), lookupCount, lookupRecord, lookup_context)); 1.1459 + } 1.1460 + 1.1461 + inline const Coverage &get_coverage (void) const 1.1462 + { 1.1463 + return this+coverage[0]; 1.1464 + } 1.1465 + 1.1466 + inline bool apply (hb_apply_context_t *c) const 1.1467 + { 1.1468 + TRACE_APPLY (this); 1.1469 + unsigned int index = (this+coverage[0]).get_coverage (c->buffer->cur().codepoint); 1.1470 + if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); 1.1471 + 1.1472 + const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount); 1.1473 + struct ContextApplyLookupContext lookup_context = { 1.1474 + {match_coverage}, 1.1475 + this 1.1476 + }; 1.1477 + return TRACE_RETURN (context_apply_lookup (c, glyphCount, (const USHORT *) (coverage + 1), lookupCount, lookupRecord, lookup_context)); 1.1478 + } 1.1479 + 1.1480 + inline bool sanitize (hb_sanitize_context_t *c) { 1.1481 + TRACE_SANITIZE (this); 1.1482 + if (!c->check_struct (this)) return TRACE_RETURN (false); 1.1483 + unsigned int count = glyphCount; 1.1484 + if (!c->check_array (coverage, coverage[0].static_size, count)) return TRACE_RETURN (false); 1.1485 + for (unsigned int i = 0; i < count; i++) 1.1486 + if (!coverage[i].sanitize (c, this)) return TRACE_RETURN (false); 1.1487 + LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * count); 1.1488 + return TRACE_RETURN (c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount)); 1.1489 + } 1.1490 + 1.1491 + protected: 1.1492 + USHORT format; /* Format identifier--format = 3 */ 1.1493 + USHORT glyphCount; /* Number of glyphs in the input glyph 1.1494 + * sequence */ 1.1495 + USHORT lookupCount; /* Number of LookupRecords */ 1.1496 + OffsetTo<Coverage> 1.1497 + coverage[VAR]; /* Array of offsets to Coverage 1.1498 + * table in glyph sequence order */ 1.1499 + LookupRecord lookupRecordX[VAR]; /* Array of LookupRecords--in 1.1500 + * design order */ 1.1501 + public: 1.1502 + DEFINE_SIZE_ARRAY2 (6, coverage, lookupRecordX); 1.1503 +}; 1.1504 + 1.1505 +struct Context 1.1506 +{ 1.1507 + template <typename context_t> 1.1508 + inline typename context_t::return_t dispatch (context_t *c) const 1.1509 + { 1.1510 + TRACE_DISPATCH (this); 1.1511 + switch (u.format) { 1.1512 + case 1: return TRACE_RETURN (c->dispatch (u.format1)); 1.1513 + case 2: return TRACE_RETURN (c->dispatch (u.format2)); 1.1514 + case 3: return TRACE_RETURN (c->dispatch (u.format3)); 1.1515 + default:return TRACE_RETURN (c->default_return_value ()); 1.1516 + } 1.1517 + } 1.1518 + 1.1519 + inline bool sanitize (hb_sanitize_context_t *c) { 1.1520 + TRACE_SANITIZE (this); 1.1521 + if (!u.format.sanitize (c)) return TRACE_RETURN (false); 1.1522 + switch (u.format) { 1.1523 + case 1: return TRACE_RETURN (u.format1.sanitize (c)); 1.1524 + case 2: return TRACE_RETURN (u.format2.sanitize (c)); 1.1525 + case 3: return TRACE_RETURN (u.format3.sanitize (c)); 1.1526 + default:return TRACE_RETURN (true); 1.1527 + } 1.1528 + } 1.1529 + 1.1530 + protected: 1.1531 + union { 1.1532 + USHORT format; /* Format identifier */ 1.1533 + ContextFormat1 format1; 1.1534 + ContextFormat2 format2; 1.1535 + ContextFormat3 format3; 1.1536 + } u; 1.1537 +}; 1.1538 + 1.1539 + 1.1540 +/* Chaining Contextual lookups */ 1.1541 + 1.1542 +struct ChainContextClosureLookupContext 1.1543 +{ 1.1544 + ContextClosureFuncs funcs; 1.1545 + const void *intersects_data[3]; 1.1546 +}; 1.1547 + 1.1548 +struct ChainContextCollectGlyphsLookupContext 1.1549 +{ 1.1550 + ContextCollectGlyphsFuncs funcs; 1.1551 + const void *collect_data[3]; 1.1552 +}; 1.1553 + 1.1554 +struct ChainContextApplyLookupContext 1.1555 +{ 1.1556 + ContextApplyFuncs funcs; 1.1557 + const void *match_data[3]; 1.1558 +}; 1.1559 + 1.1560 +static inline void chain_context_closure_lookup (hb_closure_context_t *c, 1.1561 + unsigned int backtrackCount, 1.1562 + const USHORT backtrack[], 1.1563 + unsigned int inputCount, /* Including the first glyph (not matched) */ 1.1564 + const USHORT input[], /* Array of input values--start with second glyph */ 1.1565 + unsigned int lookaheadCount, 1.1566 + const USHORT lookahead[], 1.1567 + unsigned int lookupCount, 1.1568 + const LookupRecord lookupRecord[], 1.1569 + ChainContextClosureLookupContext &lookup_context) 1.1570 +{ 1.1571 + if (intersects_array (c, 1.1572 + backtrackCount, backtrack, 1.1573 + lookup_context.funcs.intersects, lookup_context.intersects_data[0]) 1.1574 + && intersects_array (c, 1.1575 + inputCount ? inputCount - 1 : 0, input, 1.1576 + lookup_context.funcs.intersects, lookup_context.intersects_data[1]) 1.1577 + && intersects_array (c, 1.1578 + lookaheadCount, lookahead, 1.1579 + lookup_context.funcs.intersects, lookup_context.intersects_data[2])) 1.1580 + recurse_lookups (c, 1.1581 + lookupCount, lookupRecord); 1.1582 +} 1.1583 + 1.1584 +static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c, 1.1585 + unsigned int backtrackCount, 1.1586 + const USHORT backtrack[], 1.1587 + unsigned int inputCount, /* Including the first glyph (not matched) */ 1.1588 + const USHORT input[], /* Array of input values--start with second glyph */ 1.1589 + unsigned int lookaheadCount, 1.1590 + const USHORT lookahead[], 1.1591 + unsigned int lookupCount, 1.1592 + const LookupRecord lookupRecord[], 1.1593 + ChainContextCollectGlyphsLookupContext &lookup_context) 1.1594 +{ 1.1595 + collect_array (c, c->before, 1.1596 + backtrackCount, backtrack, 1.1597 + lookup_context.funcs.collect, lookup_context.collect_data[0]); 1.1598 + collect_array (c, c->input, 1.1599 + inputCount ? inputCount - 1 : 0, input, 1.1600 + lookup_context.funcs.collect, lookup_context.collect_data[1]); 1.1601 + collect_array (c, c->after, 1.1602 + lookaheadCount, lookahead, 1.1603 + lookup_context.funcs.collect, lookup_context.collect_data[2]); 1.1604 + recurse_lookups (c, 1.1605 + lookupCount, lookupRecord); 1.1606 +} 1.1607 + 1.1608 +static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c, 1.1609 + unsigned int backtrackCount, 1.1610 + const USHORT backtrack[] HB_UNUSED, 1.1611 + unsigned int inputCount, /* Including the first glyph (not matched) */ 1.1612 + const USHORT input[], /* Array of input values--start with second glyph */ 1.1613 + unsigned int lookaheadCount, 1.1614 + const USHORT lookahead[] HB_UNUSED, 1.1615 + unsigned int lookupCount HB_UNUSED, 1.1616 + const LookupRecord lookupRecord[] HB_UNUSED, 1.1617 + ChainContextApplyLookupContext &lookup_context) 1.1618 +{ 1.1619 + return (c->zero_context ? !backtrackCount && !lookaheadCount : true) 1.1620 + && would_match_input (c, 1.1621 + inputCount, input, 1.1622 + lookup_context.funcs.match, lookup_context.match_data[1]); 1.1623 +} 1.1624 + 1.1625 +static inline bool chain_context_apply_lookup (hb_apply_context_t *c, 1.1626 + unsigned int backtrackCount, 1.1627 + const USHORT backtrack[], 1.1628 + unsigned int inputCount, /* Including the first glyph (not matched) */ 1.1629 + const USHORT input[], /* Array of input values--start with second glyph */ 1.1630 + unsigned int lookaheadCount, 1.1631 + const USHORT lookahead[], 1.1632 + unsigned int lookupCount, 1.1633 + const LookupRecord lookupRecord[], 1.1634 + ChainContextApplyLookupContext &lookup_context) 1.1635 +{ 1.1636 + unsigned int match_length = 0; 1.1637 + unsigned int match_positions[MAX_CONTEXT_LENGTH]; 1.1638 + return match_input (c, 1.1639 + inputCount, input, 1.1640 + lookup_context.funcs.match, lookup_context.match_data[1], 1.1641 + &match_length, match_positions) 1.1642 + && match_backtrack (c, 1.1643 + backtrackCount, backtrack, 1.1644 + lookup_context.funcs.match, lookup_context.match_data[0]) 1.1645 + && match_lookahead (c, 1.1646 + lookaheadCount, lookahead, 1.1647 + lookup_context.funcs.match, lookup_context.match_data[2], 1.1648 + match_length) 1.1649 + && apply_lookup (c, 1.1650 + inputCount, match_positions, 1.1651 + lookupCount, lookupRecord, 1.1652 + match_length); 1.1653 +} 1.1654 + 1.1655 +struct ChainRule 1.1656 +{ 1.1657 + inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const 1.1658 + { 1.1659 + TRACE_CLOSURE (this); 1.1660 + const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); 1.1661 + const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); 1.1662 + const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1.1663 + chain_context_closure_lookup (c, 1.1664 + backtrack.len, backtrack.array, 1.1665 + input.len, input.array, 1.1666 + lookahead.len, lookahead.array, 1.1667 + lookup.len, lookup.array, 1.1668 + lookup_context); 1.1669 + } 1.1670 + 1.1671 + inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const 1.1672 + { 1.1673 + TRACE_COLLECT_GLYPHS (this); 1.1674 + const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); 1.1675 + const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); 1.1676 + const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1.1677 + chain_context_collect_glyphs_lookup (c, 1.1678 + backtrack.len, backtrack.array, 1.1679 + input.len, input.array, 1.1680 + lookahead.len, lookahead.array, 1.1681 + lookup.len, lookup.array, 1.1682 + lookup_context); 1.1683 + } 1.1684 + 1.1685 + inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const 1.1686 + { 1.1687 + TRACE_WOULD_APPLY (this); 1.1688 + const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); 1.1689 + const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); 1.1690 + const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1.1691 + return TRACE_RETURN (chain_context_would_apply_lookup (c, 1.1692 + backtrack.len, backtrack.array, 1.1693 + input.len, input.array, 1.1694 + lookahead.len, lookahead.array, lookup.len, 1.1695 + lookup.array, lookup_context)); 1.1696 + } 1.1697 + 1.1698 + inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const 1.1699 + { 1.1700 + TRACE_APPLY (this); 1.1701 + const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); 1.1702 + const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); 1.1703 + const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1.1704 + return TRACE_RETURN (chain_context_apply_lookup (c, 1.1705 + backtrack.len, backtrack.array, 1.1706 + input.len, input.array, 1.1707 + lookahead.len, lookahead.array, lookup.len, 1.1708 + lookup.array, lookup_context)); 1.1709 + } 1.1710 + 1.1711 + inline bool sanitize (hb_sanitize_context_t *c) { 1.1712 + TRACE_SANITIZE (this); 1.1713 + if (!backtrack.sanitize (c)) return TRACE_RETURN (false); 1.1714 + HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); 1.1715 + if (!input.sanitize (c)) return TRACE_RETURN (false); 1.1716 + ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); 1.1717 + if (!lookahead.sanitize (c)) return TRACE_RETURN (false); 1.1718 + ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1.1719 + return TRACE_RETURN (lookup.sanitize (c)); 1.1720 + } 1.1721 + 1.1722 + protected: 1.1723 + ArrayOf<USHORT> 1.1724 + backtrack; /* Array of backtracking values 1.1725 + * (to be matched before the input 1.1726 + * sequence) */ 1.1727 + HeadlessArrayOf<USHORT> 1.1728 + inputX; /* Array of input values (start with 1.1729 + * second glyph) */ 1.1730 + ArrayOf<USHORT> 1.1731 + lookaheadX; /* Array of lookahead values's (to be 1.1732 + * matched after the input sequence) */ 1.1733 + ArrayOf<LookupRecord> 1.1734 + lookupX; /* Array of LookupRecords--in 1.1735 + * design order) */ 1.1736 + public: 1.1737 + DEFINE_SIZE_MIN (8); 1.1738 +}; 1.1739 + 1.1740 +struct ChainRuleSet 1.1741 +{ 1.1742 + inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const 1.1743 + { 1.1744 + TRACE_CLOSURE (this); 1.1745 + unsigned int num_rules = rule.len; 1.1746 + for (unsigned int i = 0; i < num_rules; i++) 1.1747 + (this+rule[i]).closure (c, lookup_context); 1.1748 + } 1.1749 + 1.1750 + inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const 1.1751 + { 1.1752 + TRACE_COLLECT_GLYPHS (this); 1.1753 + unsigned int num_rules = rule.len; 1.1754 + for (unsigned int i = 0; i < num_rules; i++) 1.1755 + (this+rule[i]).collect_glyphs (c, lookup_context); 1.1756 + } 1.1757 + 1.1758 + inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const 1.1759 + { 1.1760 + TRACE_WOULD_APPLY (this); 1.1761 + unsigned int num_rules = rule.len; 1.1762 + for (unsigned int i = 0; i < num_rules; i++) 1.1763 + if ((this+rule[i]).would_apply (c, lookup_context)) 1.1764 + return TRACE_RETURN (true); 1.1765 + 1.1766 + return TRACE_RETURN (false); 1.1767 + } 1.1768 + 1.1769 + inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const 1.1770 + { 1.1771 + TRACE_APPLY (this); 1.1772 + unsigned int num_rules = rule.len; 1.1773 + for (unsigned int i = 0; i < num_rules; i++) 1.1774 + if ((this+rule[i]).apply (c, lookup_context)) 1.1775 + return TRACE_RETURN (true); 1.1776 + 1.1777 + return TRACE_RETURN (false); 1.1778 + } 1.1779 + 1.1780 + inline bool sanitize (hb_sanitize_context_t *c) { 1.1781 + TRACE_SANITIZE (this); 1.1782 + return TRACE_RETURN (rule.sanitize (c, this)); 1.1783 + } 1.1784 + 1.1785 + protected: 1.1786 + OffsetArrayOf<ChainRule> 1.1787 + rule; /* Array of ChainRule tables 1.1788 + * ordered by preference */ 1.1789 + public: 1.1790 + DEFINE_SIZE_ARRAY (2, rule); 1.1791 +}; 1.1792 + 1.1793 +struct ChainContextFormat1 1.1794 +{ 1.1795 + inline void closure (hb_closure_context_t *c) const 1.1796 + { 1.1797 + TRACE_CLOSURE (this); 1.1798 + const Coverage &cov = (this+coverage); 1.1799 + 1.1800 + struct ChainContextClosureLookupContext lookup_context = { 1.1801 + {intersects_glyph}, 1.1802 + {NULL, NULL, NULL} 1.1803 + }; 1.1804 + 1.1805 + unsigned int count = ruleSet.len; 1.1806 + for (unsigned int i = 0; i < count; i++) 1.1807 + if (cov.intersects_coverage (c->glyphs, i)) { 1.1808 + const ChainRuleSet &rule_set = this+ruleSet[i]; 1.1809 + rule_set.closure (c, lookup_context); 1.1810 + } 1.1811 + } 1.1812 + 1.1813 + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 1.1814 + { 1.1815 + TRACE_COLLECT_GLYPHS (this); 1.1816 + (this+coverage).add_coverage (c->input); 1.1817 + 1.1818 + struct ChainContextCollectGlyphsLookupContext lookup_context = { 1.1819 + {collect_glyph}, 1.1820 + {NULL, NULL, NULL} 1.1821 + }; 1.1822 + 1.1823 + unsigned int count = ruleSet.len; 1.1824 + for (unsigned int i = 0; i < count; i++) 1.1825 + (this+ruleSet[i]).collect_glyphs (c, lookup_context); 1.1826 + } 1.1827 + 1.1828 + inline bool would_apply (hb_would_apply_context_t *c) const 1.1829 + { 1.1830 + TRACE_WOULD_APPLY (this); 1.1831 + 1.1832 + const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])]; 1.1833 + struct ChainContextApplyLookupContext lookup_context = { 1.1834 + {match_glyph}, 1.1835 + {NULL, NULL, NULL} 1.1836 + }; 1.1837 + return TRACE_RETURN (rule_set.would_apply (c, lookup_context)); 1.1838 + } 1.1839 + 1.1840 + inline const Coverage &get_coverage (void) const 1.1841 + { 1.1842 + return this+coverage; 1.1843 + } 1.1844 + 1.1845 + inline bool apply (hb_apply_context_t *c) const 1.1846 + { 1.1847 + TRACE_APPLY (this); 1.1848 + unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); 1.1849 + if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); 1.1850 + 1.1851 + const ChainRuleSet &rule_set = this+ruleSet[index]; 1.1852 + struct ChainContextApplyLookupContext lookup_context = { 1.1853 + {match_glyph}, 1.1854 + {NULL, NULL, NULL} 1.1855 + }; 1.1856 + return TRACE_RETURN (rule_set.apply (c, lookup_context)); 1.1857 + } 1.1858 + 1.1859 + inline bool sanitize (hb_sanitize_context_t *c) { 1.1860 + TRACE_SANITIZE (this); 1.1861 + return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this)); 1.1862 + } 1.1863 + 1.1864 + protected: 1.1865 + USHORT format; /* Format identifier--format = 1 */ 1.1866 + OffsetTo<Coverage> 1.1867 + coverage; /* Offset to Coverage table--from 1.1868 + * beginning of table */ 1.1869 + OffsetArrayOf<ChainRuleSet> 1.1870 + ruleSet; /* Array of ChainRuleSet tables 1.1871 + * ordered by Coverage Index */ 1.1872 + public: 1.1873 + DEFINE_SIZE_ARRAY (6, ruleSet); 1.1874 +}; 1.1875 + 1.1876 +struct ChainContextFormat2 1.1877 +{ 1.1878 + inline void closure (hb_closure_context_t *c) const 1.1879 + { 1.1880 + TRACE_CLOSURE (this); 1.1881 + if (!(this+coverage).intersects (c->glyphs)) 1.1882 + return; 1.1883 + 1.1884 + const ClassDef &backtrack_class_def = this+backtrackClassDef; 1.1885 + const ClassDef &input_class_def = this+inputClassDef; 1.1886 + const ClassDef &lookahead_class_def = this+lookaheadClassDef; 1.1887 + 1.1888 + struct ChainContextClosureLookupContext lookup_context = { 1.1889 + {intersects_class}, 1.1890 + {&backtrack_class_def, 1.1891 + &input_class_def, 1.1892 + &lookahead_class_def} 1.1893 + }; 1.1894 + 1.1895 + unsigned int count = ruleSet.len; 1.1896 + for (unsigned int i = 0; i < count; i++) 1.1897 + if (input_class_def.intersects_class (c->glyphs, i)) { 1.1898 + const ChainRuleSet &rule_set = this+ruleSet[i]; 1.1899 + rule_set.closure (c, lookup_context); 1.1900 + } 1.1901 + } 1.1902 + 1.1903 + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 1.1904 + { 1.1905 + TRACE_COLLECT_GLYPHS (this); 1.1906 + (this+coverage).add_coverage (c->input); 1.1907 + 1.1908 + const ClassDef &backtrack_class_def = this+backtrackClassDef; 1.1909 + const ClassDef &input_class_def = this+inputClassDef; 1.1910 + const ClassDef &lookahead_class_def = this+lookaheadClassDef; 1.1911 + 1.1912 + struct ChainContextCollectGlyphsLookupContext lookup_context = { 1.1913 + {collect_class}, 1.1914 + {&backtrack_class_def, 1.1915 + &input_class_def, 1.1916 + &lookahead_class_def} 1.1917 + }; 1.1918 + 1.1919 + unsigned int count = ruleSet.len; 1.1920 + for (unsigned int i = 0; i < count; i++) 1.1921 + (this+ruleSet[i]).collect_glyphs (c, lookup_context); 1.1922 + } 1.1923 + 1.1924 + inline bool would_apply (hb_would_apply_context_t *c) const 1.1925 + { 1.1926 + TRACE_WOULD_APPLY (this); 1.1927 + 1.1928 + const ClassDef &backtrack_class_def = this+backtrackClassDef; 1.1929 + const ClassDef &input_class_def = this+inputClassDef; 1.1930 + const ClassDef &lookahead_class_def = this+lookaheadClassDef; 1.1931 + 1.1932 + unsigned int index = input_class_def.get_class (c->glyphs[0]); 1.1933 + const ChainRuleSet &rule_set = this+ruleSet[index]; 1.1934 + struct ChainContextApplyLookupContext lookup_context = { 1.1935 + {match_class}, 1.1936 + {&backtrack_class_def, 1.1937 + &input_class_def, 1.1938 + &lookahead_class_def} 1.1939 + }; 1.1940 + return TRACE_RETURN (rule_set.would_apply (c, lookup_context)); 1.1941 + } 1.1942 + 1.1943 + inline const Coverage &get_coverage (void) const 1.1944 + { 1.1945 + return this+coverage; 1.1946 + } 1.1947 + 1.1948 + inline bool apply (hb_apply_context_t *c) const 1.1949 + { 1.1950 + TRACE_APPLY (this); 1.1951 + unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); 1.1952 + if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); 1.1953 + 1.1954 + const ClassDef &backtrack_class_def = this+backtrackClassDef; 1.1955 + const ClassDef &input_class_def = this+inputClassDef; 1.1956 + const ClassDef &lookahead_class_def = this+lookaheadClassDef; 1.1957 + 1.1958 + index = input_class_def.get_class (c->buffer->cur().codepoint); 1.1959 + const ChainRuleSet &rule_set = this+ruleSet[index]; 1.1960 + struct ChainContextApplyLookupContext lookup_context = { 1.1961 + {match_class}, 1.1962 + {&backtrack_class_def, 1.1963 + &input_class_def, 1.1964 + &lookahead_class_def} 1.1965 + }; 1.1966 + return TRACE_RETURN (rule_set.apply (c, lookup_context)); 1.1967 + } 1.1968 + 1.1969 + inline bool sanitize (hb_sanitize_context_t *c) { 1.1970 + TRACE_SANITIZE (this); 1.1971 + return TRACE_RETURN (coverage.sanitize (c, this) && backtrackClassDef.sanitize (c, this) && 1.1972 + inputClassDef.sanitize (c, this) && lookaheadClassDef.sanitize (c, this) && 1.1973 + ruleSet.sanitize (c, this)); 1.1974 + } 1.1975 + 1.1976 + protected: 1.1977 + USHORT format; /* Format identifier--format = 2 */ 1.1978 + OffsetTo<Coverage> 1.1979 + coverage; /* Offset to Coverage table--from 1.1980 + * beginning of table */ 1.1981 + OffsetTo<ClassDef> 1.1982 + backtrackClassDef; /* Offset to glyph ClassDef table 1.1983 + * containing backtrack sequence 1.1984 + * data--from beginning of table */ 1.1985 + OffsetTo<ClassDef> 1.1986 + inputClassDef; /* Offset to glyph ClassDef 1.1987 + * table containing input sequence 1.1988 + * data--from beginning of table */ 1.1989 + OffsetTo<ClassDef> 1.1990 + lookaheadClassDef; /* Offset to glyph ClassDef table 1.1991 + * containing lookahead sequence 1.1992 + * data--from beginning of table */ 1.1993 + OffsetArrayOf<ChainRuleSet> 1.1994 + ruleSet; /* Array of ChainRuleSet tables 1.1995 + * ordered by class */ 1.1996 + public: 1.1997 + DEFINE_SIZE_ARRAY (12, ruleSet); 1.1998 +}; 1.1999 + 1.2000 +struct ChainContextFormat3 1.2001 +{ 1.2002 + inline void closure (hb_closure_context_t *c) const 1.2003 + { 1.2004 + TRACE_CLOSURE (this); 1.2005 + const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 1.2006 + 1.2007 + if (!(this+input[0]).intersects (c->glyphs)) 1.2008 + return; 1.2009 + 1.2010 + const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); 1.2011 + const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1.2012 + struct ChainContextClosureLookupContext lookup_context = { 1.2013 + {intersects_coverage}, 1.2014 + {this, this, this} 1.2015 + }; 1.2016 + chain_context_closure_lookup (c, 1.2017 + backtrack.len, (const USHORT *) backtrack.array, 1.2018 + input.len, (const USHORT *) input.array + 1, 1.2019 + lookahead.len, (const USHORT *) lookahead.array, 1.2020 + lookup.len, lookup.array, 1.2021 + lookup_context); 1.2022 + } 1.2023 + 1.2024 + inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 1.2025 + { 1.2026 + TRACE_COLLECT_GLYPHS (this); 1.2027 + const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 1.2028 + 1.2029 + (this+input[0]).add_coverage (c->input); 1.2030 + 1.2031 + const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); 1.2032 + const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1.2033 + struct ChainContextCollectGlyphsLookupContext lookup_context = { 1.2034 + {collect_coverage}, 1.2035 + {this, this, this} 1.2036 + }; 1.2037 + chain_context_collect_glyphs_lookup (c, 1.2038 + backtrack.len, (const USHORT *) backtrack.array, 1.2039 + input.len, (const USHORT *) input.array + 1, 1.2040 + lookahead.len, (const USHORT *) lookahead.array, 1.2041 + lookup.len, lookup.array, 1.2042 + lookup_context); 1.2043 + } 1.2044 + 1.2045 + inline bool would_apply (hb_would_apply_context_t *c) const 1.2046 + { 1.2047 + TRACE_WOULD_APPLY (this); 1.2048 + 1.2049 + const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 1.2050 + const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); 1.2051 + const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1.2052 + struct ChainContextApplyLookupContext lookup_context = { 1.2053 + {match_coverage}, 1.2054 + {this, this, this} 1.2055 + }; 1.2056 + return TRACE_RETURN (chain_context_would_apply_lookup (c, 1.2057 + backtrack.len, (const USHORT *) backtrack.array, 1.2058 + input.len, (const USHORT *) input.array + 1, 1.2059 + lookahead.len, (const USHORT *) lookahead.array, 1.2060 + lookup.len, lookup.array, lookup_context)); 1.2061 + } 1.2062 + 1.2063 + inline const Coverage &get_coverage (void) const 1.2064 + { 1.2065 + const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 1.2066 + return this+input[0]; 1.2067 + } 1.2068 + 1.2069 + inline bool apply (hb_apply_context_t *c) const 1.2070 + { 1.2071 + TRACE_APPLY (this); 1.2072 + const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 1.2073 + 1.2074 + unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint); 1.2075 + if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); 1.2076 + 1.2077 + const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); 1.2078 + const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1.2079 + struct ChainContextApplyLookupContext lookup_context = { 1.2080 + {match_coverage}, 1.2081 + {this, this, this} 1.2082 + }; 1.2083 + return TRACE_RETURN (chain_context_apply_lookup (c, 1.2084 + backtrack.len, (const USHORT *) backtrack.array, 1.2085 + input.len, (const USHORT *) input.array + 1, 1.2086 + lookahead.len, (const USHORT *) lookahead.array, 1.2087 + lookup.len, lookup.array, lookup_context)); 1.2088 + } 1.2089 + 1.2090 + inline bool sanitize (hb_sanitize_context_t *c) { 1.2091 + TRACE_SANITIZE (this); 1.2092 + if (!backtrack.sanitize (c, this)) return TRACE_RETURN (false); 1.2093 + OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 1.2094 + if (!input.sanitize (c, this)) return TRACE_RETURN (false); 1.2095 + OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); 1.2096 + if (!lookahead.sanitize (c, this)) return TRACE_RETURN (false); 1.2097 + ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); 1.2098 + return TRACE_RETURN (lookup.sanitize (c)); 1.2099 + } 1.2100 + 1.2101 + protected: 1.2102 + USHORT format; /* Format identifier--format = 3 */ 1.2103 + OffsetArrayOf<Coverage> 1.2104 + backtrack; /* Array of coverage tables 1.2105 + * in backtracking sequence, in glyph 1.2106 + * sequence order */ 1.2107 + OffsetArrayOf<Coverage> 1.2108 + inputX ; /* Array of coverage 1.2109 + * tables in input sequence, in glyph 1.2110 + * sequence order */ 1.2111 + OffsetArrayOf<Coverage> 1.2112 + lookaheadX; /* Array of coverage tables 1.2113 + * in lookahead sequence, in glyph 1.2114 + * sequence order */ 1.2115 + ArrayOf<LookupRecord> 1.2116 + lookupX; /* Array of LookupRecords--in 1.2117 + * design order) */ 1.2118 + public: 1.2119 + DEFINE_SIZE_MIN (10); 1.2120 +}; 1.2121 + 1.2122 +struct ChainContext 1.2123 +{ 1.2124 + template <typename context_t> 1.2125 + inline typename context_t::return_t dispatch (context_t *c) const 1.2126 + { 1.2127 + TRACE_DISPATCH (this); 1.2128 + switch (u.format) { 1.2129 + case 1: return TRACE_RETURN (c->dispatch (u.format1)); 1.2130 + case 2: return TRACE_RETURN (c->dispatch (u.format2)); 1.2131 + case 3: return TRACE_RETURN (c->dispatch (u.format3)); 1.2132 + default:return TRACE_RETURN (c->default_return_value ()); 1.2133 + } 1.2134 + } 1.2135 + 1.2136 + inline bool sanitize (hb_sanitize_context_t *c) { 1.2137 + TRACE_SANITIZE (this); 1.2138 + if (!u.format.sanitize (c)) return TRACE_RETURN (false); 1.2139 + switch (u.format) { 1.2140 + case 1: return TRACE_RETURN (u.format1.sanitize (c)); 1.2141 + case 2: return TRACE_RETURN (u.format2.sanitize (c)); 1.2142 + case 3: return TRACE_RETURN (u.format3.sanitize (c)); 1.2143 + default:return TRACE_RETURN (true); 1.2144 + } 1.2145 + } 1.2146 + 1.2147 + protected: 1.2148 + union { 1.2149 + USHORT format; /* Format identifier */ 1.2150 + ChainContextFormat1 format1; 1.2151 + ChainContextFormat2 format2; 1.2152 + ChainContextFormat3 format3; 1.2153 + } u; 1.2154 +}; 1.2155 + 1.2156 + 1.2157 +struct ExtensionFormat1 1.2158 +{ 1.2159 + inline unsigned int get_type (void) const { return extensionLookupType; } 1.2160 + inline unsigned int get_offset (void) const { return extensionOffset; } 1.2161 + 1.2162 + inline bool sanitize (hb_sanitize_context_t *c) { 1.2163 + TRACE_SANITIZE (this); 1.2164 + return TRACE_RETURN (c->check_struct (this)); 1.2165 + } 1.2166 + 1.2167 + protected: 1.2168 + USHORT format; /* Format identifier. Set to 1. */ 1.2169 + USHORT extensionLookupType; /* Lookup type of subtable referenced 1.2170 + * by ExtensionOffset (i.e. the 1.2171 + * extension subtable). */ 1.2172 + ULONG extensionOffset; /* Offset to the extension subtable, 1.2173 + * of lookup type subtable. */ 1.2174 + public: 1.2175 + DEFINE_SIZE_STATIC (8); 1.2176 +}; 1.2177 + 1.2178 +template <typename T> 1.2179 +struct Extension 1.2180 +{ 1.2181 + inline unsigned int get_type (void) const 1.2182 + { 1.2183 + switch (u.format) { 1.2184 + case 1: return u.format1.get_type (); 1.2185 + default:return 0; 1.2186 + } 1.2187 + } 1.2188 + inline unsigned int get_offset (void) const 1.2189 + { 1.2190 + switch (u.format) { 1.2191 + case 1: return u.format1.get_offset (); 1.2192 + default:return 0; 1.2193 + } 1.2194 + } 1.2195 + 1.2196 + template <typename X> 1.2197 + inline const X& get_subtable (void) const 1.2198 + { 1.2199 + unsigned int offset = get_offset (); 1.2200 + if (unlikely (!offset)) return Null(typename T::LookupSubTable); 1.2201 + return StructAtOffset<typename T::LookupSubTable> (this, offset); 1.2202 + } 1.2203 + 1.2204 + template <typename context_t> 1.2205 + inline typename context_t::return_t dispatch (context_t *c) const 1.2206 + { 1.2207 + return get_subtable<typename T::LookupSubTable> ().dispatch (c, get_type ()); 1.2208 + } 1.2209 + 1.2210 + inline bool sanitize_self (hb_sanitize_context_t *c) { 1.2211 + TRACE_SANITIZE (this); 1.2212 + if (!u.format.sanitize (c)) return TRACE_RETURN (false); 1.2213 + switch (u.format) { 1.2214 + case 1: return TRACE_RETURN (u.format1.sanitize (c)); 1.2215 + default:return TRACE_RETURN (true); 1.2216 + } 1.2217 + } 1.2218 + 1.2219 + inline bool sanitize (hb_sanitize_context_t *c) { 1.2220 + TRACE_SANITIZE (this); 1.2221 + if (!sanitize_self (c)) return TRACE_RETURN (false); 1.2222 + unsigned int offset = get_offset (); 1.2223 + if (unlikely (!offset)) return TRACE_RETURN (true); 1.2224 + return TRACE_RETURN (StructAtOffset<typename T::LookupSubTable> (this, offset).sanitize (c, get_type ())); 1.2225 + } 1.2226 + 1.2227 + protected: 1.2228 + union { 1.2229 + USHORT format; /* Format identifier */ 1.2230 + ExtensionFormat1 format1; 1.2231 + } u; 1.2232 +}; 1.2233 + 1.2234 + 1.2235 +/* 1.2236 + * GSUB/GPOS Common 1.2237 + */ 1.2238 + 1.2239 +struct GSUBGPOS 1.2240 +{ 1.2241 + static const hb_tag_t GSUBTag = HB_OT_TAG_GSUB; 1.2242 + static const hb_tag_t GPOSTag = HB_OT_TAG_GPOS; 1.2243 + 1.2244 + inline unsigned int get_script_count (void) const 1.2245 + { return (this+scriptList).len; } 1.2246 + inline const Tag& get_script_tag (unsigned int i) const 1.2247 + { return (this+scriptList).get_tag (i); } 1.2248 + inline unsigned int get_script_tags (unsigned int start_offset, 1.2249 + unsigned int *script_count /* IN/OUT */, 1.2250 + hb_tag_t *script_tags /* OUT */) const 1.2251 + { return (this+scriptList).get_tags (start_offset, script_count, script_tags); } 1.2252 + inline const Script& get_script (unsigned int i) const 1.2253 + { return (this+scriptList)[i]; } 1.2254 + inline bool find_script_index (hb_tag_t tag, unsigned int *index) const 1.2255 + { return (this+scriptList).find_index (tag, index); } 1.2256 + 1.2257 + inline unsigned int get_feature_count (void) const 1.2258 + { return (this+featureList).len; } 1.2259 + inline const Tag& get_feature_tag (unsigned int i) const 1.2260 + { return (this+featureList).get_tag (i); } 1.2261 + inline unsigned int get_feature_tags (unsigned int start_offset, 1.2262 + unsigned int *feature_count /* IN/OUT */, 1.2263 + hb_tag_t *feature_tags /* OUT */) const 1.2264 + { return (this+featureList).get_tags (start_offset, feature_count, feature_tags); } 1.2265 + inline const Feature& get_feature (unsigned int i) const 1.2266 + { return (this+featureList)[i]; } 1.2267 + inline bool find_feature_index (hb_tag_t tag, unsigned int *index) const 1.2268 + { return (this+featureList).find_index (tag, index); } 1.2269 + 1.2270 + inline unsigned int get_lookup_count (void) const 1.2271 + { return (this+lookupList).len; } 1.2272 + inline const Lookup& get_lookup (unsigned int i) const 1.2273 + { return (this+lookupList)[i]; } 1.2274 + 1.2275 + inline bool sanitize (hb_sanitize_context_t *c) { 1.2276 + TRACE_SANITIZE (this); 1.2277 + return TRACE_RETURN (version.sanitize (c) && likely (version.major == 1) && 1.2278 + scriptList.sanitize (c, this) && 1.2279 + featureList.sanitize (c, this) && 1.2280 + lookupList.sanitize (c, this)); 1.2281 + } 1.2282 + 1.2283 + protected: 1.2284 + FixedVersion version; /* Version of the GSUB/GPOS table--initially set 1.2285 + * to 0x00010000 */ 1.2286 + OffsetTo<ScriptList> 1.2287 + scriptList; /* ScriptList table */ 1.2288 + OffsetTo<FeatureList> 1.2289 + featureList; /* FeatureList table */ 1.2290 + OffsetTo<LookupList> 1.2291 + lookupList; /* LookupList table */ 1.2292 + public: 1.2293 + DEFINE_SIZE_STATIC (10); 1.2294 +}; 1.2295 + 1.2296 + 1.2297 +} /* namespace OT */ 1.2298 + 1.2299 + 1.2300 +#endif /* HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH */