harfrust/hb/
ot_shaper_hebrew.rs1use super::ot_shape_normalize::*;
2use super::ot_shaper::*;
3use super::{hb_tag_t, unicode};
4use crate::hb::buffer::hb_buffer_t;
5use crate::hb::ot_shape_plan::hb_ot_shape_plan_t;
6use crate::hb::unicode::Codepoint;
7use crate::hb::unicode::{combining_class, modified_combining_class};
8
9pub const HEBREW_SHAPER: hb_ot_shaper_t = hb_ot_shaper_t {
10 collect_features: None,
11 override_features: None,
12 create_data: None,
13 preprocess_text: None,
14 postprocess_glyphs: None,
15 normalization_preference: HB_OT_SHAPE_NORMALIZATION_MODE_AUTO,
16 decompose: None,
17 compose: Some(compose),
18 setup_masks: None,
19 gpos_tag: Some(hb_tag_t::new(b"hebr")),
20 reorder_marks: Some(reorder_marks_hebrew),
21 zero_width_marks: HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_LATE,
22 fallback_position: true,
23};
24
25fn reorder_marks_hebrew(
26 _: &hb_ot_shape_plan_t,
27 buffer: &mut hb_buffer_t,
28 start: usize,
29 end: usize,
30) {
31 for i in start + 2..end {
32 let c0 = buffer.info[i - 2];
33 let c1 = buffer.info[i - 1];
34 let c2 = buffer.info[i - 0];
35
36 if (c0.modified_combining_class() == modified_combining_class::CCC17
37 || c0.modified_combining_class() == modified_combining_class::CCC18) &&
39 (c1.modified_combining_class() == modified_combining_class::CCC10
40 || c1.modified_combining_class() == modified_combining_class::CCC14) &&
41 (c2.modified_combining_class() == modified_combining_class::CCC22
42 || c2.modified_combining_class() == combining_class::Below)
43 {
45 buffer.merge_clusters(i - 1, i + 1);
46 buffer.info.swap(i - 1, i);
47 break;
48 }
49 }
50}
51
52static S_DAGESH_FORMS: &[Codepoint] = &[
53 0xFB30, 0xFB31, 0xFB32, 0xFB33, 0xFB34, 0xFB35, 0xFB36, 0x0000, 0xFB38, 0xFB39, 0xFB3A, 0xFB3B, 0xFB3C, 0x0000, 0xFB3E, 0x0000, 0xFB40, 0xFB41, 0x0000, 0xFB43, 0xFB44, 0x0000, 0xFB46, 0xFB47, 0xFB48, 0xFB49, 0xFB4A, ];
81
82fn compose(ctx: &hb_ot_shape_normalize_context_t, a: Codepoint, b: Codepoint) -> Option<Codepoint> {
83 match unicode::compose(a, b) {
88 Some(c) => Some(c),
89 None if !ctx.plan.has_gpos_mark => {
90 match b {
93 0x05B4 => {
94 match a {
96 0x05D9 => Some(0xFB1D), _ => None,
98 }
99 }
100 0x05B7 => {
101 match a {
103 0x05D9 => Some(0xFB1F), 0x05D0 => Some(0xFB2E), _ => None,
106 }
107 }
108 0x05B8 => {
109 match a {
111 0x05D0 => Some(0xFB2F), _ => None,
113 }
114 }
115 0x05B9 => {
116 match a {
118 0x05D5 => Some(0xFB4B), _ => None,
120 }
121 }
122 0x05BC => {
123 match a {
125 0x05D0..=0x05EA => {
126 let c = S_DAGESH_FORMS[a as usize - 0x05D0];
127 if c != 0 {
128 Some(c)
129 } else {
130 None
131 }
132 }
133 0xFB2A => Some(0xFB2C), 0xFB2B => Some(0xFB2D), _ => None,
136 }
137 }
138 0x05BF => {
139 match a {
141 0x05D1 => Some(0xFB4C), 0x05DB => Some(0xFB4D), 0x05E4 => Some(0xFB4E), _ => None,
145 }
146 }
147 0x05C1 => {
148 match a {
150 0x05E9 => Some(0xFB2A), 0xFB49 => Some(0xFB2C), _ => None,
153 }
154 }
155 0x05C2 => {
156 match a {
158 0x05E9 => Some(0xFB2B), 0xFB49 => Some(0xFB2D), _ => None,
161 }
162 }
163 _ => None,
164 }
165 }
166 None => None,
167 }
168}