1use super::buffer::hb_buffer_t;
2use super::ot_map::*;
3use super::ot_shape::*;
4use super::ot_shape_complex::*;
5use super::ot_shape_complex_indic::{category, position};
6use super::ot_shape_normalize::*;
7use super::ot_shape_plan::hb_ot_shape_plan_t;
8use super::{hb_font_t, hb_glyph_info_t, hb_tag_t};
9
10pub const MYANMAR_SHAPER: hb_ot_complex_shaper_t = hb_ot_complex_shaper_t {
11 collect_features: Some(collect_features),
12 override_features: None,
13 create_data: None,
14 preprocess_text: None,
15 postprocess_glyphs: None,
16 normalization_preference: HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
17 decompose: None,
18 compose: None,
19 setup_masks: Some(setup_masks),
20 gpos_tag: None,
21 reorder_marks: None,
22 zero_width_marks: HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY,
23 fallback_position: false,
24};
25
26pub const MYANMAR_ZAWGYI_SHAPER: hb_ot_complex_shaper_t = hb_ot_complex_shaper_t {
30 collect_features: None,
31 override_features: None,
32 create_data: None,
33 preprocess_text: None,
34 postprocess_glyphs: None,
35 normalization_preference: HB_OT_SHAPE_NORMALIZATION_MODE_NONE,
36 decompose: None,
37 compose: None,
38 setup_masks: None,
39 gpos_tag: None,
40 reorder_marks: None,
41 zero_width_marks: HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
42 fallback_position: false,
43};
44
45const MYANMAR_FEATURES: &[hb_tag_t] = &[
46 hb_tag_t::from_bytes(b"rphf"),
50 hb_tag_t::from_bytes(b"pref"),
51 hb_tag_t::from_bytes(b"blwf"),
52 hb_tag_t::from_bytes(b"pstf"),
53 hb_tag_t::from_bytes(b"pres"),
56 hb_tag_t::from_bytes(b"abvs"),
57 hb_tag_t::from_bytes(b"blws"),
58 hb_tag_t::from_bytes(b"psts"),
59];
60
61impl hb_glyph_info_t {
62 fn set_myanmar_properties(&mut self) {
63 let u = self.glyph_id;
64 let (mut cat, mut pos) = crate::hb::ot_shape_complex_indic::get_category_and_position(u);
65
66 if (0xFE00..=0xFE0F).contains(&u) {
70 cat = category::VS;
71 }
72
73 match u {
74 0x104E => cat = category::C,
76
77 0x002D | 0x00A0 | 0x00D7 | 0x2012 | 0x2013 | 0x2014 | 0x2015 | 0x2022 | 0x25CC
78 | 0x25FB | 0x25FC | 0x25FD | 0x25FE => cat = category::PLACEHOLDER,
79
80 0x1004 | 0x101B | 0x105A => cat = category::RA,
81
82 0x1032 | 0x1036 => cat = category::A,
83
84 0x1039 => cat = category::H,
85
86 0x103A => cat = category::SYMBOL,
87
88 0x1041 | 0x1042 | 0x1043 | 0x1044 | 0x1045 | 0x1046 | 0x1047 | 0x1048 | 0x1049
89 | 0x1090 | 0x1091 | 0x1092 | 0x1093 | 0x1094 | 0x1095 | 0x1096 | 0x1097 | 0x1098
90 | 0x1099 => cat = category::D,
91
92 0x1040 => cat = category::D,
94
95 0x103E => cat = category::X_GROUP,
96
97 0x1060 => cat = category::ML,
98
99 0x103C => cat = category::Y_GROUP,
100
101 0x103D | 0x1082 => cat = category::MW,
102
103 0x103B | 0x105E | 0x105F => cat = category::MY,
104
105 0x1063 | 0x1064 | 0x1069 | 0x106A | 0x106B | 0x106C | 0x106D | 0xAA7B => {
106 cat = category::PT
107 }
108
109 0x1038 | 0x1087 | 0x1088 | 0x1089 | 0x108A | 0x108B | 0x108C | 0x108D | 0x108F
110 | 0x109A | 0x109B | 0x109C => cat = category::SM,
111
112 0x104A | 0x104B => cat = category::P,
113
114 0xAA74 | 0xAA75 | 0xAA76 => cat = category::C,
116
117 _ => {}
118 }
119
120 if cat == category::M {
123 match pos {
124 position::PRE_C => {
125 cat = category::V_PRE;
126 pos = position::PRE_M;
127 }
128 position::BELOW_C => cat = category::V_BLW,
129 position::ABOVE_C => cat = category::V_AVB,
130 position::POST_C => cat = category::V_PST,
131 _ => {}
132 }
133 }
134
135 self.set_indic_category(cat);
136 self.set_indic_position(pos);
137 }
138}
139
140fn collect_features(planner: &mut hb_ot_shape_planner_t) {
141 planner.ot_map.add_gsub_pause(Some(setup_syllables));
143
144 planner
145 .ot_map
146 .enable_feature(hb_tag_t::from_bytes(b"locl"), F_PER_SYLLABLE, 1);
147 planner
150 .ot_map
151 .enable_feature(hb_tag_t::from_bytes(b"ccmp"), F_PER_SYLLABLE, 1);
152
153 planner.ot_map.add_gsub_pause(Some(reorder));
154
155 for feature in MYANMAR_FEATURES.iter().take(4) {
156 planner.ot_map.enable_feature(*feature, F_MANUAL_ZWJ, 1);
157 planner.ot_map.add_gsub_pause(None);
158 }
159
160 for feature in MYANMAR_FEATURES.iter().skip(4) {
161 planner
162 .ot_map
163 .enable_feature(*feature, F_MANUAL_ZWJ | F_PER_SYLLABLE, 1);
164 }
165}
166
167fn setup_syllables(_: &hb_ot_shape_plan_t, _: &hb_font_t, buffer: &mut hb_buffer_t) {
168 super::ot_shape_complex_myanmar_machine::find_syllables_myanmar(buffer);
169
170 let mut start = 0;
171 let mut end = buffer.next_syllable(0);
172 while start < buffer.len {
173 buffer.unsafe_to_break(Some(start), Some(end));
174 start = end;
175 end = buffer.next_syllable(start);
176 }
177}
178
179fn reorder(_: &hb_ot_shape_plan_t, face: &hb_font_t, buffer: &mut hb_buffer_t) {
180 use super::ot_shape_complex_myanmar_machine::SyllableType;
181
182 super::ot_shape_complex_syllabic::insert_dotted_circles(
183 face,
184 buffer,
185 SyllableType::BrokenCluster as u8,
186 category::PLACEHOLDER,
187 None,
188 None,
189 );
190
191 let mut start = 0;
192 let mut end = buffer.next_syllable(0);
193 while start < buffer.len {
194 reorder_syllable(start, end, buffer);
195 start = end;
196 end = buffer.next_syllable(start);
197 }
198}
199
200fn reorder_syllable(start: usize, end: usize, buffer: &mut hb_buffer_t) {
201 use super::ot_shape_complex_myanmar_machine::SyllableType;
202
203 let syllable_type = match buffer.info[start].syllable() & 0x0F {
204 0 => SyllableType::ConsonantSyllable,
205 1 => SyllableType::PunctuationCluster,
206 2 => SyllableType::BrokenCluster,
207 3 => SyllableType::NonMyanmarCluster,
208 _ => unreachable!(),
209 };
210
211 match syllable_type {
212 SyllableType::ConsonantSyllable | SyllableType::BrokenCluster => {
214 initial_reordering_consonant_syllable(start, end, buffer);
215 }
216 SyllableType::PunctuationCluster | SyllableType::NonMyanmarCluster => {}
217 }
218}
219
220fn initial_reordering_consonant_syllable(start: usize, end: usize, buffer: &mut hb_buffer_t) {
223 let mut base = end;
224 let mut has_reph = false;
225
226 {
227 let mut limit = start;
228 if start + 3 <= end
229 && buffer.info[start + 0].indic_category() == category::RA
230 && buffer.info[start + 1].indic_category() == category::SYMBOL
231 && buffer.info[start + 2].indic_category() == category::H
232 {
233 limit += 3;
234 base = start;
235 has_reph = true;
236 }
237
238 {
239 if !has_reph {
240 base = limit;
241 }
242
243 for i in limit..end {
244 if buffer.info[i].is_consonant() {
245 base = i;
246 break;
247 }
248 }
249 }
250 }
251
252 {
254 let mut i = start;
255 while i < start + if has_reph { 3 } else { 0 } {
256 buffer.info[i].set_indic_position(position::AFTER_MAIN);
257 i += 1;
258 }
259
260 while i < base {
261 buffer.info[i].set_indic_position(position::PRE_C);
262 i += 1;
263 }
264
265 if i < end {
266 buffer.info[i].set_indic_position(position::BASE_C);
267 i += 1;
268 }
269
270 let mut pos = position::AFTER_MAIN;
271 for i in i..end {
274 if buffer.info[i].indic_category() == category::Y_GROUP {
276 buffer.info[i].set_indic_position(position::PRE_C);
277 continue;
278 }
279
280 if buffer.info[i].indic_position() < position::BASE_C {
282 continue;
283 }
284
285 if buffer.info[i].indic_category() == category::VS {
286 let t = buffer.info[i - 1].indic_position();
287 buffer.info[i].set_indic_position(t);
288 continue;
289 }
290
291 if pos == position::AFTER_MAIN && buffer.info[i].indic_category() == category::V_BLW {
292 pos = position::BELOW_C;
293 buffer.info[i].set_indic_position(pos);
294 continue;
295 }
296
297 if pos == position::BELOW_C && buffer.info[i].indic_category() == category::A {
298 buffer.info[i].set_indic_position(position::BEFORE_SUB);
299 continue;
300 }
301
302 if pos == position::BELOW_C && buffer.info[i].indic_category() == category::V_BLW {
303 buffer.info[i].set_indic_position(pos);
304 continue;
305 }
306
307 if pos == position::BELOW_C && buffer.info[i].indic_category() != category::A {
308 pos = position::AFTER_SUB;
309 buffer.info[i].set_indic_position(pos);
310 continue;
311 }
312
313 buffer.info[i].set_indic_position(pos);
314 }
315 }
316
317 buffer.sort(start, end, |a, b| {
318 a.indic_position().cmp(&b.indic_position()) == core::cmp::Ordering::Greater
319 });
320}
321
322fn setup_masks(_: &hb_ot_shape_plan_t, _: &hb_font_t, buffer: &mut hb_buffer_t) {
323 for info in buffer.info_slice_mut() {
325 info.set_myanmar_properties();
326 }
327}