27 */ |
27 */ |
28 |
28 |
29 #ifndef HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH |
29 #ifndef HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH |
30 #define HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH |
30 #define HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH |
31 |
31 |
|
32 #include "hb-private.hh" |
|
33 #include "hb-debug.hh" |
32 #include "hb-buffer-private.hh" |
34 #include "hb-buffer-private.hh" |
33 #include "hb-ot-layout-gdef-table.hh" |
35 #include "hb-ot-layout-gdef-table.hh" |
34 #include "hb-set-private.hh" |
36 #include "hb-set-private.hh" |
35 |
37 |
36 |
38 |
37 namespace OT { |
39 namespace OT { |
38 |
40 |
39 |
|
40 #ifndef HB_DEBUG_CLOSURE |
|
41 #define HB_DEBUG_CLOSURE (HB_DEBUG+0) |
|
42 #endif |
|
43 |
|
44 #define TRACE_CLOSURE(this) \ |
|
45 hb_auto_trace_t<HB_DEBUG_CLOSURE, hb_void_t> trace \ |
|
46 (&c->debug_depth, c->get_name (), this, HB_FUNC, \ |
|
47 ""); |
|
48 |
41 |
49 struct hb_closure_context_t : |
42 struct hb_closure_context_t : |
50 hb_dispatch_context_t<hb_closure_context_t, hb_void_t, HB_DEBUG_CLOSURE> |
43 hb_dispatch_context_t<hb_closure_context_t, hb_void_t, HB_DEBUG_CLOSURE> |
51 { |
44 { |
52 inline const char *get_name (void) { return "CLOSURE"; } |
45 inline const char *get_name (void) { return "CLOSURE"; } |
75 hb_closure_context_t (hb_face_t *face_, |
68 hb_closure_context_t (hb_face_t *face_, |
76 hb_set_t *glyphs_, |
69 hb_set_t *glyphs_, |
77 unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) : |
70 unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) : |
78 face (face_), |
71 face (face_), |
79 glyphs (glyphs_), |
72 glyphs (glyphs_), |
80 recurse_func (NULL), |
73 recurse_func (nullptr), |
81 nesting_level_left (nesting_level_left_), |
74 nesting_level_left (nesting_level_left_), |
82 debug_depth (0) {} |
75 debug_depth (0) {} |
83 |
76 |
84 void set_recurse_func (recurse_func_t func) { recurse_func = func; } |
77 void set_recurse_func (recurse_func_t func) { recurse_func = func; } |
85 }; |
78 }; |
86 |
79 |
87 |
|
88 |
|
89 #ifndef HB_DEBUG_WOULD_APPLY |
|
90 #define HB_DEBUG_WOULD_APPLY (HB_DEBUG+0) |
|
91 #endif |
|
92 |
|
93 #define TRACE_WOULD_APPLY(this) \ |
|
94 hb_auto_trace_t<HB_DEBUG_WOULD_APPLY, bool> trace \ |
|
95 (&c->debug_depth, c->get_name (), this, HB_FUNC, \ |
|
96 "%d glyphs", c->len); |
|
97 |
80 |
98 struct hb_would_apply_context_t : |
81 struct hb_would_apply_context_t : |
99 hb_dispatch_context_t<hb_would_apply_context_t, bool, HB_DEBUG_WOULD_APPLY> |
82 hb_dispatch_context_t<hb_would_apply_context_t, bool, HB_DEBUG_WOULD_APPLY> |
100 { |
83 { |
101 inline const char *get_name (void) { return "WOULD_APPLY"; } |
84 inline const char *get_name (void) { return "WOULD_APPLY"; } |
120 zero_context (zero_context_), |
103 zero_context (zero_context_), |
121 debug_depth (0) {} |
104 debug_depth (0) {} |
122 }; |
105 }; |
123 |
106 |
124 |
107 |
125 |
|
126 #ifndef HB_DEBUG_COLLECT_GLYPHS |
|
127 #define HB_DEBUG_COLLECT_GLYPHS (HB_DEBUG+0) |
|
128 #endif |
|
129 |
|
130 #define TRACE_COLLECT_GLYPHS(this) \ |
|
131 hb_auto_trace_t<HB_DEBUG_COLLECT_GLYPHS, hb_void_t> trace \ |
|
132 (&c->debug_depth, c->get_name (), this, HB_FUNC, \ |
|
133 ""); |
|
134 |
|
135 struct hb_collect_glyphs_context_t : |
108 struct hb_collect_glyphs_context_t : |
136 hb_dispatch_context_t<hb_collect_glyphs_context_t, hb_void_t, HB_DEBUG_COLLECT_GLYPHS> |
109 hb_dispatch_context_t<hb_collect_glyphs_context_t, hb_void_t, HB_DEBUG_COLLECT_GLYPHS> |
137 { |
110 { |
138 inline const char *get_name (void) { return "COLLECT_GLYPHS"; } |
111 inline const char *get_name (void) { return "COLLECT_GLYPHS"; } |
139 typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index); |
112 typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index); |
144 return_t recurse (unsigned int lookup_index) |
117 return_t recurse (unsigned int lookup_index) |
145 { |
118 { |
146 if (unlikely (nesting_level_left == 0 || !recurse_func)) |
119 if (unlikely (nesting_level_left == 0 || !recurse_func)) |
147 return default_return_value (); |
120 return default_return_value (); |
148 |
121 |
149 /* Note that GPOS sets recurse_func to NULL already, so it doesn't get |
122 /* Note that GPOS sets recurse_func to nullptr already, so it doesn't get |
150 * past the previous check. For GSUB, we only want to collect the output |
123 * past the previous check. For GSUB, we only want to collect the output |
151 * glyphs in the recursion. If output is not requested, we can go home now. |
124 * glyphs in the recursion. If output is not requested, we can go home now. |
152 * |
125 * |
153 * Note further, that the above is not exactly correct. A recursed lookup |
126 * Note further, that the above is not exactly correct. A recursed lookup |
154 * is allowed to match input that is not matched in the context, but that's |
127 * is allowed to match input that is not matched in the context, but that's |
174 |
147 |
175 before = old_before; |
148 before = old_before; |
176 input = old_input; |
149 input = old_input; |
177 after = old_after; |
150 after = old_after; |
178 |
151 |
179 recursed_lookups.add (lookup_index); |
152 recursed_lookups->add (lookup_index); |
180 |
153 |
181 return HB_VOID; |
154 return HB_VOID; |
182 } |
155 } |
183 |
156 |
184 hb_face_t *face; |
157 hb_face_t *face; |
185 hb_set_t *before; |
158 hb_set_t *before; |
186 hb_set_t *input; |
159 hb_set_t *input; |
187 hb_set_t *after; |
160 hb_set_t *after; |
188 hb_set_t *output; |
161 hb_set_t *output; |
189 recurse_func_t recurse_func; |
162 recurse_func_t recurse_func; |
190 hb_set_t recursed_lookups; |
163 hb_set_t *recursed_lookups; |
191 unsigned int nesting_level_left; |
164 unsigned int nesting_level_left; |
192 unsigned int debug_depth; |
165 unsigned int debug_depth; |
193 |
166 |
194 hb_collect_glyphs_context_t (hb_face_t *face_, |
167 hb_collect_glyphs_context_t (hb_face_t *face_, |
195 hb_set_t *glyphs_before, /* OUT. May be NULL */ |
168 hb_set_t *glyphs_before, /* OUT. May be nullptr */ |
196 hb_set_t *glyphs_input, /* OUT. May be NULL */ |
169 hb_set_t *glyphs_input, /* OUT. May be nullptr */ |
197 hb_set_t *glyphs_after, /* OUT. May be NULL */ |
170 hb_set_t *glyphs_after, /* OUT. May be nullptr */ |
198 hb_set_t *glyphs_output, /* OUT. May be NULL */ |
171 hb_set_t *glyphs_output, /* OUT. May be nullptr */ |
199 unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) : |
172 unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) : |
200 face (face_), |
173 face (face_), |
201 before (glyphs_before ? glyphs_before : hb_set_get_empty ()), |
174 before (glyphs_before ? glyphs_before : hb_set_get_empty ()), |
202 input (glyphs_input ? glyphs_input : hb_set_get_empty ()), |
175 input (glyphs_input ? glyphs_input : hb_set_get_empty ()), |
203 after (glyphs_after ? glyphs_after : hb_set_get_empty ()), |
176 after (glyphs_after ? glyphs_after : hb_set_get_empty ()), |
204 output (glyphs_output ? glyphs_output : hb_set_get_empty ()), |
177 output (glyphs_output ? glyphs_output : hb_set_get_empty ()), |
205 recurse_func (NULL), |
178 recurse_func (nullptr), |
206 recursed_lookups (), |
179 recursed_lookups (nullptr), |
207 nesting_level_left (nesting_level_left_), |
180 nesting_level_left (nesting_level_left_), |
208 debug_depth (0) |
181 debug_depth (0) |
209 { |
182 { |
210 recursed_lookups.init (); |
183 recursed_lookups = hb_set_create (); |
211 } |
184 } |
212 ~hb_collect_glyphs_context_t (void) |
185 ~hb_collect_glyphs_context_t (void) |
213 { |
186 { |
214 recursed_lookups.fini (); |
187 hb_set_destroy (recursed_lookups); |
215 } |
188 } |
216 |
189 |
217 void set_recurse_func (recurse_func_t func) { recurse_func = func; } |
190 void set_recurse_func (recurse_func_t func) { recurse_func = func; } |
218 }; |
191 }; |
219 |
192 |
220 |
193 |
221 |
|
222 #ifndef HB_DEBUG_GET_COVERAGE |
|
223 #define HB_DEBUG_GET_COVERAGE (HB_DEBUG+0) |
|
224 #endif |
|
225 |
194 |
226 /* XXX Can we remove this? */ |
195 /* XXX Can we remove this? */ |
227 |
196 |
228 template <typename set_t> |
197 template <typename set_t> |
229 struct hb_add_coverage_context_t : |
198 struct hb_add_coverage_context_t : |
340 struct skipping_iterator_t |
298 struct skipping_iterator_t |
341 { |
299 { |
342 inline void init (hb_apply_context_t *c_, bool context_match = false) |
300 inline void init (hb_apply_context_t *c_, bool context_match = false) |
343 { |
301 { |
344 c = c_; |
302 c = c_; |
345 match_glyph_data = NULL, |
303 match_glyph_data = nullptr; |
346 matcher.set_match_func (NULL, NULL); |
304 matcher.set_match_func (nullptr, nullptr); |
347 matcher.set_lookup_props (c->lookup_props); |
305 matcher.set_lookup_props (c->lookup_props); |
348 /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */ |
306 /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */ |
349 matcher.set_ignore_zwnj (context_match || c->table_index == 1); |
307 matcher.set_ignore_zwnj (c->table_index == 1 || (context_match && c->auto_zwnj)); |
350 /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */ |
308 /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */ |
351 matcher.set_ignore_zwj (context_match || c->table_index == 1 || c->auto_zwj); |
309 matcher.set_ignore_zwj (c->table_index == 1 || (context_match || c->auto_zwj)); |
352 matcher.set_mask (context_match ? -1 : c->lookup_mask); |
310 matcher.set_mask (context_match ? -1 : c->lookup_mask); |
353 } |
311 } |
354 inline void set_lookup_props (unsigned int lookup_props) |
312 inline void set_lookup_props (unsigned int lookup_props) |
355 { |
313 { |
356 matcher.set_lookup_props (lookup_props); |
314 matcher.set_lookup_props (lookup_props); |
455 bool ret = recurse_func (this, lookup_index); |
420 bool ret = recurse_func (this, lookup_index); |
456 nesting_level_left++; |
421 nesting_level_left++; |
457 return ret; |
422 return ret; |
458 } |
423 } |
459 |
424 |
460 unsigned int table_index; /* GSUB/GPOS */ |
425 skipping_iterator_t iter_input, iter_context; |
|
426 |
461 hb_font_t *font; |
427 hb_font_t *font; |
462 hb_face_t *face; |
428 hb_face_t *face; |
463 hb_buffer_t *buffer; |
429 hb_buffer_t *buffer; |
|
430 recurse_func_t recurse_func; |
|
431 const GDEF &gdef; |
|
432 const VariationStore &var_store; |
|
433 |
464 hb_direction_t direction; |
434 hb_direction_t direction; |
465 hb_mask_t lookup_mask; |
435 hb_mask_t lookup_mask; |
|
436 unsigned int table_index; /* GSUB/GPOS */ |
|
437 unsigned int lookup_index; |
|
438 unsigned int lookup_props; |
|
439 unsigned int nesting_level_left; |
|
440 unsigned int debug_depth; |
|
441 |
|
442 bool auto_zwnj; |
466 bool auto_zwj; |
443 bool auto_zwj; |
467 recurse_func_t recurse_func; |
|
468 unsigned int nesting_level_left; |
|
469 unsigned int lookup_props; |
|
470 const GDEF &gdef; |
|
471 bool has_glyph_classes; |
444 bool has_glyph_classes; |
472 const VariationStore &var_store; |
|
473 skipping_iterator_t iter_input, iter_context; |
|
474 unsigned int lookup_index; |
|
475 unsigned int debug_depth; |
|
476 |
445 |
477 |
446 |
478 hb_apply_context_t (unsigned int table_index_, |
447 hb_apply_context_t (unsigned int table_index_, |
479 hb_font_t *font_, |
448 hb_font_t *font_, |
480 hb_buffer_t *buffer_) : |
449 hb_buffer_t *buffer_) : |
481 table_index (table_index_), |
450 iter_input (), iter_context (), |
482 font (font_), face (font->face), buffer (buffer_), |
451 font (font_), face (font->face), buffer (buffer_), |
|
452 recurse_func (nullptr), |
|
453 gdef (*hb_ot_layout_from_face (face)->gdef), |
|
454 var_store (gdef.get_var_store ()), |
483 direction (buffer_->props.direction), |
455 direction (buffer_->props.direction), |
484 lookup_mask (1), |
456 lookup_mask (1), |
|
457 table_index (table_index_), |
|
458 lookup_index ((unsigned int) -1), |
|
459 lookup_props (0), |
|
460 nesting_level_left (HB_MAX_NESTING_LEVEL), |
|
461 debug_depth (0), |
|
462 auto_zwnj (true), |
485 auto_zwj (true), |
463 auto_zwj (true), |
486 recurse_func (NULL), |
464 has_glyph_classes (gdef.has_glyph_classes ()) {} |
487 nesting_level_left (HB_MAX_NESTING_LEVEL), |
|
488 lookup_props (0), |
|
489 gdef (*hb_ot_layout_from_face (face)->gdef), |
|
490 has_glyph_classes (gdef.has_glyph_classes ()), |
|
491 var_store (gdef.get_var_store ()), |
|
492 iter_input (), |
|
493 iter_context (), |
|
494 lookup_index ((unsigned int) -1), |
|
495 debug_depth (0) {} |
|
496 |
465 |
497 inline void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; } |
466 inline void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; } |
498 inline void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; } |
467 inline void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; } |
|
468 inline void set_auto_zwnj (bool auto_zwnj_) { auto_zwnj = auto_zwnj_; } |
499 inline void set_recurse_func (recurse_func_t func) { recurse_func = func; } |
469 inline void set_recurse_func (recurse_func_t func) { recurse_func = func; } |
500 inline void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; } |
470 inline void set_lookup_index (unsigned int lookup_index_) { lookup_index = lookup_index_; } |
501 inline void set_lookup_props (unsigned int lookup_props_) |
471 inline void set_lookup_props (unsigned int lookup_props_) |
502 { |
472 { |
503 lookup_props = lookup_props_; |
473 lookup_props = lookup_props_; |
705 const USHORT input[], /* Array of input values--start with second glyph */ |
675 const USHORT input[], /* Array of input values--start with second glyph */ |
706 match_func_t match_func, |
676 match_func_t match_func, |
707 const void *match_data, |
677 const void *match_data, |
708 unsigned int *end_offset, |
678 unsigned int *end_offset, |
709 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], |
679 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], |
710 bool *p_is_mark_ligature = NULL, |
680 bool *p_is_mark_ligature = nullptr, |
711 unsigned int *p_total_component_count = NULL) |
681 unsigned int *p_total_component_count = nullptr) |
712 { |
682 { |
713 TRACE_APPLY (NULL); |
683 TRACE_APPLY (nullptr); |
714 |
684 |
715 if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return_trace (false); |
685 if (unlikely (count > HB_MAX_CONTEXT_LENGTH)) return_trace (false); |
716 |
686 |
717 hb_buffer_t *buffer = c->buffer; |
687 hb_buffer_t *buffer = c->buffer; |
718 |
688 |
729 * it as a ligature glyph. |
699 * it as a ligature glyph. |
730 * |
700 * |
731 * - Ligatures cannot be formed across glyphs attached to different components |
701 * - Ligatures cannot be formed across glyphs attached to different components |
732 * of previous ligatures. Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and |
702 * of previous ligatures. Eg. the sequence is LAM,SHADDA,LAM,FATHA,HEH, and |
733 * LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother. |
703 * LAM,LAM,HEH form a ligature, leaving SHADDA,FATHA next to eachother. |
734 * However, it would be wrong to ligate that SHADDA,FATHA sequence.o |
704 * However, it would be wrong to ligate that SHADDA,FATHA sequence. |
735 * There is an exception to this: If a ligature tries ligating with marks that |
705 * There are a couple of exceptions to this: |
736 * belong to it itself, go ahead, assuming that the font designer knows what |
706 * |
737 * they are doing (otherwise it can break Indic stuff when a matra wants to |
707 * o If a ligature tries ligating with marks that belong to it itself, go ahead, |
738 * ligate with a conjunct...) |
708 * assuming that the font designer knows what they are doing (otherwise it can |
|
709 * break Indic stuff when a matra wants to ligate with a conjunct, |
|
710 * |
|
711 * o If two marks want to ligate and they belong to different components of the |
|
712 * same ligature glyph, and said ligature glyph is to be ignored according to |
|
713 * mark-filtering rules, then allow. |
|
714 * https://github.com/behdad/harfbuzz/issues/545 |
739 */ |
715 */ |
740 |
716 |
741 bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->cur()); |
717 bool is_mark_ligature = _hb_glyph_info_is_mark (&buffer->cur()); |
742 |
718 |
743 unsigned int total_component_count = 0; |
719 unsigned int total_component_count = 0; |
744 total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur()); |
720 total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->cur()); |
745 |
721 |
746 unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur()); |
722 unsigned int first_lig_id = _hb_glyph_info_get_lig_id (&buffer->cur()); |
747 unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur()); |
723 unsigned int first_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->cur()); |
748 |
724 |
|
725 enum { |
|
726 LIGBASE_NOT_CHECKED, |
|
727 LIGBASE_MAY_NOT_SKIP, |
|
728 LIGBASE_MAY_SKIP |
|
729 } ligbase = LIGBASE_NOT_CHECKED; |
|
730 |
749 match_positions[0] = buffer->idx; |
731 match_positions[0] = buffer->idx; |
750 for (unsigned int i = 1; i < count; i++) |
732 for (unsigned int i = 1; i < count; i++) |
751 { |
733 { |
752 if (!skippy_iter.next ()) return_trace (false); |
734 if (!skippy_iter.next ()) return_trace (false); |
753 |
735 |
754 match_positions[i] = skippy_iter.idx; |
736 match_positions[i] = skippy_iter.idx; |
755 |
737 |
756 unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]); |
738 unsigned int this_lig_id = _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]); |
757 unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]); |
739 unsigned int this_lig_comp = _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]); |
758 |
740 |
759 if (first_lig_id && first_lig_comp) { |
741 if (first_lig_id && first_lig_comp) |
|
742 { |
760 /* If first component was attached to a previous ligature component, |
743 /* If first component was attached to a previous ligature component, |
761 * all subsequent components should be attached to the same ligature |
744 * all subsequent components should be attached to the same ligature |
762 * component, otherwise we shouldn't ligate them. */ |
745 * component, otherwise we shouldn't ligate them... */ |
763 if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp) |
746 if (first_lig_id != this_lig_id || first_lig_comp != this_lig_comp) |
764 return_trace (false); |
747 { |
765 } else { |
748 /* ...unless, we are attached to a base ligature and that base |
|
749 * ligature is ignorable. */ |
|
750 if (ligbase == LIGBASE_NOT_CHECKED) |
|
751 { |
|
752 bool found = false; |
|
753 const hb_glyph_info_t *out = buffer->out_info; |
|
754 unsigned int j = buffer->out_len; |
|
755 while (j && _hb_glyph_info_get_lig_id (&out[j - 1]) == first_lig_id) |
|
756 { |
|
757 if (_hb_glyph_info_get_lig_comp (&out[j - 1]) == 0) |
|
758 { |
|
759 j--; |
|
760 found = true; |
|
761 break; |
|
762 } |
|
763 j--; |
|
764 } |
|
765 |
|
766 if (found && skippy_iter.may_skip (c, out[j]) == hb_apply_context_t::matcher_t::SKIP_YES) |
|
767 ligbase = LIGBASE_MAY_SKIP; |
|
768 else |
|
769 ligbase = LIGBASE_MAY_NOT_SKIP; |
|
770 } |
|
771 |
|
772 if (ligbase == LIGBASE_MAY_NOT_SKIP) |
|
773 return_trace (false); |
|
774 } |
|
775 } |
|
776 else |
|
777 { |
766 /* If first component was NOT attached to a previous ligature component, |
778 /* If first component was NOT attached to a previous ligature component, |
767 * all subsequent components should also NOT be attached to any ligature |
779 * all subsequent components should also NOT be attached to any ligature |
768 * component, unless they are attached to the first component itself! */ |
780 * component, unless they are attached to the first component itself! */ |
769 if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id)) |
781 if (this_lig_id && this_lig_comp && (this_lig_id != first_lig_id)) |
770 return_trace (false); |
782 return_trace (false); |
884 |
896 |
885 static inline bool match_backtrack (hb_apply_context_t *c, |
897 static inline bool match_backtrack (hb_apply_context_t *c, |
886 unsigned int count, |
898 unsigned int count, |
887 const USHORT backtrack[], |
899 const USHORT backtrack[], |
888 match_func_t match_func, |
900 match_func_t match_func, |
889 const void *match_data) |
901 const void *match_data, |
890 { |
902 unsigned int *match_start) |
891 TRACE_APPLY (NULL); |
903 { |
|
904 TRACE_APPLY (nullptr); |
892 |
905 |
893 hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context; |
906 hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context; |
894 skippy_iter.reset (c->buffer->backtrack_len (), count); |
907 skippy_iter.reset (c->buffer->backtrack_len (), count); |
895 skippy_iter.set_match_func (match_func, match_data, backtrack); |
908 skippy_iter.set_match_func (match_func, match_data, backtrack); |
896 |
909 |
897 for (unsigned int i = 0; i < count; i++) |
910 for (unsigned int i = 0; i < count; i++) |
898 if (!skippy_iter.prev ()) |
911 if (!skippy_iter.prev ()) |
899 return_trace (false); |
912 return_trace (false); |
|
913 |
|
914 *match_start = skippy_iter.idx; |
900 |
915 |
901 return_trace (true); |
916 return_trace (true); |
902 } |
917 } |
903 |
918 |
904 static inline bool match_lookahead (hb_apply_context_t *c, |
919 static inline bool match_lookahead (hb_apply_context_t *c, |
905 unsigned int count, |
920 unsigned int count, |
906 const USHORT lookahead[], |
921 const USHORT lookahead[], |
907 match_func_t match_func, |
922 match_func_t match_func, |
908 const void *match_data, |
923 const void *match_data, |
909 unsigned int offset) |
924 unsigned int offset, |
910 { |
925 unsigned int *end_index) |
911 TRACE_APPLY (NULL); |
926 { |
|
927 TRACE_APPLY (nullptr); |
912 |
928 |
913 hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context; |
929 hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context; |
914 skippy_iter.reset (c->buffer->idx + offset - 1, count); |
930 skippy_iter.reset (c->buffer->idx + offset - 1, count); |
915 skippy_iter.set_match_func (match_func, match_data, lookahead); |
931 skippy_iter.set_match_func (match_func, match_data, lookahead); |
916 |
932 |
917 for (unsigned int i = 0; i < count; i++) |
933 for (unsigned int i = 0; i < count; i++) |
918 if (!skippy_iter.next ()) |
934 if (!skippy_iter.next ()) |
919 return_trace (false); |
935 return_trace (false); |
|
936 |
|
937 *end_index = skippy_iter.idx + 1; |
920 |
938 |
921 return_trace (true); |
939 return_trace (true); |
922 } |
940 } |
923 |
941 |
924 |
942 |
994 int delta = new_len - orig_len; |
1012 int delta = new_len - orig_len; |
995 |
1013 |
996 if (!delta) |
1014 if (!delta) |
997 continue; |
1015 continue; |
998 |
1016 |
999 /* Recursed lookup changed buffer len. Adjust. */ |
1017 /* Recursed lookup changed buffer len. Adjust. |
1000 |
1018 * |
1001 end = int (end) + delta; |
1019 * TODO: |
1002 if (end <= match_positions[idx]) |
1020 * |
|
1021 * Right now, if buffer length increased by n, we assume n new glyphs |
|
1022 * were added right after the current position, and if buffer length |
|
1023 * was decreased by n, we assume n match positions after the current |
|
1024 * one where removed. The former (buffer length increased) case is |
|
1025 * fine, but the decrease case can be improved in at least two ways, |
|
1026 * both of which are significant: |
|
1027 * |
|
1028 * - If recursed-to lookup is MultipleSubst and buffer length |
|
1029 * decreased, then it's current match position that was deleted, |
|
1030 * NOT the one after it. |
|
1031 * |
|
1032 * - If buffer length was decreased by n, it does not necessarily |
|
1033 * mean that n match positions where removed, as there might |
|
1034 * have been marks and default-ignorables in the sequence. We |
|
1035 * should instead drop match positions between current-position |
|
1036 * and current-position + n instead. |
|
1037 * |
|
1038 * It should be possible to construct tests for both of these cases. |
|
1039 */ |
|
1040 |
|
1041 end += delta; |
|
1042 if (end <= int (match_positions[idx])) |
1003 { |
1043 { |
1004 /* End might end up being smaller than match_positions[idx] if the recursed |
1044 /* End might end up being smaller than match_positions[idx] if the recursed |
1005 * lookup ended up removing many items, more than we have had matched. |
1045 * lookup ended up removing many items, more than we have had matched. |
1006 * Just never rewind end back and get out of here. |
1046 * Just never rewind end back and get out of here. |
1007 * https://bugs.chromium.org/p/chromium/issues/detail?id=659496 */ |
1047 * https://bugs.chromium.org/p/chromium/issues/detail?id=659496 */ |
1116 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH]; |
1156 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH]; |
1117 return match_input (c, |
1157 return match_input (c, |
1118 inputCount, input, |
1158 inputCount, input, |
1119 lookup_context.funcs.match, lookup_context.match_data, |
1159 lookup_context.funcs.match, lookup_context.match_data, |
1120 &match_length, match_positions) |
1160 &match_length, match_positions) |
1121 && apply_lookup (c, |
1161 && (c->buffer->unsafe_to_break (c->buffer->idx, c->buffer->idx + match_length), |
|
1162 apply_lookup (c, |
1122 inputCount, match_positions, |
1163 inputCount, match_positions, |
1123 lookupCount, lookupRecord, |
1164 lookupCount, lookupRecord, |
1124 match_length); |
1165 match_length)); |
1125 } |
1166 } |
1126 |
1167 |
1127 struct Rule |
1168 struct Rule |
1128 { |
1169 { |
1129 inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const |
1170 inline void closure (hb_closure_context_t *c, ContextClosureLookupContext &lookup_context) const |
1637 const USHORT lookahead[], |
1678 const USHORT lookahead[], |
1638 unsigned int lookupCount, |
1679 unsigned int lookupCount, |
1639 const LookupRecord lookupRecord[], |
1680 const LookupRecord lookupRecord[], |
1640 ChainContextApplyLookupContext &lookup_context) |
1681 ChainContextApplyLookupContext &lookup_context) |
1641 { |
1682 { |
1642 unsigned int match_length = 0; |
1683 unsigned int start_index = 0, match_length = 0, end_index = 0; |
1643 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH]; |
1684 unsigned int match_positions[HB_MAX_CONTEXT_LENGTH]; |
1644 return match_input (c, |
1685 return match_input (c, |
1645 inputCount, input, |
1686 inputCount, input, |
1646 lookup_context.funcs.match, lookup_context.match_data[1], |
1687 lookup_context.funcs.match, lookup_context.match_data[1], |
1647 &match_length, match_positions) |
1688 &match_length, match_positions) |
1648 && match_backtrack (c, |
1689 && match_backtrack (c, |
1649 backtrackCount, backtrack, |
1690 backtrackCount, backtrack, |
1650 lookup_context.funcs.match, lookup_context.match_data[0]) |
1691 lookup_context.funcs.match, lookup_context.match_data[0], |
|
1692 &start_index) |
1651 && match_lookahead (c, |
1693 && match_lookahead (c, |
1652 lookaheadCount, lookahead, |
1694 lookaheadCount, lookahead, |
1653 lookup_context.funcs.match, lookup_context.match_data[2], |
1695 lookup_context.funcs.match, lookup_context.match_data[2], |
1654 match_length) |
1696 match_length, &end_index) |
1655 && apply_lookup (c, |
1697 && (c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index), |
|
1698 apply_lookup (c, |
1656 inputCount, match_positions, |
1699 inputCount, match_positions, |
1657 lookupCount, lookupRecord, |
1700 lookupCount, lookupRecord, |
1658 match_length); |
1701 match_length)); |
1659 } |
1702 } |
1660 |
1703 |
1661 struct ChainRule |
1704 struct ChainRule |
1662 { |
1705 { |
1663 inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const |
1706 inline void closure (hb_closure_context_t *c, ChainContextClosureLookupContext &lookup_context) const |