1use super::buffer::*;
2use super::font_funcs::FontFuncsDispatch;
3use super::ot_map::*;
4use super::ot_shape::*;
5use super::ot_shape_normalize::*;
6use super::ot_shape_plan::hb_ot_shape_plan_t;
7use super::ot_shaper::*;
8use super::ot_shaper_indic::{ot_category_t, ot_position_t};
9use super::ot_shaper_syllabic::*;
10use super::{hb_tag_t, GlyphInfo};
11use crate::hb::ot_shaper_indic::ot_category_t::OT_VPre;
12
13pub const MYANMAR_SHAPER: hb_ot_shaper_t = hb_ot_shaper_t {
14 collect_features: Some(collect_features),
15 override_features: None,
16 create_data: None,
17 preprocess_text: None,
18 postprocess_glyphs: None,
19 normalization_preference: HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
20 decompose: None,
21 compose: None,
22 setup_masks: Some(setup_masks),
23 gpos_tag: None,
24 reorder_marks: None,
25 zero_width_marks: HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY,
26 fallback_position: false,
27};
28
29impl GlyphInfo {
30 declare_buffer_var_alias!(
31 OT_SHAPER_VAR_U8_CATEGORY_VAR,
32 u8,
33 MYANMAR_CATEGORY_VAR,
34 myanmar_category,
35 set_myanmar_category
36 );
37 declare_buffer_var_alias!(
38 OT_SHAPER_VAR_U8_AUXILIARY_VAR,
39 u8,
40 MYANMAR_POSITION_VAR,
41 myanmar_position,
42 set_myanmar_position
43 );
44}
45
46pub const MYANMAR_ZAWGYI_SHAPER: hb_ot_shaper_t = hb_ot_shaper_t {
50 collect_features: None,
51 override_features: None,
52 create_data: None,
53 preprocess_text: None,
54 postprocess_glyphs: None,
55 normalization_preference: HB_OT_SHAPE_NORMALIZATION_MODE_NONE,
56 decompose: None,
57 compose: None,
58 setup_masks: None,
59 gpos_tag: None,
60 reorder_marks: None,
61 zero_width_marks: HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
62 fallback_position: false,
63};
64
65static MYANMAR_FEATURES: &[hb_tag_t] = &[
66 hb_tag_t::new(b"rphf"),
70 hb_tag_t::new(b"pref"),
71 hb_tag_t::new(b"blwf"),
72 hb_tag_t::new(b"pstf"),
73 hb_tag_t::new(b"pres"),
76 hb_tag_t::new(b"abvs"),
77 hb_tag_t::new(b"blws"),
78 hb_tag_t::new(b"psts"),
79];
80
81impl GlyphInfo {
82 fn set_myanmar_properties(&mut self) {
83 let u = self.glyph_id;
84 let (cat, _) = crate::hb::ot_shaper_indic_table::get_categories(u);
85
86 self.set_myanmar_category(cat);
87 }
88}
89
90fn collect_features(planner: &mut hb_ot_shape_planner_t) {
91 planner.ot_map.add_gsub_pause(Some(setup_syllables));
93
94 planner
95 .ot_map
96 .enable_feature(hb_tag_t::new(b"locl"), F_PER_SYLLABLE, 1);
97 planner
100 .ot_map
101 .enable_feature(hb_tag_t::new(b"ccmp"), F_PER_SYLLABLE, 1);
102
103 planner.ot_map.add_gsub_pause(Some(reorder_myanmar));
104
105 for feature in MYANMAR_FEATURES.iter().take(4) {
106 planner
107 .ot_map
108 .enable_feature(*feature, F_MANUAL_ZWJ | F_PER_SYLLABLE, 1);
109 planner.ot_map.add_gsub_pause(None);
110 }
111
112 planner.ot_map.add_gsub_pause(Some(syllabic_clear_var)); for feature in MYANMAR_FEATURES.iter().skip(4) {
115 planner.ot_map.enable_feature(*feature, F_MANUAL_ZWJ, 1);
116 }
117}
118
119fn setup_syllables(
120 _: &hb_ot_shape_plan_t,
121 _: &mut FontFuncsDispatch,
122 buffer: &mut hb_buffer_t,
123) -> bool {
124 buffer.allocate_var(GlyphInfo::SYLLABLE_VAR);
125
126 super::ot_shaper_myanmar_machine::find_syllables_myanmar(buffer);
127
128 let mut start = 0;
129 let mut end = buffer.next_syllable(0);
130 while start < buffer.len {
131 buffer.unsafe_to_break(Some(start), Some(end));
132 start = end;
133 end = buffer.next_syllable(start);
134 }
135
136 false
137}
138
139fn reorder_myanmar(
140 _: &hb_ot_shape_plan_t,
141 face: &mut FontFuncsDispatch,
142 buffer: &mut hb_buffer_t,
143) -> bool {
144 use super::ot_shaper_myanmar_machine::SyllableType;
145
146 let mut ret = false;
147
148 if insert_dotted_circles(
149 face,
150 buffer,
151 SyllableType::BrokenCluster as u8,
152 ot_category_t::OT_DOTTEDCIRCLE,
153 None,
154 None,
155 ) {
156 ret = true;
157 }
158
159 let mut start = 0;
160 let mut end = buffer.next_syllable(0);
161 while start < buffer.len {
162 reorder_syllable_myanmar(start, end, buffer);
163 start = end;
164 end = buffer.next_syllable(start);
165 }
166
167 buffer.deallocate_var(GlyphInfo::MYANMAR_CATEGORY_VAR);
168 buffer.deallocate_var(GlyphInfo::MYANMAR_POSITION_VAR);
169
170 ret
171}
172
173fn reorder_syllable_myanmar(start: usize, end: usize, buffer: &mut hb_buffer_t) {
174 use super::ot_shaper_myanmar_machine::SyllableType;
175
176 let syllable_type = match buffer.info[start].syllable() & 0x0F {
177 0 => SyllableType::ConsonantSyllable,
178 1 => SyllableType::PunctuationCluster,
179 2 => SyllableType::BrokenCluster,
180 3 => SyllableType::NonMyanmarCluster,
181 _ => unreachable!(),
182 };
183
184 match syllable_type {
185 SyllableType::ConsonantSyllable | SyllableType::BrokenCluster => {
187 initial_reordering_consonant_syllable(start, end, buffer);
188 }
189 SyllableType::PunctuationCluster | SyllableType::NonMyanmarCluster => {}
190 }
191}
192
193fn initial_reordering_consonant_syllable(start: usize, end: usize, buffer: &mut hb_buffer_t) {
196 let mut base = end;
197 let mut has_reph = false;
198
199 {
200 let mut limit = start;
201 if start + 3 <= end
202 && buffer.info[start + 0].myanmar_category() == ot_category_t::OT_Ra
203 && buffer.info[start + 1].myanmar_category() == ot_category_t::OT_As
204 && buffer.info[start + 2].myanmar_category() == ot_category_t::OT_H
205 {
206 limit += 3;
207 base = start;
208 has_reph = true;
209 }
210
211 {
212 if !has_reph {
213 base = limit;
214 }
215
216 for i in limit..end {
217 if buffer.info[i].is_consonant() {
218 base = i;
219 break;
220 }
221 }
222 }
223 }
224
225 {
227 let mut i = start;
228 while i < start + if has_reph { 3 } else { 0 } {
229 buffer.info[i].set_myanmar_position(ot_position_t::POS_AFTER_MAIN);
230 i += 1;
231 }
232
233 while i < base {
234 buffer.info[i].set_myanmar_position(ot_position_t::POS_PRE_C);
235 i += 1;
236 }
237
238 if i < end {
239 buffer.info[i].set_myanmar_position(ot_position_t::POS_BASE_C);
240 i += 1;
241 }
242
243 let mut pos = ot_position_t::POS_AFTER_MAIN;
244 for i in i..end {
247 if buffer.info[i].myanmar_category() == ot_category_t::OT_MR {
249 buffer.info[i].set_myanmar_position(ot_position_t::POS_PRE_C);
250 continue;
251 }
252
253 if buffer.info[i].myanmar_category() == OT_VPre {
255 buffer.info[i].set_myanmar_position(ot_position_t::POS_PRE_M);
256 continue;
257 }
258
259 if buffer.info[i].myanmar_category() == ot_category_t::OT_VS {
260 let t = buffer.info[i - 1].myanmar_position();
261 buffer.info[i].set_myanmar_position(t);
262 continue;
263 }
264
265 if pos == ot_position_t::POS_AFTER_MAIN
266 && buffer.info[i].myanmar_category() == ot_category_t::OT_VBlw
267 {
268 pos = ot_position_t::POS_BELOW_C;
269 buffer.info[i].set_myanmar_position(pos);
270 continue;
271 }
272
273 if pos == ot_position_t::POS_BELOW_C
274 && buffer.info[i].myanmar_category() == ot_category_t::OT_A
275 {
276 buffer.info[i].set_myanmar_position(ot_position_t::POS_BEFORE_SUB);
277 continue;
278 }
279
280 if pos == ot_position_t::POS_BELOW_C
281 && buffer.info[i].myanmar_category() == ot_category_t::OT_VBlw
282 {
283 buffer.info[i].set_myanmar_position(pos);
284 continue;
285 }
286
287 if pos == ot_position_t::POS_BELOW_C
288 && buffer.info[i].myanmar_category() != ot_category_t::OT_A
289 {
290 pos = ot_position_t::POS_AFTER_SUB;
291 buffer.info[i].set_myanmar_position(pos);
292 continue;
293 }
294
295 buffer.info[i].set_myanmar_position(pos);
296 }
297 }
298
299 buffer.sort(start, end, |a, b| {
300 a.myanmar_position().cmp(&b.myanmar_position()) == core::cmp::Ordering::Greater
301 });
302
303 let mut first_left_matra = end;
305 let mut last_left_matra = end;
306
307 for i in start..end {
308 if buffer.info[i].myanmar_position() == ot_position_t::POS_PRE_M {
309 if first_left_matra == end {
310 first_left_matra = i;
311 }
312
313 last_left_matra = i;
314 }
315 }
316
317 if first_left_matra < last_left_matra {
319 buffer.reverse_range(first_left_matra, last_left_matra + 1);
321 let mut i = first_left_matra;
323
324 for j in i..=last_left_matra {
325 if buffer.info[j].myanmar_category() == OT_VPre {
326 buffer.reverse_range(i, j + 1);
327 i = j + 1;
328 }
329 }
330 }
331}
332
333fn setup_masks(_: &hb_ot_shape_plan_t, _: &mut FontFuncsDispatch, buffer: &mut hb_buffer_t) {
334 buffer.allocate_var(GlyphInfo::MYANMAR_CATEGORY_VAR);
335 buffer.allocate_var(GlyphInfo::MYANMAR_POSITION_VAR);
336
337 for info in buffer.info_slice_mut() {
339 info.set_myanmar_properties();
340 }
341}