|
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_PRIVATE_HH |
|
30 #define HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH |
|
31 |
|
32 #include "hb-buffer-private.hh" |
|
33 #include "hb-ot-layout-gdef-table.hh" |
|
34 #include "hb-set-private.hh" |
|
35 |
|
36 |
|
37 namespace OT { |
|
38 |
|
39 |
|
40 |
|
41 #define TRACE_DISPATCH(this) \ |
|
42 hb_auto_trace_t<context_t::max_debug_depth, typename context_t::return_t> trace \ |
|
43 (&c->debug_depth, c->get_name (), this, HB_FUNC, \ |
|
44 ""); |
|
45 |
|
46 #ifndef HB_DEBUG_CLOSURE |
|
47 #define HB_DEBUG_CLOSURE (HB_DEBUG+0) |
|
48 #endif |
|
49 |
|
50 #define TRACE_CLOSURE(this) \ |
|
51 hb_auto_trace_t<HB_DEBUG_CLOSURE, hb_void_t> trace \ |
|
52 (&c->debug_depth, c->get_name (), this, HB_FUNC, \ |
|
53 ""); |
|
54 |
|
55 struct hb_closure_context_t |
|
56 { |
|
57 inline const char *get_name (void) { return "CLOSURE"; } |
|
58 static const unsigned int max_debug_depth = HB_DEBUG_CLOSURE; |
|
59 typedef hb_void_t return_t; |
|
60 typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index); |
|
61 template <typename T> |
|
62 inline return_t dispatch (const T &obj) { obj.closure (this); return HB_VOID; } |
|
63 static return_t default_return_value (void) { return HB_VOID; } |
|
64 bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; } |
|
65 return_t recurse (unsigned int lookup_index) |
|
66 { |
|
67 if (unlikely (nesting_level_left == 0 || !recurse_func)) |
|
68 return default_return_value (); |
|
69 |
|
70 nesting_level_left--; |
|
71 recurse_func (this, lookup_index); |
|
72 nesting_level_left++; |
|
73 return HB_VOID; |
|
74 } |
|
75 |
|
76 hb_face_t *face; |
|
77 hb_set_t *glyphs; |
|
78 recurse_func_t recurse_func; |
|
79 unsigned int nesting_level_left; |
|
80 unsigned int debug_depth; |
|
81 |
|
82 hb_closure_context_t (hb_face_t *face_, |
|
83 hb_set_t *glyphs_, |
|
84 unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) : |
|
85 face (face_), |
|
86 glyphs (glyphs_), |
|
87 recurse_func (NULL), |
|
88 nesting_level_left (nesting_level_left_), |
|
89 debug_depth (0) {} |
|
90 |
|
91 void set_recurse_func (recurse_func_t func) { recurse_func = func; } |
|
92 }; |
|
93 |
|
94 |
|
95 |
|
96 #ifndef HB_DEBUG_WOULD_APPLY |
|
97 #define HB_DEBUG_WOULD_APPLY (HB_DEBUG+0) |
|
98 #endif |
|
99 |
|
100 #define TRACE_WOULD_APPLY(this) \ |
|
101 hb_auto_trace_t<HB_DEBUG_WOULD_APPLY, bool> trace \ |
|
102 (&c->debug_depth, c->get_name (), this, HB_FUNC, \ |
|
103 "%d glyphs", c->len); |
|
104 |
|
105 struct hb_would_apply_context_t |
|
106 { |
|
107 inline const char *get_name (void) { return "WOULD_APPLY"; } |
|
108 static const unsigned int max_debug_depth = HB_DEBUG_WOULD_APPLY; |
|
109 typedef bool return_t; |
|
110 template <typename T> |
|
111 inline return_t dispatch (const T &obj) { return obj.would_apply (this); } |
|
112 static return_t default_return_value (void) { return false; } |
|
113 bool stop_sublookup_iteration (return_t r) const { return r; } |
|
114 |
|
115 hb_face_t *face; |
|
116 const hb_codepoint_t *glyphs; |
|
117 unsigned int len; |
|
118 bool zero_context; |
|
119 unsigned int debug_depth; |
|
120 |
|
121 hb_would_apply_context_t (hb_face_t *face_, |
|
122 const hb_codepoint_t *glyphs_, |
|
123 unsigned int len_, |
|
124 bool zero_context_) : |
|
125 face (face_), |
|
126 glyphs (glyphs_), |
|
127 len (len_), |
|
128 zero_context (zero_context_), |
|
129 debug_depth (0) {} |
|
130 }; |
|
131 |
|
132 |
|
133 |
|
134 #ifndef HB_DEBUG_COLLECT_GLYPHS |
|
135 #define HB_DEBUG_COLLECT_GLYPHS (HB_DEBUG+0) |
|
136 #endif |
|
137 |
|
138 #define TRACE_COLLECT_GLYPHS(this) \ |
|
139 hb_auto_trace_t<HB_DEBUG_COLLECT_GLYPHS, hb_void_t> trace \ |
|
140 (&c->debug_depth, c->get_name (), this, HB_FUNC, \ |
|
141 ""); |
|
142 |
|
143 struct hb_collect_glyphs_context_t |
|
144 { |
|
145 inline const char *get_name (void) { return "COLLECT_GLYPHS"; } |
|
146 static const unsigned int max_debug_depth = HB_DEBUG_COLLECT_GLYPHS; |
|
147 typedef hb_void_t return_t; |
|
148 typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index); |
|
149 template <typename T> |
|
150 inline return_t dispatch (const T &obj) { obj.collect_glyphs (this); return HB_VOID; } |
|
151 static return_t default_return_value (void) { return HB_VOID; } |
|
152 bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return false; } |
|
153 return_t recurse (unsigned int lookup_index) |
|
154 { |
|
155 if (unlikely (nesting_level_left == 0 || !recurse_func)) |
|
156 return default_return_value (); |
|
157 |
|
158 /* Note that GPOS sets recurse_func to NULL already, so it doesn't get |
|
159 * past the previous check. For GSUB, we only want to collect the output |
|
160 * glyphs in the recursion. If output is not requested, we can go home now. |
|
161 * |
|
162 * Note further, that the above is not exactly correct. A recursed lookup |
|
163 * is allowed to match input that is not matched in the context, but that's |
|
164 * not how most fonts are built. It's possible to relax that and recurse |
|
165 * with all sets here if it proves to be an issue. |
|
166 */ |
|
167 |
|
168 if (output == hb_set_get_empty ()) |
|
169 return HB_VOID; |
|
170 |
|
171 hb_set_t *old_before = before; |
|
172 hb_set_t *old_input = input; |
|
173 hb_set_t *old_after = after; |
|
174 before = input = after = hb_set_get_empty (); |
|
175 |
|
176 nesting_level_left--; |
|
177 recurse_func (this, lookup_index); |
|
178 nesting_level_left++; |
|
179 |
|
180 before = old_before; |
|
181 input = old_input; |
|
182 after = old_after; |
|
183 |
|
184 return HB_VOID; |
|
185 } |
|
186 |
|
187 hb_face_t *face; |
|
188 hb_set_t *before; |
|
189 hb_set_t *input; |
|
190 hb_set_t *after; |
|
191 hb_set_t *output; |
|
192 recurse_func_t recurse_func; |
|
193 unsigned int nesting_level_left; |
|
194 unsigned int debug_depth; |
|
195 |
|
196 hb_collect_glyphs_context_t (hb_face_t *face_, |
|
197 hb_set_t *glyphs_before, /* OUT. May be NULL */ |
|
198 hb_set_t *glyphs_input, /* OUT. May be NULL */ |
|
199 hb_set_t *glyphs_after, /* OUT. May be NULL */ |
|
200 hb_set_t *glyphs_output, /* OUT. May be NULL */ |
|
201 unsigned int nesting_level_left_ = MAX_NESTING_LEVEL) : |
|
202 face (face_), |
|
203 before (glyphs_before ? glyphs_before : hb_set_get_empty ()), |
|
204 input (glyphs_input ? glyphs_input : hb_set_get_empty ()), |
|
205 after (glyphs_after ? glyphs_after : hb_set_get_empty ()), |
|
206 output (glyphs_output ? glyphs_output : hb_set_get_empty ()), |
|
207 recurse_func (NULL), |
|
208 nesting_level_left (nesting_level_left_), |
|
209 debug_depth (0) {} |
|
210 |
|
211 void set_recurse_func (recurse_func_t func) { recurse_func = func; } |
|
212 }; |
|
213 |
|
214 |
|
215 |
|
216 struct hb_get_coverage_context_t |
|
217 { |
|
218 inline const char *get_name (void) { return "GET_COVERAGE"; } |
|
219 static const unsigned int max_debug_depth = 0; |
|
220 typedef const Coverage &return_t; |
|
221 template <typename T> |
|
222 inline return_t dispatch (const T &obj) { return obj.get_coverage (); } |
|
223 static return_t default_return_value (void) { return Null(Coverage); } |
|
224 |
|
225 hb_get_coverage_context_t (void) : |
|
226 debug_depth (0) {} |
|
227 |
|
228 unsigned int debug_depth; |
|
229 }; |
|
230 |
|
231 |
|
232 |
|
233 #ifndef HB_DEBUG_APPLY |
|
234 #define HB_DEBUG_APPLY (HB_DEBUG+0) |
|
235 #endif |
|
236 |
|
237 #define TRACE_APPLY(this) \ |
|
238 hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace \ |
|
239 (&c->debug_depth, c->get_name (), this, HB_FUNC, \ |
|
240 "idx %d codepoint %u", c->buffer->idx, c->buffer->cur().codepoint); |
|
241 |
|
242 struct hb_apply_context_t |
|
243 { |
|
244 inline const char *get_name (void) { return "APPLY"; } |
|
245 static const unsigned int max_debug_depth = HB_DEBUG_APPLY; |
|
246 typedef bool return_t; |
|
247 typedef return_t (*recurse_func_t) (hb_apply_context_t *c, unsigned int lookup_index); |
|
248 template <typename T> |
|
249 inline return_t dispatch (const T &obj) { return obj.apply (this); } |
|
250 static return_t default_return_value (void) { return false; } |
|
251 bool stop_sublookup_iteration (return_t r) const { return r; } |
|
252 return_t recurse (unsigned int lookup_index) |
|
253 { |
|
254 if (unlikely (nesting_level_left == 0 || !recurse_func)) |
|
255 return default_return_value (); |
|
256 |
|
257 nesting_level_left--; |
|
258 bool ret = recurse_func (this, lookup_index); |
|
259 nesting_level_left++; |
|
260 return ret; |
|
261 } |
|
262 |
|
263 unsigned int table_index; /* GSUB/GPOS */ |
|
264 hb_font_t *font; |
|
265 hb_face_t *face; |
|
266 hb_buffer_t *buffer; |
|
267 hb_direction_t direction; |
|
268 hb_mask_t lookup_mask; |
|
269 bool auto_zwj; |
|
270 recurse_func_t recurse_func; |
|
271 unsigned int nesting_level_left; |
|
272 unsigned int lookup_props; |
|
273 const GDEF &gdef; |
|
274 bool has_glyph_classes; |
|
275 unsigned int debug_depth; |
|
276 |
|
277 |
|
278 hb_apply_context_t (unsigned int table_index_, |
|
279 hb_font_t *font_, |
|
280 hb_buffer_t *buffer_) : |
|
281 table_index (table_index_), |
|
282 font (font_), face (font->face), buffer (buffer_), |
|
283 direction (buffer_->props.direction), |
|
284 lookup_mask (1), |
|
285 auto_zwj (true), |
|
286 recurse_func (NULL), |
|
287 nesting_level_left (MAX_NESTING_LEVEL), |
|
288 lookup_props (0), |
|
289 gdef (*hb_ot_layout_from_face (face)->gdef), |
|
290 has_glyph_classes (gdef.has_glyph_classes ()), |
|
291 debug_depth (0) {} |
|
292 |
|
293 inline void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; } |
|
294 inline void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; } |
|
295 inline void set_recurse_func (recurse_func_t func) { recurse_func = func; } |
|
296 inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; } |
|
297 inline void set_lookup (const Lookup &l) { lookup_props = l.get_props (); } |
|
298 |
|
299 struct matcher_t |
|
300 { |
|
301 inline matcher_t (void) : |
|
302 lookup_props (0), |
|
303 ignore_zwnj (false), |
|
304 ignore_zwj (false), |
|
305 mask (-1), |
|
306 #define arg1(arg) (arg) /* Remove the macro to see why it's needed! */ |
|
307 syllable arg1(0), |
|
308 #undef arg1 |
|
309 match_func (NULL), |
|
310 match_data (NULL) {}; |
|
311 |
|
312 typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data); |
|
313 |
|
314 inline void set_ignore_zwnj (bool ignore_zwnj_) { ignore_zwnj = ignore_zwnj_; } |
|
315 inline void set_ignore_zwj (bool ignore_zwj_) { ignore_zwj = ignore_zwj_; } |
|
316 inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; } |
|
317 inline void set_mask (hb_mask_t mask_) { mask = mask_; } |
|
318 inline void set_syllable (uint8_t syllable_) { syllable = syllable_; } |
|
319 inline void set_match_func (match_func_t match_func_, |
|
320 const void *match_data_) |
|
321 { match_func = match_func_; match_data = match_data_; } |
|
322 |
|
323 enum may_match_t { |
|
324 MATCH_NO, |
|
325 MATCH_YES, |
|
326 MATCH_MAYBE |
|
327 }; |
|
328 |
|
329 inline may_match_t may_match (const hb_glyph_info_t &info, |
|
330 const USHORT *glyph_data) const |
|
331 { |
|
332 if (!(info.mask & mask) || |
|
333 (syllable && syllable != info.syllable ())) |
|
334 return MATCH_NO; |
|
335 |
|
336 if (match_func) |
|
337 return match_func (info.codepoint, *glyph_data, match_data) ? MATCH_YES : MATCH_NO; |
|
338 |
|
339 return MATCH_MAYBE; |
|
340 } |
|
341 |
|
342 enum may_skip_t { |
|
343 SKIP_NO, |
|
344 SKIP_YES, |
|
345 SKIP_MAYBE |
|
346 }; |
|
347 |
|
348 inline may_skip_t |
|
349 may_skip (const hb_apply_context_t *c, |
|
350 const hb_glyph_info_t &info) const |
|
351 { |
|
352 unsigned int property; |
|
353 |
|
354 property = _hb_glyph_info_get_glyph_props (&info); |
|
355 |
|
356 if (!c->match_properties (info.codepoint, property, lookup_props)) |
|
357 return SKIP_YES; |
|
358 |
|
359 if (unlikely (_hb_glyph_info_is_default_ignorable (&info) && |
|
360 (ignore_zwnj || !_hb_glyph_info_is_zwnj (&info)) && |
|
361 (ignore_zwj || !_hb_glyph_info_is_zwj (&info)) && |
|
362 !_hb_glyph_info_ligated (&info))) |
|
363 return SKIP_MAYBE; |
|
364 |
|
365 return SKIP_NO; |
|
366 } |
|
367 |
|
368 protected: |
|
369 unsigned int lookup_props; |
|
370 bool ignore_zwnj; |
|
371 bool ignore_zwj; |
|
372 hb_mask_t mask; |
|
373 uint8_t syllable; |
|
374 match_func_t match_func; |
|
375 const void *match_data; |
|
376 }; |
|
377 |
|
378 struct skipping_forward_iterator_t |
|
379 { |
|
380 inline skipping_forward_iterator_t (hb_apply_context_t *c_, |
|
381 unsigned int start_index_, |
|
382 unsigned int num_items_, |
|
383 bool context_match = false) : |
|
384 idx (start_index_), |
|
385 c (c_), |
|
386 match_glyph_data (NULL), |
|
387 num_items (num_items_), |
|
388 end (c->buffer->len) |
|
389 { |
|
390 matcher.set_lookup_props (c->lookup_props); |
|
391 /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */ |
|
392 matcher.set_ignore_zwnj (context_match || c->table_index == 1); |
|
393 /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */ |
|
394 matcher.set_ignore_zwj (context_match || c->table_index == 1 || c->auto_zwj); |
|
395 if (!context_match) |
|
396 matcher.set_mask (c->lookup_mask); |
|
397 matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0); |
|
398 } |
|
399 inline void set_lookup_props (unsigned int lookup_props) { matcher.set_lookup_props (lookup_props); } |
|
400 inline void set_syllable (unsigned int syllable) { matcher.set_syllable (syllable); } |
|
401 inline void set_match_func (matcher_t::match_func_t match_func, |
|
402 const void *match_data, |
|
403 const USHORT glyph_data[]) |
|
404 { |
|
405 matcher.set_match_func (match_func, match_data); |
|
406 match_glyph_data = glyph_data; |
|
407 } |
|
408 |
|
409 inline bool has_no_chance (void) const { return unlikely (num_items && idx + num_items >= end); } |
|
410 inline void reject (void) { num_items++; match_glyph_data--; } |
|
411 inline bool next (void) |
|
412 { |
|
413 assert (num_items > 0); |
|
414 while (!has_no_chance ()) |
|
415 { |
|
416 idx++; |
|
417 const hb_glyph_info_t &info = c->buffer->info[idx]; |
|
418 |
|
419 matcher_t::may_skip_t skip = matcher.may_skip (c, info); |
|
420 if (unlikely (skip == matcher_t::SKIP_YES)) |
|
421 continue; |
|
422 |
|
423 matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data); |
|
424 if (match == matcher_t::MATCH_YES || |
|
425 (match == matcher_t::MATCH_MAYBE && |
|
426 skip == matcher_t::SKIP_NO)) |
|
427 { |
|
428 num_items--; |
|
429 match_glyph_data++; |
|
430 return true; |
|
431 } |
|
432 |
|
433 if (skip == matcher_t::SKIP_NO) |
|
434 return false; |
|
435 } |
|
436 return false; |
|
437 } |
|
438 |
|
439 unsigned int idx; |
|
440 protected: |
|
441 hb_apply_context_t *c; |
|
442 matcher_t matcher; |
|
443 const USHORT *match_glyph_data; |
|
444 |
|
445 unsigned int num_items; |
|
446 unsigned int end; |
|
447 }; |
|
448 |
|
449 struct skipping_backward_iterator_t |
|
450 { |
|
451 inline skipping_backward_iterator_t (hb_apply_context_t *c_, |
|
452 unsigned int start_index_, |
|
453 unsigned int num_items_, |
|
454 bool context_match = false) : |
|
455 idx (start_index_), |
|
456 c (c_), |
|
457 match_glyph_data (NULL), |
|
458 num_items (num_items_) |
|
459 { |
|
460 matcher.set_lookup_props (c->lookup_props); |
|
461 /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */ |
|
462 matcher.set_ignore_zwnj (context_match || c->table_index == 1); |
|
463 /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */ |
|
464 matcher.set_ignore_zwj (context_match || c->table_index == 1 || c->auto_zwj); |
|
465 if (!context_match) |
|
466 matcher.set_mask (c->lookup_mask); |
|
467 matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0); |
|
468 } |
|
469 inline void set_lookup_props (unsigned int lookup_props) { matcher.set_lookup_props (lookup_props); } |
|
470 inline void set_syllable (unsigned int syllable) { matcher.set_syllable (syllable); } |
|
471 inline void set_match_func (matcher_t::match_func_t match_func, |
|
472 const void *match_data, |
|
473 const USHORT glyph_data[]) |
|
474 { |
|
475 matcher.set_match_func (match_func, match_data); |
|
476 match_glyph_data = glyph_data; |
|
477 } |
|
478 |
|
479 inline bool has_no_chance (void) const { return unlikely (idx < num_items); } |
|
480 inline void reject (void) { num_items++; } |
|
481 inline bool prev (void) |
|
482 { |
|
483 assert (num_items > 0); |
|
484 while (!has_no_chance ()) |
|
485 { |
|
486 idx--; |
|
487 const hb_glyph_info_t &info = c->buffer->out_info[idx]; |
|
488 |
|
489 matcher_t::may_skip_t skip = matcher.may_skip (c, info); |
|
490 |
|
491 if (unlikely (skip == matcher_t::SKIP_YES)) |
|
492 continue; |
|
493 |
|
494 matcher_t::may_match_t match = matcher.may_match (info, match_glyph_data); |
|
495 if (match == matcher_t::MATCH_YES || |
|
496 (match == matcher_t::MATCH_MAYBE && |
|
497 skip == matcher_t::SKIP_NO)) |
|
498 { |
|
499 num_items--; |
|
500 match_glyph_data++; |
|
501 return true; |
|
502 } |
|
503 |
|
504 if (skip == matcher_t::SKIP_NO) |
|
505 return false; |
|
506 } |
|
507 return false; |
|
508 } |
|
509 |
|
510 unsigned int idx; |
|
511 protected: |
|
512 hb_apply_context_t *c; |
|
513 matcher_t matcher; |
|
514 const USHORT *match_glyph_data; |
|
515 |
|
516 unsigned int num_items; |
|
517 }; |
|
518 |
|
519 inline bool |
|
520 match_properties_mark (hb_codepoint_t glyph, |
|
521 unsigned int glyph_props, |
|
522 unsigned int lookup_props) const |
|
523 { |
|
524 /* If using mark filtering sets, the high short of |
|
525 * lookup_props has the set index. |
|
526 */ |
|
527 if (lookup_props & LookupFlag::UseMarkFilteringSet) |
|
528 return gdef.mark_set_covers (lookup_props >> 16, glyph); |
|
529 |
|
530 /* The second byte of lookup_props has the meaning |
|
531 * "ignore marks of attachment type different than |
|
532 * the attachment type specified." |
|
533 */ |
|
534 if (lookup_props & LookupFlag::MarkAttachmentType) |
|
535 return (lookup_props & LookupFlag::MarkAttachmentType) == (glyph_props & LookupFlag::MarkAttachmentType); |
|
536 |
|
537 return true; |
|
538 } |
|
539 |
|
540 inline bool |
|
541 match_properties (hb_codepoint_t glyph, |
|
542 unsigned int glyph_props, |
|
543 unsigned int lookup_props) const |
|
544 { |
|
545 /* Not covered, if, for example, glyph class is ligature and |
|
546 * lookup_props includes LookupFlags::IgnoreLigatures |
|
547 */ |
|
548 if (glyph_props & lookup_props & LookupFlag::IgnoreFlags) |
|
549 return false; |
|
550 |
|
551 if (unlikely (glyph_props & HB_OT_LAYOUT_GLYPH_PROPS_MARK)) |
|
552 return match_properties_mark (glyph, glyph_props, lookup_props); |
|
553 |
|
554 return true; |
|
555 } |
|
556 |
|
557 inline bool |
|
558 check_glyph_property (hb_glyph_info_t *info, |
|
559 unsigned int lookup_props) const |
|
560 { |
|
561 unsigned int property; |
|
562 |
|
563 property = _hb_glyph_info_get_glyph_props (info); |
|
564 |
|
565 return match_properties (info->codepoint, property, lookup_props); |
|
566 } |
|
567 |
|
568 inline void _set_glyph_props (hb_codepoint_t glyph_index, |
|
569 unsigned int class_guess = 0, |
|
570 bool ligature = false) const |
|
571 { |
|
572 unsigned int add_in = _hb_glyph_info_get_glyph_props (&buffer->cur()) & |
|
573 HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE; |
|
574 add_in |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED; |
|
575 if (ligature) |
|
576 add_in |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED; |
|
577 if (likely (has_glyph_classes)) |
|
578 _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | gdef.get_glyph_props (glyph_index)); |
|
579 else if (class_guess) |
|
580 _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | class_guess); |
|
581 } |
|
582 |
|
583 inline void replace_glyph (hb_codepoint_t glyph_index) const |
|
584 { |
|
585 _set_glyph_props (glyph_index); |
|
586 buffer->replace_glyph (glyph_index); |
|
587 } |
|
588 inline void replace_glyph_inplace (hb_codepoint_t glyph_index) const |
|
589 { |
|
590 _set_glyph_props (glyph_index); |
|
591 buffer->cur().codepoint = glyph_index; |
|
592 } |
|
593 inline void replace_glyph_with_ligature (hb_codepoint_t glyph_index, |
|
594 unsigned int class_guess) const |
|
595 { |
|
596 _set_glyph_props (glyph_index, class_guess, true); |
|
597 buffer->replace_glyph (glyph_index); |
|
598 } |
|
599 inline void output_glyph (hb_codepoint_t glyph_index, |
|
600 unsigned int class_guess) const |
|
601 { |
|
602 _set_glyph_props (glyph_index, class_guess); |
|
603 buffer->output_glyph (glyph_index); |
|
604 } |
|
605 }; |
|
606 |
|
607 |
|
608 |
|
609 typedef bool (*intersects_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data); |
|
610 typedef void (*collect_glyphs_func_t) (hb_set_t *glyphs, const USHORT &value, const void *data); |
|
611 typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, const void *data); |
|
612 |
|
613 struct ContextClosureFuncs |
|
614 { |
|
615 intersects_func_t intersects; |
|
616 }; |
|
617 struct ContextCollectGlyphsFuncs |
|
618 { |
|
619 collect_glyphs_func_t collect; |
|
620 }; |
|
621 struct ContextApplyFuncs |
|
622 { |
|
623 match_func_t match; |
|
624 }; |
|
625 |
|
626 |
|
627 static inline bool intersects_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED) |
|
628 { |
|
629 return glyphs->has (value); |
|
630 } |
|
631 static inline bool intersects_class (hb_set_t *glyphs, const USHORT &value, const void *data) |
|
632 { |
|
633 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data); |
|
634 return class_def.intersects_class (glyphs, value); |
|
635 } |
|
636 static inline bool intersects_coverage (hb_set_t *glyphs, const USHORT &value, const void *data) |
|
637 { |
|
638 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value; |
|
639 return (data+coverage).intersects (glyphs); |
|
640 } |
|
641 |
|
642 static inline bool intersects_array (hb_closure_context_t *c, |
|
643 unsigned int count, |
|
644 const USHORT values[], |
|
645 intersects_func_t intersects_func, |
|
646 const void *intersects_data) |
|
647 { |
|
648 for (unsigned int i = 0; i < count; i++) |
|
649 if (likely (!intersects_func (c->glyphs, values[i], intersects_data))) |
|
650 return false; |
|
651 return true; |
|
652 } |
|
653 |
|
654 |
|
655 static inline void collect_glyph (hb_set_t *glyphs, const USHORT &value, const void *data HB_UNUSED) |
|
656 { |
|
657 glyphs->add (value); |
|
658 } |
|
659 static inline void collect_class (hb_set_t *glyphs, const USHORT &value, const void *data) |
|
660 { |
|
661 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data); |
|
662 class_def.add_class (glyphs, value); |
|
663 } |
|
664 static inline void collect_coverage (hb_set_t *glyphs, const USHORT &value, const void *data) |
|
665 { |
|
666 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value; |
|
667 (data+coverage).add_coverage (glyphs); |
|
668 } |
|
669 static inline void collect_array (hb_collect_glyphs_context_t *c HB_UNUSED, |
|
670 hb_set_t *glyphs, |
|
671 unsigned int count, |
|
672 const USHORT values[], |
|
673 collect_glyphs_func_t collect_func, |
|
674 const void *collect_data) |
|
675 { |
|
676 for (unsigned int i = 0; i < count; i++) |
|
677 collect_func (glyphs, values[i], collect_data); |
|
678 } |
|
679 |
|
680 |
|
681 static inline bool match_glyph (hb_codepoint_t glyph_id, const USHORT &value, const void *data HB_UNUSED) |
|
682 { |
|
683 return glyph_id == value; |
|
684 } |
|
685 static inline bool match_class (hb_codepoint_t glyph_id, const USHORT &value, const void *data) |
|
686 { |
|
687 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data); |
|
688 return class_def.get_class (glyph_id) == value; |
|
689 } |
|
690 static inline bool match_coverage (hb_codepoint_t glyph_id, const USHORT &value, const void *data) |
|
691 { |
|
692 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value; |
|
693 return (data+coverage).get_coverage (glyph_id) != NOT_COVERED; |
|
694 } |
|
695 |
|
696 static inline bool would_match_input (hb_would_apply_context_t *c, |
|
697 unsigned int count, /* Including the first glyph (not matched) */ |
|
698 const USHORT input[], /* Array of input values--start with second glyph */ |
|
699 match_func_t match_func, |
|
700 const void *match_data) |
|
701 { |
|
702 if (count != c->len) |
|
703 return false; |
|
704 |
|
705 for (unsigned int i = 1; i < count; i++) |
|
706 if (likely (!match_func (c->glyphs[i], input[i - 1], match_data))) |
|
707 return false; |
|
708 |
|
709 return true; |
|
710 } |
|
711 static inline bool match_input (hb_apply_context_t *c, |
|
712 unsigned int count, /* Including the first glyph (not matched) */ |
|
713 const USHORT input[], /* Array of input values--start with second glyph */ |
|
714 match_func_t match_func, |
|
715 const void *match_data, |
|
716 unsigned int *end_offset, |
|
717 unsigned int match_positions[MAX_CONTEXT_LENGTH], |
|
718 bool *p_is_mark_ligature = NULL, |
|
719 unsigned int *p_total_component_count = NULL) |
|
720 { |
|
721 TRACE_APPLY (NULL); |
|
722 |
|
723 if (unlikely (count > MAX_CONTEXT_LENGTH)) TRACE_RETURN (false); |
|
724 |
|
725 hb_buffer_t *buffer = c->buffer; |
|
726 |
|
727 hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, buffer->idx, count - 1); |
|
728 skippy_iter.set_match_func (match_func, match_data, input); |
|
729 if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false); |
|
730 |
|
731 /* |
|
732 * This is perhaps the trickiest part of OpenType... Remarks: |
|
733 * |
|
734 * - If all components of the ligature were marks, we call this a mark ligature. |
|
735 * |
|
736 * - If there is no GDEF, and the ligature is NOT a mark ligature, we categorize |
|
737 * it as a ligature glyph. |
|
738 * |
|
739 * - Ligatures cannot be formed across glyphs attached to different components |
|
740 * of previous ligatures. Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and |
|
741 * LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother. |
|
742 * However, it would be wrong to ligate that SHADDA,FATHA sequence.o |
|
743 * There is an exception to this: If a ligature tries ligating with marks that |
|
744 * belong to it itself, go ahead, assuming that the font designer knows what |
|
745 * they are doing (otherwise it can break Indic stuff when a matra wants to |
|
746 * ligate with a conjunct...) |
|
747 */ |
|
748 |
|
749 bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->cur()); |
|
750 |
|
751 unsigned int total_component_count = 0; |
|
752 total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur()); |
|
753 |
|
754 unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur()); |
|
755 unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur()); |
|
756 |
|
757 match_positions[0] = buffer->idx; |
|
758 for (unsigned int i = 1; i < count; i++) |
|
759 { |
|
760 if (!skippy_iter.next ()) return TRACE_RETURN (false); |
|
761 |
|
762 match_positions[i] = skippy_iter.idx; |
|
763 |
|
764 unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]); |
|
765 unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]); |
|
766 |
|
767 if (first_lig_id && first_lig_comp) { |
|
768 /* If first component was attached to a previous ligature component, |
|
769 * all subsequent components should be attached to the same ligature |
|
770 * component, otherwise we shouldn't ligate them. */ |
|
771 if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp) |
|
772 return TRACE_RETURN (false); |
|
773 } else { |
|
774 /* If first component was NOT attached to a previous ligature component, |
|
775 * all subsequent components should also NOT be attached to any ligature |
|
776 * component, unless they are attached to the first component itself! */ |
|
777 if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id)) |
|
778 return TRACE_RETURN (false); |
|
779 } |
|
780 |
|
781 is_mark_ligature = is_mark_ligature && _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx]); |
|
782 total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]); |
|
783 } |
|
784 |
|
785 *end_offset = skippy_iter.idx - buffer->idx + 1; |
|
786 |
|
787 if (p_is_mark_ligature) |
|
788 *p_is_mark_ligature = is_mark_ligature; |
|
789 |
|
790 if (p_total_component_count) |
|
791 *p_total_component_count = total_component_count; |
|
792 |
|
793 return TRACE_RETURN (true); |
|
794 } |
|
795 static inline void ligate_input (hb_apply_context_t *c, |
|
796 unsigned int count, /* Including the first glyph */ |
|
797 unsigned int match_positions[MAX_CONTEXT_LENGTH], /* Including the first glyph */ |
|
798 unsigned int match_length, |
|
799 hb_codepoint_t lig_glyph, |
|
800 bool is_mark_ligature, |
|
801 unsigned int total_component_count) |
|
802 { |
|
803 TRACE_APPLY (NULL); |
|
804 |
|
805 hb_buffer_t *buffer = c->buffer; |
|
806 |
|
807 buffer->merge_clusters (buffer->idx, buffer->idx + match_length); |
|
808 |
|
809 /* |
|
810 * - If it *is* a mark ligature, we don't allocate a new ligature id, and leave |
|
811 * the ligature to keep its old ligature id. This will allow it to attach to |
|
812 * a base ligature in GPOS. Eg. if the sequence is: LAM,LAM,SHADDA,FATHA,HEH, |
|
813 * and LAM,LAM,HEH for a ligature, they will leave SHADDA and FATHA wit a |
|
814 * ligature id and component value of 2. Then if SHADDA,FATHA form a ligature |
|
815 * later, we don't want them to lose their ligature id/component, otherwise |
|
816 * GPOS will fail to correctly position the mark ligature on top of the |
|
817 * LAM,LAM,HEH ligature. See: |
|
818 * https://bugzilla.gnome.org/show_bug.cgi?id=676343 |
|
819 * |
|
820 * - If a ligature is formed of components that some of which are also ligatures |
|
821 * themselves, and those ligature components had marks attached to *their* |
|
822 * components, we have to attach the marks to the new ligature component |
|
823 * positions! Now *that*'s tricky! And these marks may be following the |
|
824 * last component of the whole sequence, so we should loop forward looking |
|
825 * for them and update them. |
|
826 * |
|
827 * Eg. the sequence is LAM,LAM,SHADDA,FATHA,HEH, and the font first forms a |
|
828 * 'calt' ligature of LAM,HEH, leaving the SHADDA and FATHA with a ligature |
|
829 * id and component == 1. Now, during 'liga', the LAM and the LAM-HEH ligature |
|
830 * form a LAM-LAM-HEH ligature. We need to reassign the SHADDA and FATHA to |
|
831 * the new ligature with a component value of 2. |
|
832 * |
|
833 * This in fact happened to a font... See: |
|
834 * https://bugzilla.gnome.org/show_bug.cgi?id=437633 |
|
835 */ |
|
836 |
|
837 unsigned int klass = is_mark_ligature ? 0 : HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE; |
|
838 unsigned int lig_id = is_mark_ligature ? 0 : _hb_allocate_lig_id (buffer); |
|
839 unsigned int last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur()); |
|
840 unsigned int last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur()); |
|
841 unsigned int components_so_far = last_num_components; |
|
842 |
|
843 if (!is_mark_ligature) |
|
844 { |
|
845 _hb_glyph_info_set_lig_props_for_ligature (&buffer->cur(), lig_id, total_component_count); |
|
846 if (_hb_glyph_info_get_general_category (&buffer->cur()) == HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK) |
|
847 { |
|
848 _hb_glyph_info_set_general_category (&buffer->cur(), HB_UNICODE_GENERAL_CATEGORY_OTHER_LETTER); |
|
849 _hb_glyph_info_set_modified_combining_class (&buffer->cur(), 0); |
|
850 } |
|
851 } |
|
852 c->replace_glyph_with_ligature (lig_glyph, klass); |
|
853 |
|
854 for (unsigned int i = 1; i < count; i++) |
|
855 { |
|
856 while (buffer->idx < match_positions[i]) |
|
857 { |
|
858 if (!is_mark_ligature) { |
|
859 unsigned int new_lig_comp = components_so_far - last_num_components + |
|
860 MIN (MAX (_hb_glyph_info_get_lig_comp (&buffer->cur()), 1u), last_num_components); |
|
861 _hb_glyph_info_set_lig_props_for_mark (&buffer->cur(), lig_id, new_lig_comp); |
|
862 } |
|
863 buffer->next_glyph (); |
|
864 } |
|
865 |
|
866 last_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur()); |
|
867 last_num_components = _hb_glyph_info_get_lig_num_comps (&buffer->cur()); |
|
868 components_so_far += last_num_components; |
|
869 |
|
870 /* Skip the base glyph */ |
|
871 buffer->idx++; |
|
872 } |
|
873 |
|
874 if (!is_mark_ligature && last_lig_id) { |
|
875 /* Re-adjust components for any marks following. */ |
|
876 for (unsigned int i = buffer->idx; i < buffer->len; i++) { |
|
877 if (last_lig_id == _hb_glyph_info_get_lig_id (&buffer->info[i])) { |
|
878 unsigned int new_lig_comp = components_so_far - last_num_components + |
|
879 MIN (MAX (_hb_glyph_info_get_lig_comp (&buffer->info[i]), 1u), last_num_components); |
|
880 _hb_glyph_info_set_lig_props_for_mark (&buffer->info[i], lig_id, new_lig_comp); |
|
881 } else |
|
882 break; |
|
883 } |
|
884 } |
|
885 } |
|
886 |
|
887 static inline bool match_backtrack (hb_apply_context_t *c, |
|
888 unsigned int count, |
|
889 const USHORT backtrack[], |
|
890 match_func_t match_func, |
|
891 const void *match_data) |
|
892 { |
|
893 TRACE_APPLY (NULL); |
|
894 |
|
895 hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, c->buffer->backtrack_len (), count, true); |
|
896 skippy_iter.set_match_func (match_func, match_data, backtrack); |
|
897 if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false); |
|
898 |
|
899 for (unsigned int i = 0; i < count; i++) |
|
900 if (!skippy_iter.prev ()) |
|
901 return TRACE_RETURN (false); |
|
902 |
|
903 return TRACE_RETURN (true); |
|
904 } |
|
905 |
|
906 static inline bool match_lookahead (hb_apply_context_t *c, |
|
907 unsigned int count, |
|
908 const USHORT lookahead[], |
|
909 match_func_t match_func, |
|
910 const void *match_data, |
|
911 unsigned int offset) |
|
912 { |
|
913 TRACE_APPLY (NULL); |
|
914 |
|
915 hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx + offset - 1, count, true); |
|
916 skippy_iter.set_match_func (match_func, match_data, lookahead); |
|
917 if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false); |
|
918 |
|
919 for (unsigned int i = 0; i < count; i++) |
|
920 if (!skippy_iter.next ()) |
|
921 return TRACE_RETURN (false); |
|
922 |
|
923 return TRACE_RETURN (true); |
|
924 } |
|
925 |
|
926 |
|
927 |
|
928 struct LookupRecord |
|
929 { |
|
930 inline bool sanitize (hb_sanitize_context_t *c) { |
|
931 TRACE_SANITIZE (this); |
|
932 return TRACE_RETURN (c->check_struct (this)); |
|
933 } |
|
934 |
|
935 USHORT sequenceIndex; /* Index into current glyph |
|
936 * sequence--first glyph = 0 */ |
|
937 USHORT lookupListIndex; /* Lookup to apply to that |
|
938 * position--zero--based */ |
|
939 public: |
|
940 DEFINE_SIZE_STATIC (4); |
|
941 }; |
|
942 |
|
943 |
|
944 template <typename context_t> |
|
945 static inline void recurse_lookups (context_t *c, |
|
946 unsigned int lookupCount, |
|
947 const LookupRecord lookupRecord[] /* Array of LookupRecords--in design order */) |
|
948 { |
|
949 for (unsigned int i = 0; i < lookupCount; i++) |
|
950 c->recurse (lookupRecord[i].lookupListIndex); |
|
951 } |
|
952 |
|
953 static inline bool apply_lookup (hb_apply_context_t *c, |
|
954 unsigned int count, /* Including the first glyph */ |
|
955 unsigned int match_positions[MAX_CONTEXT_LENGTH], /* Including the first glyph */ |
|
956 unsigned int lookupCount, |
|
957 const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */ |
|
958 unsigned int match_length) |
|
959 { |
|
960 TRACE_APPLY (NULL); |
|
961 |
|
962 hb_buffer_t *buffer = c->buffer; |
|
963 unsigned int end; |
|
964 |
|
965 /* All positions are distance from beginning of *output* buffer. |
|
966 * Adjust. */ |
|
967 { |
|
968 unsigned int bl = buffer->backtrack_len (); |
|
969 end = bl + match_length; |
|
970 |
|
971 int delta = bl - buffer->idx; |
|
972 /* Convert positions to new indexing. */ |
|
973 for (unsigned int j = 0; j < count; j++) |
|
974 match_positions[j] += delta; |
|
975 } |
|
976 |
|
977 for (unsigned int i = 0; i < lookupCount; i++) |
|
978 { |
|
979 unsigned int idx = lookupRecord[i].sequenceIndex; |
|
980 if (idx >= count) |
|
981 continue; |
|
982 |
|
983 buffer->move_to (match_positions[idx]); |
|
984 |
|
985 unsigned int orig_len = buffer->backtrack_len () + buffer->lookahead_len (); |
|
986 if (!c->recurse (lookupRecord[i].lookupListIndex)) |
|
987 continue; |
|
988 |
|
989 unsigned int new_len = buffer->backtrack_len () + buffer->lookahead_len (); |
|
990 int delta = new_len - orig_len; |
|
991 |
|
992 if (!delta) |
|
993 continue; |
|
994 |
|
995 /* Recursed lookup changed buffer len. Adjust. */ |
|
996 |
|
997 /* end can't go back past the current match position. */ |
|
998 end = MAX ((int) match_positions[idx] + 1, int (end) + delta); |
|
999 |
|
1000 unsigned int next = idx + 1; /* next now is the position after the recursed lookup. */ |
|
1001 |
|
1002 if (delta > 0) |
|
1003 { |
|
1004 if (unlikely (delta + count > MAX_CONTEXT_LENGTH)) |
|
1005 break; |
|
1006 } |
|
1007 else |
|
1008 { |
|
1009 /* NOTE: delta is negative. */ |
|
1010 delta = MAX (delta, (int) next - (int) count); |
|
1011 next -= delta; |
|
1012 } |
|
1013 |
|
1014 /* Shift! */ |
|
1015 memmove (match_positions + next + delta, match_positions + next, |
|
1016 (count - next) * sizeof (match_positions[0])); |
|
1017 next += delta; |
|
1018 count += delta; |
|
1019 |
|
1020 /* Fill in new entries. */ |
|
1021 for (unsigned int j = idx + 1; j < next; j++) |
|
1022 match_positions[j] = match_positions[j - 1] + 1; |
|
1023 |
|
1024 /* And fixup the rest. */ |
|
1025 for (; next < count; next++) |
|
1026 match_positions[next] += delta; |
|
1027 } |
|
1028 |
|
1029 buffer->move_to (end); |
|
1030 |
|
1031 return TRACE_RETURN (true); |
|
1032 } |
|
1033 |
|
1034 |
|
1035 |
|
1036 /* Contextual lookups */ |
|
1037 |
|
1038 struct ContextClosureLookupContext |
|
1039 { |
|
1040 ContextClosureFuncs funcs; |
|
1041 const void *intersects_data; |
|
1042 }; |
|
1043 |
|
1044 struct ContextCollectGlyphsLookupContext |
|
1045 { |
|
1046 ContextCollectGlyphsFuncs funcs; |
|
1047 const void *collect_data; |
|
1048 }; |
|
1049 |
|
1050 struct ContextApplyLookupContext |
|
1051 { |
|
1052 ContextApplyFuncs funcs; |
|
1053 const void *match_data; |
|
1054 }; |
|
1055 |
|
1056 static inline void context_closure_lookup (hb_closure_context_t *c, |
|
1057 unsigned int inputCount, /* Including the first glyph (not matched) */ |
|
1058 const USHORT input[], /* Array of input values--start with second glyph */ |
|
1059 unsigned int lookupCount, |
|
1060 const LookupRecord lookupRecord[], |
|
1061 ContextClosureLookupContext &lookup_context) |
|
1062 { |
|
1063 if (intersects_array (c, |
|
1064 inputCount ? inputCount - 1 : 0, input, |
|
1065 lookup_context.funcs.intersects, lookup_context.intersects_data)) |
|
1066 recurse_lookups (c, |
|
1067 lookupCount, lookupRecord); |
|
1068 } |
|
1069 |
|
1070 static inline void context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c, |
|
1071 unsigned int inputCount, /* Including the first glyph (not matched) */ |
|
1072 const USHORT input[], /* Array of input values--start with second glyph */ |
|
1073 unsigned int lookupCount, |
|
1074 const LookupRecord lookupRecord[], |
|
1075 ContextCollectGlyphsLookupContext &lookup_context) |
|
1076 { |
|
1077 collect_array (c, c->input, |
|
1078 inputCount ? inputCount - 1 : 0, input, |
|
1079 lookup_context.funcs.collect, lookup_context.collect_data); |
|
1080 recurse_lookups (c, |
|
1081 lookupCount, lookupRecord); |
|
1082 } |
|
1083 |
|
1084 static inline bool context_would_apply_lookup (hb_would_apply_context_t *c, |
|
1085 unsigned int inputCount, /* Including the first glyph (not matched) */ |
|
1086 const USHORT input[], /* Array of input values--start with second glyph */ |
|
1087 unsigned int lookupCount HB_UNUSED, |
|
1088 const LookupRecord lookupRecord[] HB_UNUSED, |
|
1089 ContextApplyLookupContext &lookup_context) |
|
1090 { |
|
1091 return would_match_input (c, |
|
1092 inputCount, input, |
|
1093 lookup_context.funcs.match, lookup_context.match_data); |
|
1094 } |
|
1095 static inline bool context_apply_lookup (hb_apply_context_t *c, |
|
1096 unsigned int inputCount, /* Including the first glyph (not matched) */ |
|
1097 const USHORT input[], /* Array of input values--start with second glyph */ |
|
1098 unsigned int lookupCount, |
|
1099 const LookupRecord lookupRecord[], |
|
1100 ContextApplyLookupContext &lookup_context) |
|
1101 { |
|
1102 unsigned int match_length = 0; |
|
1103 unsigned int match_positions[MAX_CONTEXT_LENGTH]; |
|
1104 return match_input (c, |
|
1105 inputCount, input, |
|
1106 lookup_context.funcs.match, lookup_context.match_data, |
|
1107 &match_length, match_positions) |
|
1108 && apply_lookup (c, |
|
1109 inputCount, match_positions, |
|
1110 lookupCount, lookupRecord, |
|
1111 match_length); |
|
1112 } |
|
1113 |
|
1114 struct Rule |
|
1115 { |
|
1116 inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const |
|
1117 { |
|
1118 TRACE_CLOSURE (this); |
|
1119 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0)); |
|
1120 context_closure_lookup (c, |
|
1121 inputCount, input, |
|
1122 lookupCount, lookupRecord, |
|
1123 lookup_context); |
|
1124 } |
|
1125 |
|
1126 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const |
|
1127 { |
|
1128 TRACE_COLLECT_GLYPHS (this); |
|
1129 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0)); |
|
1130 context_collect_glyphs_lookup (c, |
|
1131 inputCount, input, |
|
1132 lookupCount, lookupRecord, |
|
1133 lookup_context); |
|
1134 } |
|
1135 |
|
1136 inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const |
|
1137 { |
|
1138 TRACE_WOULD_APPLY (this); |
|
1139 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0)); |
|
1140 return TRACE_RETURN (context_would_apply_lookup (c, inputCount, input, lookupCount, lookupRecord, lookup_context)); |
|
1141 } |
|
1142 |
|
1143 inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const |
|
1144 { |
|
1145 TRACE_APPLY (this); |
|
1146 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, input[0].static_size * (inputCount ? inputCount - 1 : 0)); |
|
1147 return TRACE_RETURN (context_apply_lookup (c, inputCount, input, lookupCount, lookupRecord, lookup_context)); |
|
1148 } |
|
1149 |
|
1150 public: |
|
1151 inline bool sanitize (hb_sanitize_context_t *c) { |
|
1152 TRACE_SANITIZE (this); |
|
1153 return inputCount.sanitize (c) |
|
1154 && lookupCount.sanitize (c) |
|
1155 && c->check_range (input, |
|
1156 input[0].static_size * inputCount |
|
1157 + lookupRecordX[0].static_size * lookupCount); |
|
1158 } |
|
1159 |
|
1160 protected: |
|
1161 USHORT inputCount; /* Total number of glyphs in input |
|
1162 * glyph sequence--includes the first |
|
1163 * glyph */ |
|
1164 USHORT lookupCount; /* Number of LookupRecords */ |
|
1165 USHORT input[VAR]; /* Array of match inputs--start with |
|
1166 * second glyph */ |
|
1167 LookupRecord lookupRecordX[VAR]; /* Array of LookupRecords--in |
|
1168 * design order */ |
|
1169 public: |
|
1170 DEFINE_SIZE_ARRAY2 (4, input, lookupRecordX); |
|
1171 }; |
|
1172 |
|
1173 struct RuleSet |
|
1174 { |
|
1175 inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const |
|
1176 { |
|
1177 TRACE_CLOSURE (this); |
|
1178 unsigned int num_rules = rule.len; |
|
1179 for (unsigned int i = 0; i < num_rules; i++) |
|
1180 (this+rule[i]).closure (c, lookup_context); |
|
1181 } |
|
1182 |
|
1183 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ContextCollectGlyphsLookupContext &lookup_context) const |
|
1184 { |
|
1185 TRACE_COLLECT_GLYPHS (this); |
|
1186 unsigned int num_rules = rule.len; |
|
1187 for (unsigned int i = 0; i < num_rules; i++) |
|
1188 (this+rule[i]).collect_glyphs (c, lookup_context); |
|
1189 } |
|
1190 |
|
1191 inline bool would_apply (hb_would_apply_context_t *c, ContextApplyLookupContext &lookup_context) const |
|
1192 { |
|
1193 TRACE_WOULD_APPLY (this); |
|
1194 unsigned int num_rules = rule.len; |
|
1195 for (unsigned int i = 0; i < num_rules; i++) |
|
1196 { |
|
1197 if ((this+rule[i]).would_apply (c, lookup_context)) |
|
1198 return TRACE_RETURN (true); |
|
1199 } |
|
1200 return TRACE_RETURN (false); |
|
1201 } |
|
1202 |
|
1203 inline bool apply (hb_apply_context_t *c, ContextApplyLookupContext &lookup_context) const |
|
1204 { |
|
1205 TRACE_APPLY (this); |
|
1206 unsigned int num_rules = rule.len; |
|
1207 for (unsigned int i = 0; i < num_rules; i++) |
|
1208 { |
|
1209 if ((this+rule[i]).apply (c, lookup_context)) |
|
1210 return TRACE_RETURN (true); |
|
1211 } |
|
1212 return TRACE_RETURN (false); |
|
1213 } |
|
1214 |
|
1215 inline bool sanitize (hb_sanitize_context_t *c) { |
|
1216 TRACE_SANITIZE (this); |
|
1217 return TRACE_RETURN (rule.sanitize (c, this)); |
|
1218 } |
|
1219 |
|
1220 protected: |
|
1221 OffsetArrayOf<Rule> |
|
1222 rule; /* Array of Rule tables |
|
1223 * ordered by preference */ |
|
1224 public: |
|
1225 DEFINE_SIZE_ARRAY (2, rule); |
|
1226 }; |
|
1227 |
|
1228 |
|
1229 struct ContextFormat1 |
|
1230 { |
|
1231 inline void closure (hb_closure_context_t *c) const |
|
1232 { |
|
1233 TRACE_CLOSURE (this); |
|
1234 |
|
1235 const Coverage &cov = (this+coverage); |
|
1236 |
|
1237 struct ContextClosureLookupContext lookup_context = { |
|
1238 {intersects_glyph}, |
|
1239 NULL |
|
1240 }; |
|
1241 |
|
1242 unsigned int count = ruleSet.len; |
|
1243 for (unsigned int i = 0; i < count; i++) |
|
1244 if (cov.intersects_coverage (c->glyphs, i)) { |
|
1245 const RuleSet &rule_set = this+ruleSet[i]; |
|
1246 rule_set.closure (c, lookup_context); |
|
1247 } |
|
1248 } |
|
1249 |
|
1250 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const |
|
1251 { |
|
1252 TRACE_COLLECT_GLYPHS (this); |
|
1253 (this+coverage).add_coverage (c->input); |
|
1254 |
|
1255 struct ContextCollectGlyphsLookupContext lookup_context = { |
|
1256 {collect_glyph}, |
|
1257 NULL |
|
1258 }; |
|
1259 |
|
1260 unsigned int count = ruleSet.len; |
|
1261 for (unsigned int i = 0; i < count; i++) |
|
1262 (this+ruleSet[i]).collect_glyphs (c, lookup_context); |
|
1263 } |
|
1264 |
|
1265 inline bool would_apply (hb_would_apply_context_t *c) const |
|
1266 { |
|
1267 TRACE_WOULD_APPLY (this); |
|
1268 |
|
1269 const RuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])]; |
|
1270 struct ContextApplyLookupContext lookup_context = { |
|
1271 {match_glyph}, |
|
1272 NULL |
|
1273 }; |
|
1274 return TRACE_RETURN (rule_set.would_apply (c, lookup_context)); |
|
1275 } |
|
1276 |
|
1277 inline const Coverage &get_coverage (void) const |
|
1278 { |
|
1279 return this+coverage; |
|
1280 } |
|
1281 |
|
1282 inline bool apply (hb_apply_context_t *c) const |
|
1283 { |
|
1284 TRACE_APPLY (this); |
|
1285 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); |
|
1286 if (likely (index == NOT_COVERED)) |
|
1287 return TRACE_RETURN (false); |
|
1288 |
|
1289 const RuleSet &rule_set = this+ruleSet[index]; |
|
1290 struct ContextApplyLookupContext lookup_context = { |
|
1291 {match_glyph}, |
|
1292 NULL |
|
1293 }; |
|
1294 return TRACE_RETURN (rule_set.apply (c, lookup_context)); |
|
1295 } |
|
1296 |
|
1297 inline bool sanitize (hb_sanitize_context_t *c) { |
|
1298 TRACE_SANITIZE (this); |
|
1299 return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this)); |
|
1300 } |
|
1301 |
|
1302 protected: |
|
1303 USHORT format; /* Format identifier--format = 1 */ |
|
1304 OffsetTo<Coverage> |
|
1305 coverage; /* Offset to Coverage table--from |
|
1306 * beginning of table */ |
|
1307 OffsetArrayOf<RuleSet> |
|
1308 ruleSet; /* Array of RuleSet tables |
|
1309 * ordered by Coverage Index */ |
|
1310 public: |
|
1311 DEFINE_SIZE_ARRAY (6, ruleSet); |
|
1312 }; |
|
1313 |
|
1314 |
|
1315 struct ContextFormat2 |
|
1316 { |
|
1317 inline void closure (hb_closure_context_t *c) const |
|
1318 { |
|
1319 TRACE_CLOSURE (this); |
|
1320 if (!(this+coverage).intersects (c->glyphs)) |
|
1321 return; |
|
1322 |
|
1323 const ClassDef &class_def = this+classDef; |
|
1324 |
|
1325 struct ContextClosureLookupContext lookup_context = { |
|
1326 {intersects_class}, |
|
1327 &class_def |
|
1328 }; |
|
1329 |
|
1330 unsigned int count = ruleSet.len; |
|
1331 for (unsigned int i = 0; i < count; i++) |
|
1332 if (class_def.intersects_class (c->glyphs, i)) { |
|
1333 const RuleSet &rule_set = this+ruleSet[i]; |
|
1334 rule_set.closure (c, lookup_context); |
|
1335 } |
|
1336 } |
|
1337 |
|
1338 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const |
|
1339 { |
|
1340 TRACE_COLLECT_GLYPHS (this); |
|
1341 (this+coverage).add_coverage (c->input); |
|
1342 |
|
1343 const ClassDef &class_def = this+classDef; |
|
1344 struct ContextCollectGlyphsLookupContext lookup_context = { |
|
1345 {collect_class}, |
|
1346 &class_def |
|
1347 }; |
|
1348 |
|
1349 unsigned int count = ruleSet.len; |
|
1350 for (unsigned int i = 0; i < count; i++) |
|
1351 (this+ruleSet[i]).collect_glyphs (c, lookup_context); |
|
1352 } |
|
1353 |
|
1354 inline bool would_apply (hb_would_apply_context_t *c) const |
|
1355 { |
|
1356 TRACE_WOULD_APPLY (this); |
|
1357 |
|
1358 const ClassDef &class_def = this+classDef; |
|
1359 unsigned int index = class_def.get_class (c->glyphs[0]); |
|
1360 const RuleSet &rule_set = this+ruleSet[index]; |
|
1361 struct ContextApplyLookupContext lookup_context = { |
|
1362 {match_class}, |
|
1363 &class_def |
|
1364 }; |
|
1365 return TRACE_RETURN (rule_set.would_apply (c, lookup_context)); |
|
1366 } |
|
1367 |
|
1368 inline const Coverage &get_coverage (void) const |
|
1369 { |
|
1370 return this+coverage; |
|
1371 } |
|
1372 |
|
1373 inline bool apply (hb_apply_context_t *c) const |
|
1374 { |
|
1375 TRACE_APPLY (this); |
|
1376 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); |
|
1377 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); |
|
1378 |
|
1379 const ClassDef &class_def = this+classDef; |
|
1380 index = class_def.get_class (c->buffer->cur().codepoint); |
|
1381 const RuleSet &rule_set = this+ruleSet[index]; |
|
1382 struct ContextApplyLookupContext lookup_context = { |
|
1383 {match_class}, |
|
1384 &class_def |
|
1385 }; |
|
1386 return TRACE_RETURN (rule_set.apply (c, lookup_context)); |
|
1387 } |
|
1388 |
|
1389 inline bool sanitize (hb_sanitize_context_t *c) { |
|
1390 TRACE_SANITIZE (this); |
|
1391 return TRACE_RETURN (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this)); |
|
1392 } |
|
1393 |
|
1394 protected: |
|
1395 USHORT format; /* Format identifier--format = 2 */ |
|
1396 OffsetTo<Coverage> |
|
1397 coverage; /* Offset to Coverage table--from |
|
1398 * beginning of table */ |
|
1399 OffsetTo<ClassDef> |
|
1400 classDef; /* Offset to glyph ClassDef table--from |
|
1401 * beginning of table */ |
|
1402 OffsetArrayOf<RuleSet> |
|
1403 ruleSet; /* Array of RuleSet tables |
|
1404 * ordered by class */ |
|
1405 public: |
|
1406 DEFINE_SIZE_ARRAY (8, ruleSet); |
|
1407 }; |
|
1408 |
|
1409 |
|
1410 struct ContextFormat3 |
|
1411 { |
|
1412 inline void closure (hb_closure_context_t *c) const |
|
1413 { |
|
1414 TRACE_CLOSURE (this); |
|
1415 if (!(this+coverage[0]).intersects (c->glyphs)) |
|
1416 return; |
|
1417 |
|
1418 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount); |
|
1419 struct ContextClosureLookupContext lookup_context = { |
|
1420 {intersects_coverage}, |
|
1421 this |
|
1422 }; |
|
1423 context_closure_lookup (c, |
|
1424 glyphCount, (const USHORT *) (coverage + 1), |
|
1425 lookupCount, lookupRecord, |
|
1426 lookup_context); |
|
1427 } |
|
1428 |
|
1429 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const |
|
1430 { |
|
1431 TRACE_COLLECT_GLYPHS (this); |
|
1432 (this+coverage[0]).add_coverage (c->input); |
|
1433 |
|
1434 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount); |
|
1435 struct ContextCollectGlyphsLookupContext lookup_context = { |
|
1436 {collect_coverage}, |
|
1437 this |
|
1438 }; |
|
1439 |
|
1440 context_collect_glyphs_lookup (c, |
|
1441 glyphCount, (const USHORT *) (coverage + 1), |
|
1442 lookupCount, lookupRecord, |
|
1443 lookup_context); |
|
1444 } |
|
1445 |
|
1446 inline bool would_apply (hb_would_apply_context_t *c) const |
|
1447 { |
|
1448 TRACE_WOULD_APPLY (this); |
|
1449 |
|
1450 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount); |
|
1451 struct ContextApplyLookupContext lookup_context = { |
|
1452 {match_coverage}, |
|
1453 this |
|
1454 }; |
|
1455 return TRACE_RETURN (context_would_apply_lookup (c, glyphCount, (const USHORT *) (coverage + 1), lookupCount, lookupRecord, lookup_context)); |
|
1456 } |
|
1457 |
|
1458 inline const Coverage &get_coverage (void) const |
|
1459 { |
|
1460 return this+coverage[0]; |
|
1461 } |
|
1462 |
|
1463 inline bool apply (hb_apply_context_t *c) const |
|
1464 { |
|
1465 TRACE_APPLY (this); |
|
1466 unsigned int index = (this+coverage[0]).get_coverage (c->buffer->cur().codepoint); |
|
1467 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); |
|
1468 |
|
1469 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * glyphCount); |
|
1470 struct ContextApplyLookupContext lookup_context = { |
|
1471 {match_coverage}, |
|
1472 this |
|
1473 }; |
|
1474 return TRACE_RETURN (context_apply_lookup (c, glyphCount, (const USHORT *) (coverage + 1), lookupCount, lookupRecord, lookup_context)); |
|
1475 } |
|
1476 |
|
1477 inline bool sanitize (hb_sanitize_context_t *c) { |
|
1478 TRACE_SANITIZE (this); |
|
1479 if (!c->check_struct (this)) return TRACE_RETURN (false); |
|
1480 unsigned int count = glyphCount; |
|
1481 if (!c->check_array (coverage, coverage[0].static_size, count)) return TRACE_RETURN (false); |
|
1482 for (unsigned int i = 0; i < count; i++) |
|
1483 if (!coverage[i].sanitize (c, this)) return TRACE_RETURN (false); |
|
1484 LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, coverage[0].static_size * count); |
|
1485 return TRACE_RETURN (c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount)); |
|
1486 } |
|
1487 |
|
1488 protected: |
|
1489 USHORT format; /* Format identifier--format = 3 */ |
|
1490 USHORT glyphCount; /* Number of glyphs in the input glyph |
|
1491 * sequence */ |
|
1492 USHORT lookupCount; /* Number of LookupRecords */ |
|
1493 OffsetTo<Coverage> |
|
1494 coverage[VAR]; /* Array of offsets to Coverage |
|
1495 * table in glyph sequence order */ |
|
1496 LookupRecord lookupRecordX[VAR]; /* Array of LookupRecords--in |
|
1497 * design order */ |
|
1498 public: |
|
1499 DEFINE_SIZE_ARRAY2 (6, coverage, lookupRecordX); |
|
1500 }; |
|
1501 |
|
1502 struct Context |
|
1503 { |
|
1504 template <typename context_t> |
|
1505 inline typename context_t::return_t dispatch (context_t *c) const |
|
1506 { |
|
1507 TRACE_DISPATCH (this); |
|
1508 switch (u.format) { |
|
1509 case 1: return TRACE_RETURN (c->dispatch (u.format1)); |
|
1510 case 2: return TRACE_RETURN (c->dispatch (u.format2)); |
|
1511 case 3: return TRACE_RETURN (c->dispatch (u.format3)); |
|
1512 default:return TRACE_RETURN (c->default_return_value ()); |
|
1513 } |
|
1514 } |
|
1515 |
|
1516 inline bool sanitize (hb_sanitize_context_t *c) { |
|
1517 TRACE_SANITIZE (this); |
|
1518 if (!u.format.sanitize (c)) return TRACE_RETURN (false); |
|
1519 switch (u.format) { |
|
1520 case 1: return TRACE_RETURN (u.format1.sanitize (c)); |
|
1521 case 2: return TRACE_RETURN (u.format2.sanitize (c)); |
|
1522 case 3: return TRACE_RETURN (u.format3.sanitize (c)); |
|
1523 default:return TRACE_RETURN (true); |
|
1524 } |
|
1525 } |
|
1526 |
|
1527 protected: |
|
1528 union { |
|
1529 USHORT format; /* Format identifier */ |
|
1530 ContextFormat1 format1; |
|
1531 ContextFormat2 format2; |
|
1532 ContextFormat3 format3; |
|
1533 } u; |
|
1534 }; |
|
1535 |
|
1536 |
|
1537 /* Chaining Contextual lookups */ |
|
1538 |
|
1539 struct ChainContextClosureLookupContext |
|
1540 { |
|
1541 ContextClosureFuncs funcs; |
|
1542 const void *intersects_data[3]; |
|
1543 }; |
|
1544 |
|
1545 struct ChainContextCollectGlyphsLookupContext |
|
1546 { |
|
1547 ContextCollectGlyphsFuncs funcs; |
|
1548 const void *collect_data[3]; |
|
1549 }; |
|
1550 |
|
1551 struct ChainContextApplyLookupContext |
|
1552 { |
|
1553 ContextApplyFuncs funcs; |
|
1554 const void *match_data[3]; |
|
1555 }; |
|
1556 |
|
1557 static inline void chain_context_closure_lookup (hb_closure_context_t *c, |
|
1558 unsigned int backtrackCount, |
|
1559 const USHORT backtrack[], |
|
1560 unsigned int inputCount, /* Including the first glyph (not matched) */ |
|
1561 const USHORT input[], /* Array of input values--start with second glyph */ |
|
1562 unsigned int lookaheadCount, |
|
1563 const USHORT lookahead[], |
|
1564 unsigned int lookupCount, |
|
1565 const LookupRecord lookupRecord[], |
|
1566 ChainContextClosureLookupContext &lookup_context) |
|
1567 { |
|
1568 if (intersects_array (c, |
|
1569 backtrackCount, backtrack, |
|
1570 lookup_context.funcs.intersects, lookup_context.intersects_data[0]) |
|
1571 && intersects_array (c, |
|
1572 inputCount ? inputCount - 1 : 0, input, |
|
1573 lookup_context.funcs.intersects, lookup_context.intersects_data[1]) |
|
1574 && intersects_array (c, |
|
1575 lookaheadCount, lookahead, |
|
1576 lookup_context.funcs.intersects, lookup_context.intersects_data[2])) |
|
1577 recurse_lookups (c, |
|
1578 lookupCount, lookupRecord); |
|
1579 } |
|
1580 |
|
1581 static inline void chain_context_collect_glyphs_lookup (hb_collect_glyphs_context_t *c, |
|
1582 unsigned int backtrackCount, |
|
1583 const USHORT backtrack[], |
|
1584 unsigned int inputCount, /* Including the first glyph (not matched) */ |
|
1585 const USHORT input[], /* Array of input values--start with second glyph */ |
|
1586 unsigned int lookaheadCount, |
|
1587 const USHORT lookahead[], |
|
1588 unsigned int lookupCount, |
|
1589 const LookupRecord lookupRecord[], |
|
1590 ChainContextCollectGlyphsLookupContext &lookup_context) |
|
1591 { |
|
1592 collect_array (c, c->before, |
|
1593 backtrackCount, backtrack, |
|
1594 lookup_context.funcs.collect, lookup_context.collect_data[0]); |
|
1595 collect_array (c, c->input, |
|
1596 inputCount ? inputCount - 1 : 0, input, |
|
1597 lookup_context.funcs.collect, lookup_context.collect_data[1]); |
|
1598 collect_array (c, c->after, |
|
1599 lookaheadCount, lookahead, |
|
1600 lookup_context.funcs.collect, lookup_context.collect_data[2]); |
|
1601 recurse_lookups (c, |
|
1602 lookupCount, lookupRecord); |
|
1603 } |
|
1604 |
|
1605 static inline bool chain_context_would_apply_lookup (hb_would_apply_context_t *c, |
|
1606 unsigned int backtrackCount, |
|
1607 const USHORT backtrack[] HB_UNUSED, |
|
1608 unsigned int inputCount, /* Including the first glyph (not matched) */ |
|
1609 const USHORT input[], /* Array of input values--start with second glyph */ |
|
1610 unsigned int lookaheadCount, |
|
1611 const USHORT lookahead[] HB_UNUSED, |
|
1612 unsigned int lookupCount HB_UNUSED, |
|
1613 const LookupRecord lookupRecord[] HB_UNUSED, |
|
1614 ChainContextApplyLookupContext &lookup_context) |
|
1615 { |
|
1616 return (c->zero_context ? !backtrackCount && !lookaheadCount : true) |
|
1617 && would_match_input (c, |
|
1618 inputCount, input, |
|
1619 lookup_context.funcs.match, lookup_context.match_data[1]); |
|
1620 } |
|
1621 |
|
1622 static inline bool chain_context_apply_lookup (hb_apply_context_t *c, |
|
1623 unsigned int backtrackCount, |
|
1624 const USHORT backtrack[], |
|
1625 unsigned int inputCount, /* Including the first glyph (not matched) */ |
|
1626 const USHORT input[], /* Array of input values--start with second glyph */ |
|
1627 unsigned int lookaheadCount, |
|
1628 const USHORT lookahead[], |
|
1629 unsigned int lookupCount, |
|
1630 const LookupRecord lookupRecord[], |
|
1631 ChainContextApplyLookupContext &lookup_context) |
|
1632 { |
|
1633 unsigned int match_length = 0; |
|
1634 unsigned int match_positions[MAX_CONTEXT_LENGTH]; |
|
1635 return match_input (c, |
|
1636 inputCount, input, |
|
1637 lookup_context.funcs.match, lookup_context.match_data[1], |
|
1638 &match_length, match_positions) |
|
1639 && match_backtrack (c, |
|
1640 backtrackCount, backtrack, |
|
1641 lookup_context.funcs.match, lookup_context.match_data[0]) |
|
1642 && match_lookahead (c, |
|
1643 lookaheadCount, lookahead, |
|
1644 lookup_context.funcs.match, lookup_context.match_data[2], |
|
1645 match_length) |
|
1646 && apply_lookup (c, |
|
1647 inputCount, match_positions, |
|
1648 lookupCount, lookupRecord, |
|
1649 match_length); |
|
1650 } |
|
1651 |
|
1652 struct ChainRule |
|
1653 { |
|
1654 inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const |
|
1655 { |
|
1656 TRACE_CLOSURE (this); |
|
1657 const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); |
|
1658 const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); |
|
1659 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); |
|
1660 chain_context_closure_lookup (c, |
|
1661 backtrack.len, backtrack.array, |
|
1662 input.len, input.array, |
|
1663 lookahead.len, lookahead.array, |
|
1664 lookup.len, lookup.array, |
|
1665 lookup_context); |
|
1666 } |
|
1667 |
|
1668 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const |
|
1669 { |
|
1670 TRACE_COLLECT_GLYPHS (this); |
|
1671 const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); |
|
1672 const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); |
|
1673 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); |
|
1674 chain_context_collect_glyphs_lookup (c, |
|
1675 backtrack.len, backtrack.array, |
|
1676 input.len, input.array, |
|
1677 lookahead.len, lookahead.array, |
|
1678 lookup.len, lookup.array, |
|
1679 lookup_context); |
|
1680 } |
|
1681 |
|
1682 inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const |
|
1683 { |
|
1684 TRACE_WOULD_APPLY (this); |
|
1685 const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); |
|
1686 const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); |
|
1687 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); |
|
1688 return TRACE_RETURN (chain_context_would_apply_lookup (c, |
|
1689 backtrack.len, backtrack.array, |
|
1690 input.len, input.array, |
|
1691 lookahead.len, lookahead.array, lookup.len, |
|
1692 lookup.array, lookup_context)); |
|
1693 } |
|
1694 |
|
1695 inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const |
|
1696 { |
|
1697 TRACE_APPLY (this); |
|
1698 const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); |
|
1699 const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); |
|
1700 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); |
|
1701 return TRACE_RETURN (chain_context_apply_lookup (c, |
|
1702 backtrack.len, backtrack.array, |
|
1703 input.len, input.array, |
|
1704 lookahead.len, lookahead.array, lookup.len, |
|
1705 lookup.array, lookup_context)); |
|
1706 } |
|
1707 |
|
1708 inline bool sanitize (hb_sanitize_context_t *c) { |
|
1709 TRACE_SANITIZE (this); |
|
1710 if (!backtrack.sanitize (c)) return TRACE_RETURN (false); |
|
1711 HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack); |
|
1712 if (!input.sanitize (c)) return TRACE_RETURN (false); |
|
1713 ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); |
|
1714 if (!lookahead.sanitize (c)) return TRACE_RETURN (false); |
|
1715 ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); |
|
1716 return TRACE_RETURN (lookup.sanitize (c)); |
|
1717 } |
|
1718 |
|
1719 protected: |
|
1720 ArrayOf<USHORT> |
|
1721 backtrack; /* Array of backtracking values |
|
1722 * (to be matched before the input |
|
1723 * sequence) */ |
|
1724 HeadlessArrayOf<USHORT> |
|
1725 inputX; /* Array of input values (start with |
|
1726 * second glyph) */ |
|
1727 ArrayOf<USHORT> |
|
1728 lookaheadX; /* Array of lookahead values's (to be |
|
1729 * matched after the input sequence) */ |
|
1730 ArrayOf<LookupRecord> |
|
1731 lookupX; /* Array of LookupRecords--in |
|
1732 * design order) */ |
|
1733 public: |
|
1734 DEFINE_SIZE_MIN (8); |
|
1735 }; |
|
1736 |
|
1737 struct ChainRuleSet |
|
1738 { |
|
1739 inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const |
|
1740 { |
|
1741 TRACE_CLOSURE (this); |
|
1742 unsigned int num_rules = rule.len; |
|
1743 for (unsigned int i = 0; i < num_rules; i++) |
|
1744 (this+rule[i]).closure (c, lookup_context); |
|
1745 } |
|
1746 |
|
1747 inline void collect_glyphs (hb_collect_glyphs_context_t *c, ChainContextCollectGlyphsLookupContext &lookup_context) const |
|
1748 { |
|
1749 TRACE_COLLECT_GLYPHS (this); |
|
1750 unsigned int num_rules = rule.len; |
|
1751 for (unsigned int i = 0; i < num_rules; i++) |
|
1752 (this+rule[i]).collect_glyphs (c, lookup_context); |
|
1753 } |
|
1754 |
|
1755 inline bool would_apply (hb_would_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const |
|
1756 { |
|
1757 TRACE_WOULD_APPLY (this); |
|
1758 unsigned int num_rules = rule.len; |
|
1759 for (unsigned int i = 0; i < num_rules; i++) |
|
1760 if ((this+rule[i]).would_apply (c, lookup_context)) |
|
1761 return TRACE_RETURN (true); |
|
1762 |
|
1763 return TRACE_RETURN (false); |
|
1764 } |
|
1765 |
|
1766 inline bool apply (hb_apply_context_t *c, ChainContextApplyLookupContext &lookup_context) const |
|
1767 { |
|
1768 TRACE_APPLY (this); |
|
1769 unsigned int num_rules = rule.len; |
|
1770 for (unsigned int i = 0; i < num_rules; i++) |
|
1771 if ((this+rule[i]).apply (c, lookup_context)) |
|
1772 return TRACE_RETURN (true); |
|
1773 |
|
1774 return TRACE_RETURN (false); |
|
1775 } |
|
1776 |
|
1777 inline bool sanitize (hb_sanitize_context_t *c) { |
|
1778 TRACE_SANITIZE (this); |
|
1779 return TRACE_RETURN (rule.sanitize (c, this)); |
|
1780 } |
|
1781 |
|
1782 protected: |
|
1783 OffsetArrayOf<ChainRule> |
|
1784 rule; /* Array of ChainRule tables |
|
1785 * ordered by preference */ |
|
1786 public: |
|
1787 DEFINE_SIZE_ARRAY (2, rule); |
|
1788 }; |
|
1789 |
|
1790 struct ChainContextFormat1 |
|
1791 { |
|
1792 inline void closure (hb_closure_context_t *c) const |
|
1793 { |
|
1794 TRACE_CLOSURE (this); |
|
1795 const Coverage &cov = (this+coverage); |
|
1796 |
|
1797 struct ChainContextClosureLookupContext lookup_context = { |
|
1798 {intersects_glyph}, |
|
1799 {NULL, NULL, NULL} |
|
1800 }; |
|
1801 |
|
1802 unsigned int count = ruleSet.len; |
|
1803 for (unsigned int i = 0; i < count; i++) |
|
1804 if (cov.intersects_coverage (c->glyphs, i)) { |
|
1805 const ChainRuleSet &rule_set = this+ruleSet[i]; |
|
1806 rule_set.closure (c, lookup_context); |
|
1807 } |
|
1808 } |
|
1809 |
|
1810 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const |
|
1811 { |
|
1812 TRACE_COLLECT_GLYPHS (this); |
|
1813 (this+coverage).add_coverage (c->input); |
|
1814 |
|
1815 struct ChainContextCollectGlyphsLookupContext lookup_context = { |
|
1816 {collect_glyph}, |
|
1817 {NULL, NULL, NULL} |
|
1818 }; |
|
1819 |
|
1820 unsigned int count = ruleSet.len; |
|
1821 for (unsigned int i = 0; i < count; i++) |
|
1822 (this+ruleSet[i]).collect_glyphs (c, lookup_context); |
|
1823 } |
|
1824 |
|
1825 inline bool would_apply (hb_would_apply_context_t *c) const |
|
1826 { |
|
1827 TRACE_WOULD_APPLY (this); |
|
1828 |
|
1829 const ChainRuleSet &rule_set = this+ruleSet[(this+coverage).get_coverage (c->glyphs[0])]; |
|
1830 struct ChainContextApplyLookupContext lookup_context = { |
|
1831 {match_glyph}, |
|
1832 {NULL, NULL, NULL} |
|
1833 }; |
|
1834 return TRACE_RETURN (rule_set.would_apply (c, lookup_context)); |
|
1835 } |
|
1836 |
|
1837 inline const Coverage &get_coverage (void) const |
|
1838 { |
|
1839 return this+coverage; |
|
1840 } |
|
1841 |
|
1842 inline bool apply (hb_apply_context_t *c) const |
|
1843 { |
|
1844 TRACE_APPLY (this); |
|
1845 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); |
|
1846 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); |
|
1847 |
|
1848 const ChainRuleSet &rule_set = this+ruleSet[index]; |
|
1849 struct ChainContextApplyLookupContext lookup_context = { |
|
1850 {match_glyph}, |
|
1851 {NULL, NULL, NULL} |
|
1852 }; |
|
1853 return TRACE_RETURN (rule_set.apply (c, lookup_context)); |
|
1854 } |
|
1855 |
|
1856 inline bool sanitize (hb_sanitize_context_t *c) { |
|
1857 TRACE_SANITIZE (this); |
|
1858 return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this)); |
|
1859 } |
|
1860 |
|
1861 protected: |
|
1862 USHORT format; /* Format identifier--format = 1 */ |
|
1863 OffsetTo<Coverage> |
|
1864 coverage; /* Offset to Coverage table--from |
|
1865 * beginning of table */ |
|
1866 OffsetArrayOf<ChainRuleSet> |
|
1867 ruleSet; /* Array of ChainRuleSet tables |
|
1868 * ordered by Coverage Index */ |
|
1869 public: |
|
1870 DEFINE_SIZE_ARRAY (6, ruleSet); |
|
1871 }; |
|
1872 |
|
1873 struct ChainContextFormat2 |
|
1874 { |
|
1875 inline void closure (hb_closure_context_t *c) const |
|
1876 { |
|
1877 TRACE_CLOSURE (this); |
|
1878 if (!(this+coverage).intersects (c->glyphs)) |
|
1879 return; |
|
1880 |
|
1881 const ClassDef &backtrack_class_def = this+backtrackClassDef; |
|
1882 const ClassDef &input_class_def = this+inputClassDef; |
|
1883 const ClassDef &lookahead_class_def = this+lookaheadClassDef; |
|
1884 |
|
1885 struct ChainContextClosureLookupContext lookup_context = { |
|
1886 {intersects_class}, |
|
1887 {&backtrack_class_def, |
|
1888 &input_class_def, |
|
1889 &lookahead_class_def} |
|
1890 }; |
|
1891 |
|
1892 unsigned int count = ruleSet.len; |
|
1893 for (unsigned int i = 0; i < count; i++) |
|
1894 if (input_class_def.intersects_class (c->glyphs, i)) { |
|
1895 const ChainRuleSet &rule_set = this+ruleSet[i]; |
|
1896 rule_set.closure (c, lookup_context); |
|
1897 } |
|
1898 } |
|
1899 |
|
1900 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const |
|
1901 { |
|
1902 TRACE_COLLECT_GLYPHS (this); |
|
1903 (this+coverage).add_coverage (c->input); |
|
1904 |
|
1905 const ClassDef &backtrack_class_def = this+backtrackClassDef; |
|
1906 const ClassDef &input_class_def = this+inputClassDef; |
|
1907 const ClassDef &lookahead_class_def = this+lookaheadClassDef; |
|
1908 |
|
1909 struct ChainContextCollectGlyphsLookupContext lookup_context = { |
|
1910 {collect_class}, |
|
1911 {&backtrack_class_def, |
|
1912 &input_class_def, |
|
1913 &lookahead_class_def} |
|
1914 }; |
|
1915 |
|
1916 unsigned int count = ruleSet.len; |
|
1917 for (unsigned int i = 0; i < count; i++) |
|
1918 (this+ruleSet[i]).collect_glyphs (c, lookup_context); |
|
1919 } |
|
1920 |
|
1921 inline bool would_apply (hb_would_apply_context_t *c) const |
|
1922 { |
|
1923 TRACE_WOULD_APPLY (this); |
|
1924 |
|
1925 const ClassDef &backtrack_class_def = this+backtrackClassDef; |
|
1926 const ClassDef &input_class_def = this+inputClassDef; |
|
1927 const ClassDef &lookahead_class_def = this+lookaheadClassDef; |
|
1928 |
|
1929 unsigned int index = input_class_def.get_class (c->glyphs[0]); |
|
1930 const ChainRuleSet &rule_set = this+ruleSet[index]; |
|
1931 struct ChainContextApplyLookupContext lookup_context = { |
|
1932 {match_class}, |
|
1933 {&backtrack_class_def, |
|
1934 &input_class_def, |
|
1935 &lookahead_class_def} |
|
1936 }; |
|
1937 return TRACE_RETURN (rule_set.would_apply (c, lookup_context)); |
|
1938 } |
|
1939 |
|
1940 inline const Coverage &get_coverage (void) const |
|
1941 { |
|
1942 return this+coverage; |
|
1943 } |
|
1944 |
|
1945 inline bool apply (hb_apply_context_t *c) const |
|
1946 { |
|
1947 TRACE_APPLY (this); |
|
1948 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); |
|
1949 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); |
|
1950 |
|
1951 const ClassDef &backtrack_class_def = this+backtrackClassDef; |
|
1952 const ClassDef &input_class_def = this+inputClassDef; |
|
1953 const ClassDef &lookahead_class_def = this+lookaheadClassDef; |
|
1954 |
|
1955 index = input_class_def.get_class (c->buffer->cur().codepoint); |
|
1956 const ChainRuleSet &rule_set = this+ruleSet[index]; |
|
1957 struct ChainContextApplyLookupContext lookup_context = { |
|
1958 {match_class}, |
|
1959 {&backtrack_class_def, |
|
1960 &input_class_def, |
|
1961 &lookahead_class_def} |
|
1962 }; |
|
1963 return TRACE_RETURN (rule_set.apply (c, lookup_context)); |
|
1964 } |
|
1965 |
|
1966 inline bool sanitize (hb_sanitize_context_t *c) { |
|
1967 TRACE_SANITIZE (this); |
|
1968 return TRACE_RETURN (coverage.sanitize (c, this) && backtrackClassDef.sanitize (c, this) && |
|
1969 inputClassDef.sanitize (c, this) && lookaheadClassDef.sanitize (c, this) && |
|
1970 ruleSet.sanitize (c, this)); |
|
1971 } |
|
1972 |
|
1973 protected: |
|
1974 USHORT format; /* Format identifier--format = 2 */ |
|
1975 OffsetTo<Coverage> |
|
1976 coverage; /* Offset to Coverage table--from |
|
1977 * beginning of table */ |
|
1978 OffsetTo<ClassDef> |
|
1979 backtrackClassDef; /* Offset to glyph ClassDef table |
|
1980 * containing backtrack sequence |
|
1981 * data--from beginning of table */ |
|
1982 OffsetTo<ClassDef> |
|
1983 inputClassDef; /* Offset to glyph ClassDef |
|
1984 * table containing input sequence |
|
1985 * data--from beginning of table */ |
|
1986 OffsetTo<ClassDef> |
|
1987 lookaheadClassDef; /* Offset to glyph ClassDef table |
|
1988 * containing lookahead sequence |
|
1989 * data--from beginning of table */ |
|
1990 OffsetArrayOf<ChainRuleSet> |
|
1991 ruleSet; /* Array of ChainRuleSet tables |
|
1992 * ordered by class */ |
|
1993 public: |
|
1994 DEFINE_SIZE_ARRAY (12, ruleSet); |
|
1995 }; |
|
1996 |
|
1997 struct ChainContextFormat3 |
|
1998 { |
|
1999 inline void closure (hb_closure_context_t *c) const |
|
2000 { |
|
2001 TRACE_CLOSURE (this); |
|
2002 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); |
|
2003 |
|
2004 if (!(this+input[0]).intersects (c->glyphs)) |
|
2005 return; |
|
2006 |
|
2007 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); |
|
2008 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); |
|
2009 struct ChainContextClosureLookupContext lookup_context = { |
|
2010 {intersects_coverage}, |
|
2011 {this, this, this} |
|
2012 }; |
|
2013 chain_context_closure_lookup (c, |
|
2014 backtrack.len, (const USHORT *) backtrack.array, |
|
2015 input.len, (const USHORT *) input.array + 1, |
|
2016 lookahead.len, (const USHORT *) lookahead.array, |
|
2017 lookup.len, lookup.array, |
|
2018 lookup_context); |
|
2019 } |
|
2020 |
|
2021 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const |
|
2022 { |
|
2023 TRACE_COLLECT_GLYPHS (this); |
|
2024 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); |
|
2025 |
|
2026 (this+input[0]).add_coverage (c->input); |
|
2027 |
|
2028 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); |
|
2029 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); |
|
2030 struct ChainContextCollectGlyphsLookupContext lookup_context = { |
|
2031 {collect_coverage}, |
|
2032 {this, this, this} |
|
2033 }; |
|
2034 chain_context_collect_glyphs_lookup (c, |
|
2035 backtrack.len, (const USHORT *) backtrack.array, |
|
2036 input.len, (const USHORT *) input.array + 1, |
|
2037 lookahead.len, (const USHORT *) lookahead.array, |
|
2038 lookup.len, lookup.array, |
|
2039 lookup_context); |
|
2040 } |
|
2041 |
|
2042 inline bool would_apply (hb_would_apply_context_t *c) const |
|
2043 { |
|
2044 TRACE_WOULD_APPLY (this); |
|
2045 |
|
2046 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); |
|
2047 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); |
|
2048 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); |
|
2049 struct ChainContextApplyLookupContext lookup_context = { |
|
2050 {match_coverage}, |
|
2051 {this, this, this} |
|
2052 }; |
|
2053 return TRACE_RETURN (chain_context_would_apply_lookup (c, |
|
2054 backtrack.len, (const USHORT *) backtrack.array, |
|
2055 input.len, (const USHORT *) input.array + 1, |
|
2056 lookahead.len, (const USHORT *) lookahead.array, |
|
2057 lookup.len, lookup.array, lookup_context)); |
|
2058 } |
|
2059 |
|
2060 inline const Coverage &get_coverage (void) const |
|
2061 { |
|
2062 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); |
|
2063 return this+input[0]; |
|
2064 } |
|
2065 |
|
2066 inline bool apply (hb_apply_context_t *c) const |
|
2067 { |
|
2068 TRACE_APPLY (this); |
|
2069 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); |
|
2070 |
|
2071 unsigned int index = (this+input[0]).get_coverage (c->buffer->cur().codepoint); |
|
2072 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); |
|
2073 |
|
2074 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); |
|
2075 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); |
|
2076 struct ChainContextApplyLookupContext lookup_context = { |
|
2077 {match_coverage}, |
|
2078 {this, this, this} |
|
2079 }; |
|
2080 return TRACE_RETURN (chain_context_apply_lookup (c, |
|
2081 backtrack.len, (const USHORT *) backtrack.array, |
|
2082 input.len, (const USHORT *) input.array + 1, |
|
2083 lookahead.len, (const USHORT *) lookahead.array, |
|
2084 lookup.len, lookup.array, lookup_context)); |
|
2085 } |
|
2086 |
|
2087 inline bool sanitize (hb_sanitize_context_t *c) { |
|
2088 TRACE_SANITIZE (this); |
|
2089 if (!backtrack.sanitize (c, this)) return TRACE_RETURN (false); |
|
2090 OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack); |
|
2091 if (!input.sanitize (c, this)) return TRACE_RETURN (false); |
|
2092 OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input); |
|
2093 if (!lookahead.sanitize (c, this)) return TRACE_RETURN (false); |
|
2094 ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead); |
|
2095 return TRACE_RETURN (lookup.sanitize (c)); |
|
2096 } |
|
2097 |
|
2098 protected: |
|
2099 USHORT format; /* Format identifier--format = 3 */ |
|
2100 OffsetArrayOf<Coverage> |
|
2101 backtrack; /* Array of coverage tables |
|
2102 * in backtracking sequence, in glyph |
|
2103 * sequence order */ |
|
2104 OffsetArrayOf<Coverage> |
|
2105 inputX ; /* Array of coverage |
|
2106 * tables in input sequence, in glyph |
|
2107 * sequence order */ |
|
2108 OffsetArrayOf<Coverage> |
|
2109 lookaheadX; /* Array of coverage tables |
|
2110 * in lookahead sequence, in glyph |
|
2111 * sequence order */ |
|
2112 ArrayOf<LookupRecord> |
|
2113 lookupX; /* Array of LookupRecords--in |
|
2114 * design order) */ |
|
2115 public: |
|
2116 DEFINE_SIZE_MIN (10); |
|
2117 }; |
|
2118 |
|
2119 struct ChainContext |
|
2120 { |
|
2121 template <typename context_t> |
|
2122 inline typename context_t::return_t dispatch (context_t *c) const |
|
2123 { |
|
2124 TRACE_DISPATCH (this); |
|
2125 switch (u.format) { |
|
2126 case 1: return TRACE_RETURN (c->dispatch (u.format1)); |
|
2127 case 2: return TRACE_RETURN (c->dispatch (u.format2)); |
|
2128 case 3: return TRACE_RETURN (c->dispatch (u.format3)); |
|
2129 default:return TRACE_RETURN (c->default_return_value ()); |
|
2130 } |
|
2131 } |
|
2132 |
|
2133 inline bool sanitize (hb_sanitize_context_t *c) { |
|
2134 TRACE_SANITIZE (this); |
|
2135 if (!u.format.sanitize (c)) return TRACE_RETURN (false); |
|
2136 switch (u.format) { |
|
2137 case 1: return TRACE_RETURN (u.format1.sanitize (c)); |
|
2138 case 2: return TRACE_RETURN (u.format2.sanitize (c)); |
|
2139 case 3: return TRACE_RETURN (u.format3.sanitize (c)); |
|
2140 default:return TRACE_RETURN (true); |
|
2141 } |
|
2142 } |
|
2143 |
|
2144 protected: |
|
2145 union { |
|
2146 USHORT format; /* Format identifier */ |
|
2147 ChainContextFormat1 format1; |
|
2148 ChainContextFormat2 format2; |
|
2149 ChainContextFormat3 format3; |
|
2150 } u; |
|
2151 }; |
|
2152 |
|
2153 |
|
2154 struct ExtensionFormat1 |
|
2155 { |
|
2156 inline unsigned int get_type (void) const { return extensionLookupType; } |
|
2157 inline unsigned int get_offset (void) const { return extensionOffset; } |
|
2158 |
|
2159 inline bool sanitize (hb_sanitize_context_t *c) { |
|
2160 TRACE_SANITIZE (this); |
|
2161 return TRACE_RETURN (c->check_struct (this)); |
|
2162 } |
|
2163 |
|
2164 protected: |
|
2165 USHORT format; /* Format identifier. Set to 1. */ |
|
2166 USHORT extensionLookupType; /* Lookup type of subtable referenced |
|
2167 * by ExtensionOffset (i.e. the |
|
2168 * extension subtable). */ |
|
2169 ULONG extensionOffset; /* Offset to the extension subtable, |
|
2170 * of lookup type subtable. */ |
|
2171 public: |
|
2172 DEFINE_SIZE_STATIC (8); |
|
2173 }; |
|
2174 |
|
2175 template <typename T> |
|
2176 struct Extension |
|
2177 { |
|
2178 inline unsigned int get_type (void) const |
|
2179 { |
|
2180 switch (u.format) { |
|
2181 case 1: return u.format1.get_type (); |
|
2182 default:return 0; |
|
2183 } |
|
2184 } |
|
2185 inline unsigned int get_offset (void) const |
|
2186 { |
|
2187 switch (u.format) { |
|
2188 case 1: return u.format1.get_offset (); |
|
2189 default:return 0; |
|
2190 } |
|
2191 } |
|
2192 |
|
2193 template <typename X> |
|
2194 inline const X& get_subtable (void) const |
|
2195 { |
|
2196 unsigned int offset = get_offset (); |
|
2197 if (unlikely (!offset)) return Null(typename T::LookupSubTable); |
|
2198 return StructAtOffset<typename T::LookupSubTable> (this, offset); |
|
2199 } |
|
2200 |
|
2201 template <typename context_t> |
|
2202 inline typename context_t::return_t dispatch (context_t *c) const |
|
2203 { |
|
2204 return get_subtable<typename T::LookupSubTable> ().dispatch (c, get_type ()); |
|
2205 } |
|
2206 |
|
2207 inline bool sanitize_self (hb_sanitize_context_t *c) { |
|
2208 TRACE_SANITIZE (this); |
|
2209 if (!u.format.sanitize (c)) return TRACE_RETURN (false); |
|
2210 switch (u.format) { |
|
2211 case 1: return TRACE_RETURN (u.format1.sanitize (c)); |
|
2212 default:return TRACE_RETURN (true); |
|
2213 } |
|
2214 } |
|
2215 |
|
2216 inline bool sanitize (hb_sanitize_context_t *c) { |
|
2217 TRACE_SANITIZE (this); |
|
2218 if (!sanitize_self (c)) return TRACE_RETURN (false); |
|
2219 unsigned int offset = get_offset (); |
|
2220 if (unlikely (!offset)) return TRACE_RETURN (true); |
|
2221 return TRACE_RETURN (StructAtOffset<typename T::LookupSubTable> (this, offset).sanitize (c, get_type ())); |
|
2222 } |
|
2223 |
|
2224 protected: |
|
2225 union { |
|
2226 USHORT format; /* Format identifier */ |
|
2227 ExtensionFormat1 format1; |
|
2228 } u; |
|
2229 }; |
|
2230 |
|
2231 |
|
2232 /* |
|
2233 * GSUB/GPOS Common |
|
2234 */ |
|
2235 |
|
2236 struct GSUBGPOS |
|
2237 { |
|
2238 static const hb_tag_t GSUBTag = HB_OT_TAG_GSUB; |
|
2239 static const hb_tag_t GPOSTag = HB_OT_TAG_GPOS; |
|
2240 |
|
2241 inline unsigned int get_script_count (void) const |
|
2242 { return (this+scriptList).len; } |
|
2243 inline const Tag& get_script_tag (unsigned int i) const |
|
2244 { return (this+scriptList).get_tag (i); } |
|
2245 inline unsigned int get_script_tags (unsigned int start_offset, |
|
2246 unsigned int *script_count /* IN/OUT */, |
|
2247 hb_tag_t *script_tags /* OUT */) const |
|
2248 { return (this+scriptList).get_tags (start_offset, script_count, script_tags); } |
|
2249 inline const Script& get_script (unsigned int i) const |
|
2250 { return (this+scriptList)[i]; } |
|
2251 inline bool find_script_index (hb_tag_t tag, unsigned int *index) const |
|
2252 { return (this+scriptList).find_index (tag, index); } |
|
2253 |
|
2254 inline unsigned int get_feature_count (void) const |
|
2255 { return (this+featureList).len; } |
|
2256 inline const Tag& get_feature_tag (unsigned int i) const |
|
2257 { return (this+featureList).get_tag (i); } |
|
2258 inline unsigned int get_feature_tags (unsigned int start_offset, |
|
2259 unsigned int *feature_count /* IN/OUT */, |
|
2260 hb_tag_t *feature_tags /* OUT */) const |
|
2261 { return (this+featureList).get_tags (start_offset, feature_count, feature_tags); } |
|
2262 inline const Feature& get_feature (unsigned int i) const |
|
2263 { return (this+featureList)[i]; } |
|
2264 inline bool find_feature_index (hb_tag_t tag, unsigned int *index) const |
|
2265 { return (this+featureList).find_index (tag, index); } |
|
2266 |
|
2267 inline unsigned int get_lookup_count (void) const |
|
2268 { return (this+lookupList).len; } |
|
2269 inline const Lookup& get_lookup (unsigned int i) const |
|
2270 { return (this+lookupList)[i]; } |
|
2271 |
|
2272 inline bool sanitize (hb_sanitize_context_t *c) { |
|
2273 TRACE_SANITIZE (this); |
|
2274 return TRACE_RETURN (version.sanitize (c) && likely (version.major == 1) && |
|
2275 scriptList.sanitize (c, this) && |
|
2276 featureList.sanitize (c, this) && |
|
2277 lookupList.sanitize (c, this)); |
|
2278 } |
|
2279 |
|
2280 protected: |
|
2281 FixedVersion version; /* Version of the GSUB/GPOS table--initially set |
|
2282 * to 0x00010000 */ |
|
2283 OffsetTo<ScriptList> |
|
2284 scriptList; /* ScriptList table */ |
|
2285 OffsetTo<FeatureList> |
|
2286 featureList; /* FeatureList table */ |
|
2287 OffsetTo<LookupList> |
|
2288 lookupList; /* LookupList table */ |
|
2289 public: |
|
2290 DEFINE_SIZE_STATIC (10); |
|
2291 }; |
|
2292 |
|
2293 |
|
2294 } /* namespace OT */ |
|
2295 |
|
2296 |
|
2297 #endif /* HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH */ |