77 static const hb_tag_t |
78 static const hb_tag_t |
78 other_features[] = |
79 other_features[] = |
79 { |
80 { |
80 /* |
81 /* |
81 * Other features. |
82 * Other features. |
82 * These features are applied all at once, after reordering. |
83 * These features are applied all at once, after reordering and |
|
84 * clearing syllables. |
83 */ |
85 */ |
84 HB_TAG('a','b','v','s'), |
86 HB_TAG('a','b','v','s'), |
85 HB_TAG('b','l','w','s'), |
87 HB_TAG('b','l','w','s'), |
86 HB_TAG('h','a','l','n'), |
88 HB_TAG('h','a','l','n'), |
87 HB_TAG('p','r','e','s'), |
89 HB_TAG('p','r','e','s'), |
88 HB_TAG('p','s','t','s'), |
90 HB_TAG('p','s','t','s'), |
89 /* Positioning features, though we don't care about the types. */ |
91 }; |
|
92 static const hb_tag_t |
|
93 positioning_features[] = |
|
94 { |
|
95 /* |
|
96 * Positioning features. |
|
97 * We don't care about the types. |
|
98 */ |
90 HB_TAG('d','i','s','t'), |
99 HB_TAG('d','i','s','t'), |
91 HB_TAG('a','b','v','m'), |
100 HB_TAG('a','b','v','m'), |
92 HB_TAG('b','l','w','m'), |
101 HB_TAG('b','l','w','m'), |
93 }; |
102 }; |
94 |
103 |
110 hb_buffer_t *buffer); |
119 hb_buffer_t *buffer); |
111 static void |
120 static void |
112 reorder (const hb_ot_shape_plan_t *plan, |
121 reorder (const hb_ot_shape_plan_t *plan, |
113 hb_font_t *font, |
122 hb_font_t *font, |
114 hb_buffer_t *buffer); |
123 hb_buffer_t *buffer); |
|
124 static void |
|
125 clear_syllables (const hb_ot_shape_plan_t *plan, |
|
126 hb_font_t *font, |
|
127 hb_buffer_t *buffer); |
115 |
128 |
116 static void |
129 static void |
117 collect_features_use (hb_ot_shape_planner_t *plan) |
130 collect_features_use (hb_ot_shape_planner_t *plan) |
118 { |
131 { |
119 hb_ot_map_builder_t *map = &plan->map; |
132 hb_ot_map_builder_t *map = &plan->map; |
120 |
133 |
121 /* Do this before any lookups have been applied. */ |
134 /* Do this before any lookups have been applied. */ |
122 map->add_gsub_pause (setup_syllables); |
135 map->add_gsub_pause (setup_syllables); |
123 |
136 |
124 /* "Default glyph pre-processing group" */ |
137 /* "Default glyph pre-processing group" */ |
125 map->add_global_bool_feature (HB_TAG('l','o','c','l')); |
138 map->enable_feature (HB_TAG('l','o','c','l')); |
126 map->add_global_bool_feature (HB_TAG('c','c','m','p')); |
139 map->enable_feature (HB_TAG('c','c','m','p')); |
127 map->add_global_bool_feature (HB_TAG('n','u','k','t')); |
140 map->enable_feature (HB_TAG('n','u','k','t')); |
128 map->add_global_bool_feature (HB_TAG('a','k','h','n')); |
141 map->enable_feature (HB_TAG('a','k','h','n'), F_MANUAL_ZWJ); |
129 |
142 |
130 /* "Reordering group" */ |
143 /* "Reordering group" */ |
131 map->add_gsub_pause (clear_substitution_flags); |
144 map->add_gsub_pause (clear_substitution_flags); |
132 map->add_feature (HB_TAG('r','p','h','f'), 1, F_MANUAL_ZWJ); |
145 map->add_feature (HB_TAG('r','p','h','f'), F_MANUAL_ZWJ); |
133 map->add_gsub_pause (record_rphf); |
146 map->add_gsub_pause (record_rphf); |
134 map->add_gsub_pause (clear_substitution_flags); |
147 map->add_gsub_pause (clear_substitution_flags); |
135 map->add_feature (HB_TAG('p','r','e','f'), 1, F_GLOBAL | F_MANUAL_ZWJ); |
148 map->enable_feature (HB_TAG('p','r','e','f'), F_MANUAL_ZWJ); |
136 map->add_gsub_pause (record_pref); |
149 map->add_gsub_pause (record_pref); |
137 |
150 |
138 /* "Orthographic unit shaping group" */ |
151 /* "Orthographic unit shaping group" */ |
139 for (unsigned int i = 0; i < ARRAY_LENGTH (basic_features); i++) |
152 for (unsigned int i = 0; i < ARRAY_LENGTH (basic_features); i++) |
140 map->add_feature (basic_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ); |
153 map->enable_feature (basic_features[i], F_MANUAL_ZWJ); |
141 |
154 |
142 map->add_gsub_pause (reorder); |
155 map->add_gsub_pause (reorder); |
|
156 map->add_gsub_pause (clear_syllables); |
143 |
157 |
144 /* "Topographical features" */ |
158 /* "Topographical features" */ |
145 for (unsigned int i = 0; i < ARRAY_LENGTH (arabic_features); i++) |
159 for (unsigned int i = 0; i < ARRAY_LENGTH (arabic_features); i++) |
146 map->add_feature (arabic_features[i], 1, F_NONE); |
160 map->add_feature (arabic_features[i]); |
147 map->add_gsub_pause (nullptr); |
161 map->add_gsub_pause (nullptr); |
148 |
162 |
149 /* "Standard typographic presentation" and "Positional feature application" */ |
163 /* "Standard typographic presentation" */ |
150 for (unsigned int i = 0; i < ARRAY_LENGTH (other_features); i++) |
164 for (unsigned int i = 0; i < ARRAY_LENGTH (other_features); i++) |
151 map->add_feature (other_features[i], 1, F_GLOBAL | F_MANUAL_ZWJ); |
165 map->enable_feature (other_features[i], F_MANUAL_ZWJ); |
|
166 |
|
167 /* "Positional feature application" */ |
|
168 for (unsigned int i = 0; i < ARRAY_LENGTH (positioning_features); i++) |
|
169 map->enable_feature (positioning_features[i]); |
152 } |
170 } |
153 |
171 |
154 struct use_shape_plan_t |
172 struct use_shape_plan_t |
155 { |
173 { |
156 ASSERT_POD (); |
|
157 |
|
158 hb_mask_t rphf_mask; |
174 hb_mask_t rphf_mask; |
159 |
175 |
160 arabic_shape_plan_t *arabic_plan; |
176 arabic_shape_plan_t *arabic_plan; |
161 }; |
177 }; |
162 |
178 |
431 0)))) |
448 0)))) |
432 return; |
449 return; |
433 |
450 |
434 hb_glyph_info_t *info = buffer->info; |
451 hb_glyph_info_t *info = buffer->info; |
435 |
452 |
436 #define BASE_FLAGS (FLAG (USE_B) | FLAG (USE_GB)) |
453 #define POST_BASE_FLAGS64 (FLAG64 (USE_FM) | \ |
|
454 FLAG64 (USE_FAbv) | \ |
|
455 FLAG64 (USE_FBlw) | \ |
|
456 FLAG64 (USE_FPst) | \ |
|
457 FLAG64 (USE_MAbv) | \ |
|
458 FLAG64 (USE_MBlw) | \ |
|
459 FLAG64 (USE_MPst) | \ |
|
460 FLAG64 (USE_MPre) | \ |
|
461 FLAG64 (USE_VAbv) | \ |
|
462 FLAG64 (USE_VBlw) | \ |
|
463 FLAG64 (USE_VPst) | \ |
|
464 FLAG64 (USE_VPre) | \ |
|
465 FLAG64 (USE_VMAbv) | \ |
|
466 FLAG64 (USE_VMBlw) | \ |
|
467 FLAG64 (USE_VMPst) | \ |
|
468 FLAG64 (USE_VMPre)) |
437 |
469 |
438 /* Move things forward. */ |
470 /* Move things forward. */ |
439 if (info[start].use_category() == USE_R && end - start > 1) |
471 if (info[start].use_category() == USE_R && end - start > 1) |
440 { |
472 { |
441 /* Got a repha. Reorder it to after first base, before first halant. */ |
473 /* Got a repha. Reorder it towards the end, but before the first post-base |
|
474 * glyph. */ |
442 for (unsigned int i = start + 1; i < end; i++) |
475 for (unsigned int i = start + 1; i < end; i++) |
443 if ((FLAG_UNSAFE (info[i].use_category()) & (BASE_FLAGS)) || is_halant (info[i])) |
476 { |
|
477 bool is_post_base_glyph = (FLAG64_UNSAFE (info[i].use_category()) & POST_BASE_FLAGS64) || |
|
478 is_halant (info[i]); |
|
479 if (is_post_base_glyph || i == end - 1) |
444 { |
480 { |
445 /* If we hit a halant, move before it; otherwise it's a base: move to it's |
481 /* If we hit a post-base glyph, move before it; otherwise move to the |
446 * place, and shift things in between backward. */ |
482 * end. Shift things in between backward. */ |
447 |
483 |
448 if (is_halant (info[i])) |
484 if (is_post_base_glyph) |
449 i--; |
485 i--; |
450 |
486 |
451 buffer->merge_clusters (start, i + 1); |
487 buffer->merge_clusters (start, i + 1); |
452 hb_glyph_info_t t = info[start]; |
488 hb_glyph_info_t t = info[start]; |
453 memmove (&info[start], &info[start + 1], (i - start) * sizeof (info[0])); |
489 memmove (&info[start], &info[start + 1], (i - start) * sizeof (info[0])); |
454 info[i] = t; |
490 info[i] = t; |
455 |
491 |
456 break; |
492 break; |
457 } |
493 } |
|
494 } |
458 } |
495 } |
459 |
496 |
460 /* Move things back. */ |
497 /* Move things back. */ |
461 unsigned int j = end; |
498 unsigned int j = start; |
462 for (unsigned int i = start; i < end; i++) |
499 for (unsigned int i = start; i < end; i++) |
463 { |
500 { |
464 uint32_t flag = FLAG_UNSAFE (info[i].use_category()); |
501 uint32_t flag = FLAG_UNSAFE (info[i].use_category()); |
465 if ((flag & (BASE_FLAGS)) || is_halant (info[i])) |
502 if (is_halant (info[i])) |
466 { |
503 { |
467 /* If we hit a halant, move after it; otherwise it's a base: move to it's |
504 /* If we hit a halant, move after it; otherwise move to the beginning, and |
468 * place, and shift things in between backward. */ |
505 * shift things in between forward. */ |
469 if (is_halant (info[i])) |
506 j = i + 1; |
470 j = i + 1; |
|
471 else |
|
472 j = i; |
|
473 } |
507 } |
474 else if (((flag) & (FLAG (USE_VPre) | FLAG (USE_VMPre))) && |
508 else if (((flag) & (FLAG (USE_VPre) | FLAG (USE_VMPre))) && |
475 /* Only move the first component of a MultipleSubst. */ |
509 /* Only move the first component of a MultipleSubst. */ |
476 0 == _hb_glyph_info_get_lig_comp (&info[i]) && |
510 0 == _hb_glyph_info_get_lig_comp (&info[i]) && |
477 j < i) |
511 j < i) |
534 buffer->output_info (ginfo); |
568 buffer->output_info (ginfo); |
535 } |
569 } |
536 else |
570 else |
537 buffer->next_glyph (); |
571 buffer->next_glyph (); |
538 } |
572 } |
539 |
|
540 buffer->swap_buffers (); |
573 buffer->swap_buffers (); |
541 } |
574 } |
542 |
575 |
543 static void |
576 static void |
544 reorder (const hb_ot_shape_plan_t *plan, |
577 reorder (const hb_ot_shape_plan_t *plan, |
545 hb_font_t *font, |
578 hb_font_t *font, |
546 hb_buffer_t *buffer) |
579 hb_buffer_t *buffer) |
547 { |
580 { |
548 insert_dotted_circles (plan, font, buffer); |
581 insert_dotted_circles (plan, font, buffer); |
549 |
582 |
550 hb_glyph_info_t *info = buffer->info; |
|
551 |
|
552 foreach_syllable (buffer, start, end) |
583 foreach_syllable (buffer, start, end) |
553 reorder_syllable (buffer, start, end); |
584 reorder_syllable (buffer, start, end); |
554 |
585 |
555 /* Zero syllables now... */ |
586 HB_BUFFER_DEALLOCATE_VAR (buffer, use_category); |
|
587 } |
|
588 |
|
589 static void |
|
590 clear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED, |
|
591 hb_font_t *font HB_UNUSED, |
|
592 hb_buffer_t *buffer) |
|
593 { |
|
594 hb_glyph_info_t *info = buffer->info; |
556 unsigned int count = buffer->len; |
595 unsigned int count = buffer->len; |
557 for (unsigned int i = 0; i < count; i++) |
596 for (unsigned int i = 0; i < count; i++) |
558 info[i].syllable() = 0; |
597 info[i].syllable() = 0; |
559 |
598 } |
560 HB_BUFFER_DEALLOCATE_VAR (buffer, use_category); |
599 |
561 } |
600 |
562 |
601 static void |
563 static bool |
602 preprocess_text_use (const hb_ot_shape_plan_t *plan, |
564 decompose_use (const hb_ot_shape_normalize_context_t *c, |
603 hb_buffer_t *buffer, |
565 hb_codepoint_t ab, |
604 hb_font_t *font) |
566 hb_codepoint_t *a, |
605 { |
567 hb_codepoint_t *b) |
606 _hb_preprocess_text_vowel_constraints (plan, buffer, font); |
568 { |
|
569 switch (ab) |
|
570 { |
|
571 /* Chakma: |
|
572 * Special case where the Unicode decomp gives matras in the wrong order |
|
573 * for cluster validation. |
|
574 */ |
|
575 case 0x1112Eu : *a = 0x11127u; *b= 0x11131u; return true; |
|
576 case 0x1112Fu : *a = 0x11127u; *b= 0x11132u; return true; |
|
577 } |
|
578 |
|
579 return (bool) c->unicode->decompose (ab, a, b); |
|
580 } |
607 } |
581 |
608 |
582 static bool |
609 static bool |
583 compose_use (const hb_ot_shape_normalize_context_t *c, |
610 compose_use (const hb_ot_shape_normalize_context_t *c, |
584 hb_codepoint_t a, |
611 hb_codepoint_t a, |
597 { |
624 { |
598 collect_features_use, |
625 collect_features_use, |
599 nullptr, /* override_features */ |
626 nullptr, /* override_features */ |
600 data_create_use, |
627 data_create_use, |
601 data_destroy_use, |
628 data_destroy_use, |
602 nullptr, /* preprocess_text */ |
629 preprocess_text_use, |
603 nullptr, /* postprocess_glyphs */ |
630 nullptr, /* postprocess_glyphs */ |
604 HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT, |
631 HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT, |
605 decompose_use, |
632 nullptr, /* decompose */ |
606 compose_use, |
633 compose_use, |
607 setup_masks_use, |
634 setup_masks_use, |
608 nullptr, /* disable_otl */ |
635 HB_TAG_NONE, /* gpos_tag */ |
609 nullptr, /* reorder_marks */ |
636 nullptr, /* reorder_marks */ |
610 HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY, |
637 HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY, |
611 false, /* fallback_position */ |
638 false, /* fallback_position */ |
612 }; |
639 }; |