xref: /aosp_15_r20/external/harfbuzz_ng/src/hb-ot-shaper-myanmar.cc (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
1*2d1272b8SAndroid Build Coastguard Worker /*
2*2d1272b8SAndroid Build Coastguard Worker  * Copyright © 2011,2012,2013  Google, Inc.
3*2d1272b8SAndroid Build Coastguard Worker  *
4*2d1272b8SAndroid Build Coastguard Worker  *  This is part of HarfBuzz, a text shaping library.
5*2d1272b8SAndroid Build Coastguard Worker  *
6*2d1272b8SAndroid Build Coastguard Worker  * Permission is hereby granted, without written agreement and without
7*2d1272b8SAndroid Build Coastguard Worker  * license or royalty fees, to use, copy, modify, and distribute this
8*2d1272b8SAndroid Build Coastguard Worker  * software and its documentation for any purpose, provided that the
9*2d1272b8SAndroid Build Coastguard Worker  * above copyright notice and the following two paragraphs appear in
10*2d1272b8SAndroid Build Coastguard Worker  * all copies of this software.
11*2d1272b8SAndroid Build Coastguard Worker  *
12*2d1272b8SAndroid Build Coastguard Worker  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13*2d1272b8SAndroid Build Coastguard Worker  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14*2d1272b8SAndroid Build Coastguard Worker  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15*2d1272b8SAndroid Build Coastguard Worker  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16*2d1272b8SAndroid Build Coastguard Worker  * DAMAGE.
17*2d1272b8SAndroid Build Coastguard Worker  *
18*2d1272b8SAndroid Build Coastguard Worker  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19*2d1272b8SAndroid Build Coastguard Worker  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20*2d1272b8SAndroid Build Coastguard Worker  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
21*2d1272b8SAndroid Build Coastguard Worker  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22*2d1272b8SAndroid Build Coastguard Worker  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23*2d1272b8SAndroid Build Coastguard Worker  *
24*2d1272b8SAndroid Build Coastguard Worker  * Google Author(s): Behdad Esfahbod
25*2d1272b8SAndroid Build Coastguard Worker  */
26*2d1272b8SAndroid Build Coastguard Worker 
27*2d1272b8SAndroid Build Coastguard Worker #include "hb.hh"
28*2d1272b8SAndroid Build Coastguard Worker 
29*2d1272b8SAndroid Build Coastguard Worker #ifndef HB_NO_OT_SHAPE
30*2d1272b8SAndroid Build Coastguard Worker 
31*2d1272b8SAndroid Build Coastguard Worker #include "hb-ot-shaper-myanmar-machine.hh"
32*2d1272b8SAndroid Build Coastguard Worker #include "hb-ot-shaper-indic.hh"
33*2d1272b8SAndroid Build Coastguard Worker #include "hb-ot-layout.hh"
34*2d1272b8SAndroid Build Coastguard Worker 
35*2d1272b8SAndroid Build Coastguard Worker 
36*2d1272b8SAndroid Build Coastguard Worker /*
37*2d1272b8SAndroid Build Coastguard Worker  * Myanmar shaper.
38*2d1272b8SAndroid Build Coastguard Worker  */
39*2d1272b8SAndroid Build Coastguard Worker 
40*2d1272b8SAndroid Build Coastguard Worker 
41*2d1272b8SAndroid Build Coastguard Worker static const hb_tag_t
42*2d1272b8SAndroid Build Coastguard Worker myanmar_basic_features[] =
43*2d1272b8SAndroid Build Coastguard Worker {
44*2d1272b8SAndroid Build Coastguard Worker   /*
45*2d1272b8SAndroid Build Coastguard Worker    * Basic features.
46*2d1272b8SAndroid Build Coastguard Worker    * These features are applied in order, one at a time, after reordering,
47*2d1272b8SAndroid Build Coastguard Worker    * constrained to the syllable.
48*2d1272b8SAndroid Build Coastguard Worker    */
49*2d1272b8SAndroid Build Coastguard Worker   HB_TAG('r','p','h','f'),
50*2d1272b8SAndroid Build Coastguard Worker   HB_TAG('p','r','e','f'),
51*2d1272b8SAndroid Build Coastguard Worker   HB_TAG('b','l','w','f'),
52*2d1272b8SAndroid Build Coastguard Worker   HB_TAG('p','s','t','f'),
53*2d1272b8SAndroid Build Coastguard Worker };
54*2d1272b8SAndroid Build Coastguard Worker static const hb_tag_t
55*2d1272b8SAndroid Build Coastguard Worker myanmar_other_features[] =
56*2d1272b8SAndroid Build Coastguard Worker {
57*2d1272b8SAndroid Build Coastguard Worker   /*
58*2d1272b8SAndroid Build Coastguard Worker    * Other features.
59*2d1272b8SAndroid Build Coastguard Worker    * These features are applied all at once, after clearing syllables.
60*2d1272b8SAndroid Build Coastguard Worker    */
61*2d1272b8SAndroid Build Coastguard Worker   HB_TAG('p','r','e','s'),
62*2d1272b8SAndroid Build Coastguard Worker   HB_TAG('a','b','v','s'),
63*2d1272b8SAndroid Build Coastguard Worker   HB_TAG('b','l','w','s'),
64*2d1272b8SAndroid Build Coastguard Worker   HB_TAG('p','s','t','s'),
65*2d1272b8SAndroid Build Coastguard Worker };
66*2d1272b8SAndroid Build Coastguard Worker 
67*2d1272b8SAndroid Build Coastguard Worker static inline void
set_myanmar_properties(hb_glyph_info_t & info)68*2d1272b8SAndroid Build Coastguard Worker set_myanmar_properties (hb_glyph_info_t &info)
69*2d1272b8SAndroid Build Coastguard Worker {
70*2d1272b8SAndroid Build Coastguard Worker   hb_codepoint_t u = info.codepoint;
71*2d1272b8SAndroid Build Coastguard Worker   unsigned int type = hb_indic_get_categories (u);
72*2d1272b8SAndroid Build Coastguard Worker 
73*2d1272b8SAndroid Build Coastguard Worker   info.myanmar_category() = (myanmar_category_t) (type & 0xFFu);
74*2d1272b8SAndroid Build Coastguard Worker }
75*2d1272b8SAndroid Build Coastguard Worker 
76*2d1272b8SAndroid Build Coastguard Worker 
77*2d1272b8SAndroid Build Coastguard Worker static inline bool
is_one_of_myanmar(const hb_glyph_info_t & info,unsigned int flags)78*2d1272b8SAndroid Build Coastguard Worker is_one_of_myanmar (const hb_glyph_info_t &info, unsigned int flags)
79*2d1272b8SAndroid Build Coastguard Worker {
80*2d1272b8SAndroid Build Coastguard Worker   /* If it ligated, all bets are off. */
81*2d1272b8SAndroid Build Coastguard Worker   if (_hb_glyph_info_ligated (&info)) return false;
82*2d1272b8SAndroid Build Coastguard Worker   return !!(FLAG_UNSAFE (info.myanmar_category()) & flags);
83*2d1272b8SAndroid Build Coastguard Worker }
84*2d1272b8SAndroid Build Coastguard Worker 
85*2d1272b8SAndroid Build Coastguard Worker /* Note:
86*2d1272b8SAndroid Build Coastguard Worker  *
87*2d1272b8SAndroid Build Coastguard Worker  * We treat Vowels and placeholders as if they were consonants.  This is safe because Vowels
88*2d1272b8SAndroid Build Coastguard Worker  * cannot happen in a consonant syllable.  The plus side however is, we can call the
89*2d1272b8SAndroid Build Coastguard Worker  * consonant syllable logic from the vowel syllable function and get it all right!
90*2d1272b8SAndroid Build Coastguard Worker  *
91*2d1272b8SAndroid Build Coastguard Worker  * Keep in sync with consonant_categories in the generator. */
92*2d1272b8SAndroid Build Coastguard Worker #define CONSONANT_FLAGS_MYANMAR (FLAG (M_Cat(C)) | FLAG (M_Cat(CS)) | FLAG (M_Cat(Ra)) | /* FLAG (M_Cat(CM)) | */ FLAG (M_Cat(IV)) | FLAG (M_Cat(GB)) | FLAG (M_Cat(DOTTEDCIRCLE)))
93*2d1272b8SAndroid Build Coastguard Worker 
94*2d1272b8SAndroid Build Coastguard Worker static inline bool
is_consonant_myanmar(const hb_glyph_info_t & info)95*2d1272b8SAndroid Build Coastguard Worker is_consonant_myanmar (const hb_glyph_info_t &info)
96*2d1272b8SAndroid Build Coastguard Worker {
97*2d1272b8SAndroid Build Coastguard Worker   return is_one_of_myanmar (info, CONSONANT_FLAGS_MYANMAR);
98*2d1272b8SAndroid Build Coastguard Worker }
99*2d1272b8SAndroid Build Coastguard Worker 
100*2d1272b8SAndroid Build Coastguard Worker 
101*2d1272b8SAndroid Build Coastguard Worker static bool
102*2d1272b8SAndroid Build Coastguard Worker setup_syllables_myanmar (const hb_ot_shape_plan_t *plan,
103*2d1272b8SAndroid Build Coastguard Worker 			 hb_font_t *font,
104*2d1272b8SAndroid Build Coastguard Worker 			 hb_buffer_t *buffer);
105*2d1272b8SAndroid Build Coastguard Worker static bool
106*2d1272b8SAndroid Build Coastguard Worker reorder_myanmar (const hb_ot_shape_plan_t *plan,
107*2d1272b8SAndroid Build Coastguard Worker 		 hb_font_t *font,
108*2d1272b8SAndroid Build Coastguard Worker 		 hb_buffer_t *buffer);
109*2d1272b8SAndroid Build Coastguard Worker 
110*2d1272b8SAndroid Build Coastguard Worker static void
collect_features_myanmar(hb_ot_shape_planner_t * plan)111*2d1272b8SAndroid Build Coastguard Worker collect_features_myanmar (hb_ot_shape_planner_t *plan)
112*2d1272b8SAndroid Build Coastguard Worker {
113*2d1272b8SAndroid Build Coastguard Worker   hb_ot_map_builder_t *map = &plan->map;
114*2d1272b8SAndroid Build Coastguard Worker 
115*2d1272b8SAndroid Build Coastguard Worker   /* Do this before any lookups have been applied. */
116*2d1272b8SAndroid Build Coastguard Worker   map->add_gsub_pause (setup_syllables_myanmar);
117*2d1272b8SAndroid Build Coastguard Worker 
118*2d1272b8SAndroid Build Coastguard Worker   map->enable_feature (HB_TAG('l','o','c','l'), F_PER_SYLLABLE);
119*2d1272b8SAndroid Build Coastguard Worker   /* The Indic specs do not require ccmp, but we apply it here since if
120*2d1272b8SAndroid Build Coastguard Worker    * there is a use of it, it's typically at the beginning. */
121*2d1272b8SAndroid Build Coastguard Worker   map->enable_feature (HB_TAG('c','c','m','p'), F_PER_SYLLABLE);
122*2d1272b8SAndroid Build Coastguard Worker 
123*2d1272b8SAndroid Build Coastguard Worker 
124*2d1272b8SAndroid Build Coastguard Worker   map->add_gsub_pause (reorder_myanmar);
125*2d1272b8SAndroid Build Coastguard Worker 
126*2d1272b8SAndroid Build Coastguard Worker   for (unsigned int i = 0; i < ARRAY_LENGTH (myanmar_basic_features); i++)
127*2d1272b8SAndroid Build Coastguard Worker   {
128*2d1272b8SAndroid Build Coastguard Worker     map->enable_feature (myanmar_basic_features[i], F_MANUAL_ZWJ | F_PER_SYLLABLE);
129*2d1272b8SAndroid Build Coastguard Worker     map->add_gsub_pause (nullptr);
130*2d1272b8SAndroid Build Coastguard Worker   }
131*2d1272b8SAndroid Build Coastguard Worker   map->add_gsub_pause (hb_syllabic_clear_var); // Don't need syllables anymore, use stop to free buffer var
132*2d1272b8SAndroid Build Coastguard Worker 
133*2d1272b8SAndroid Build Coastguard Worker   for (unsigned int i = 0; i < ARRAY_LENGTH (myanmar_other_features); i++)
134*2d1272b8SAndroid Build Coastguard Worker     map->enable_feature (myanmar_other_features[i], F_MANUAL_ZWJ);
135*2d1272b8SAndroid Build Coastguard Worker }
136*2d1272b8SAndroid Build Coastguard Worker 
137*2d1272b8SAndroid Build Coastguard Worker static void
setup_masks_myanmar(const hb_ot_shape_plan_t * plan HB_UNUSED,hb_buffer_t * buffer,hb_font_t * font HB_UNUSED)138*2d1272b8SAndroid Build Coastguard Worker setup_masks_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED,
139*2d1272b8SAndroid Build Coastguard Worker 		     hb_buffer_t              *buffer,
140*2d1272b8SAndroid Build Coastguard Worker 		     hb_font_t                *font HB_UNUSED)
141*2d1272b8SAndroid Build Coastguard Worker {
142*2d1272b8SAndroid Build Coastguard Worker   HB_BUFFER_ALLOCATE_VAR (buffer, myanmar_category);
143*2d1272b8SAndroid Build Coastguard Worker   HB_BUFFER_ALLOCATE_VAR (buffer, myanmar_position);
144*2d1272b8SAndroid Build Coastguard Worker 
145*2d1272b8SAndroid Build Coastguard Worker   /* No masks, we just save information about characters. */
146*2d1272b8SAndroid Build Coastguard Worker 
147*2d1272b8SAndroid Build Coastguard Worker   unsigned int count = buffer->len;
148*2d1272b8SAndroid Build Coastguard Worker   hb_glyph_info_t *info = buffer->info;
149*2d1272b8SAndroid Build Coastguard Worker   for (unsigned int i = 0; i < count; i++)
150*2d1272b8SAndroid Build Coastguard Worker     set_myanmar_properties (info[i]);
151*2d1272b8SAndroid Build Coastguard Worker }
152*2d1272b8SAndroid Build Coastguard Worker 
153*2d1272b8SAndroid Build Coastguard Worker static bool
setup_syllables_myanmar(const hb_ot_shape_plan_t * plan HB_UNUSED,hb_font_t * font HB_UNUSED,hb_buffer_t * buffer)154*2d1272b8SAndroid Build Coastguard Worker setup_syllables_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED,
155*2d1272b8SAndroid Build Coastguard Worker 			 hb_font_t *font HB_UNUSED,
156*2d1272b8SAndroid Build Coastguard Worker 			 hb_buffer_t *buffer)
157*2d1272b8SAndroid Build Coastguard Worker {
158*2d1272b8SAndroid Build Coastguard Worker   HB_BUFFER_ALLOCATE_VAR (buffer, syllable);
159*2d1272b8SAndroid Build Coastguard Worker   find_syllables_myanmar (buffer);
160*2d1272b8SAndroid Build Coastguard Worker   foreach_syllable (buffer, start, end)
161*2d1272b8SAndroid Build Coastguard Worker     buffer->unsafe_to_break (start, end);
162*2d1272b8SAndroid Build Coastguard Worker   return false;
163*2d1272b8SAndroid Build Coastguard Worker }
164*2d1272b8SAndroid Build Coastguard Worker 
165*2d1272b8SAndroid Build Coastguard Worker static int
compare_myanmar_order(const hb_glyph_info_t * pa,const hb_glyph_info_t * pb)166*2d1272b8SAndroid Build Coastguard Worker compare_myanmar_order (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb)
167*2d1272b8SAndroid Build Coastguard Worker {
168*2d1272b8SAndroid Build Coastguard Worker   int a = pa->myanmar_position();
169*2d1272b8SAndroid Build Coastguard Worker   int b = pb->myanmar_position();
170*2d1272b8SAndroid Build Coastguard Worker 
171*2d1272b8SAndroid Build Coastguard Worker   return (int) a - (int) b;
172*2d1272b8SAndroid Build Coastguard Worker }
173*2d1272b8SAndroid Build Coastguard Worker 
174*2d1272b8SAndroid Build Coastguard Worker 
175*2d1272b8SAndroid Build Coastguard Worker /* Rules from:
176*2d1272b8SAndroid Build Coastguard Worker  * https://docs.microsoft.com/en-us/typography/script-development/myanmar */
177*2d1272b8SAndroid Build Coastguard Worker 
178*2d1272b8SAndroid Build Coastguard Worker static void
initial_reordering_consonant_syllable(hb_buffer_t * buffer,unsigned int start,unsigned int end)179*2d1272b8SAndroid Build Coastguard Worker initial_reordering_consonant_syllable (hb_buffer_t *buffer,
180*2d1272b8SAndroid Build Coastguard Worker 				       unsigned int start, unsigned int end)
181*2d1272b8SAndroid Build Coastguard Worker {
182*2d1272b8SAndroid Build Coastguard Worker   hb_glyph_info_t *info = buffer->info;
183*2d1272b8SAndroid Build Coastguard Worker 
184*2d1272b8SAndroid Build Coastguard Worker   unsigned int base = end;
185*2d1272b8SAndroid Build Coastguard Worker   bool has_reph = false;
186*2d1272b8SAndroid Build Coastguard Worker 
187*2d1272b8SAndroid Build Coastguard Worker   {
188*2d1272b8SAndroid Build Coastguard Worker     unsigned int limit = start;
189*2d1272b8SAndroid Build Coastguard Worker     if (start + 3 <= end &&
190*2d1272b8SAndroid Build Coastguard Worker 	info[start  ].myanmar_category() == M_Cat(Ra) &&
191*2d1272b8SAndroid Build Coastguard Worker 	info[start+1].myanmar_category() == M_Cat(As) &&
192*2d1272b8SAndroid Build Coastguard Worker 	info[start+2].myanmar_category() == M_Cat(H))
193*2d1272b8SAndroid Build Coastguard Worker     {
194*2d1272b8SAndroid Build Coastguard Worker       limit += 3;
195*2d1272b8SAndroid Build Coastguard Worker       base = start;
196*2d1272b8SAndroid Build Coastguard Worker       has_reph = true;
197*2d1272b8SAndroid Build Coastguard Worker     }
198*2d1272b8SAndroid Build Coastguard Worker 
199*2d1272b8SAndroid Build Coastguard Worker     {
200*2d1272b8SAndroid Build Coastguard Worker       if (!has_reph)
201*2d1272b8SAndroid Build Coastguard Worker 	base = limit;
202*2d1272b8SAndroid Build Coastguard Worker 
203*2d1272b8SAndroid Build Coastguard Worker       for (unsigned int i = limit; i < end; i++)
204*2d1272b8SAndroid Build Coastguard Worker 	if (is_consonant_myanmar (info[i]))
205*2d1272b8SAndroid Build Coastguard Worker 	{
206*2d1272b8SAndroid Build Coastguard Worker 	  base = i;
207*2d1272b8SAndroid Build Coastguard Worker 	  break;
208*2d1272b8SAndroid Build Coastguard Worker 	}
209*2d1272b8SAndroid Build Coastguard Worker     }
210*2d1272b8SAndroid Build Coastguard Worker   }
211*2d1272b8SAndroid Build Coastguard Worker 
212*2d1272b8SAndroid Build Coastguard Worker   /* Reorder! */
213*2d1272b8SAndroid Build Coastguard Worker   {
214*2d1272b8SAndroid Build Coastguard Worker     unsigned int i = start;
215*2d1272b8SAndroid Build Coastguard Worker     for (; i < start + (has_reph ? 3 : 0); i++)
216*2d1272b8SAndroid Build Coastguard Worker       info[i].myanmar_position() = POS_AFTER_MAIN;
217*2d1272b8SAndroid Build Coastguard Worker     for (; i < base; i++)
218*2d1272b8SAndroid Build Coastguard Worker       info[i].myanmar_position() = POS_PRE_C;
219*2d1272b8SAndroid Build Coastguard Worker     if (i < end)
220*2d1272b8SAndroid Build Coastguard Worker     {
221*2d1272b8SAndroid Build Coastguard Worker       info[i].myanmar_position() = POS_BASE_C;
222*2d1272b8SAndroid Build Coastguard Worker       i++;
223*2d1272b8SAndroid Build Coastguard Worker     }
224*2d1272b8SAndroid Build Coastguard Worker     myanmar_position_t pos = POS_AFTER_MAIN;
225*2d1272b8SAndroid Build Coastguard Worker     /* The following loop may be ugly, but it implements all of
226*2d1272b8SAndroid Build Coastguard Worker      * Myanmar reordering! */
227*2d1272b8SAndroid Build Coastguard Worker     for (; i < end; i++)
228*2d1272b8SAndroid Build Coastguard Worker     {
229*2d1272b8SAndroid Build Coastguard Worker       if (info[i].myanmar_category() == M_Cat(MR)) /* Pre-base reordering */
230*2d1272b8SAndroid Build Coastguard Worker       {
231*2d1272b8SAndroid Build Coastguard Worker 	info[i].myanmar_position() = POS_PRE_C;
232*2d1272b8SAndroid Build Coastguard Worker 	continue;
233*2d1272b8SAndroid Build Coastguard Worker       }
234*2d1272b8SAndroid Build Coastguard Worker       if (info[i].myanmar_category() == M_Cat(VPre)) /* Left matra */
235*2d1272b8SAndroid Build Coastguard Worker       {
236*2d1272b8SAndroid Build Coastguard Worker 	info[i].myanmar_position() = POS_PRE_M;
237*2d1272b8SAndroid Build Coastguard Worker 	continue;
238*2d1272b8SAndroid Build Coastguard Worker       }
239*2d1272b8SAndroid Build Coastguard Worker       if (info[i].myanmar_category() == M_Cat(VS))
240*2d1272b8SAndroid Build Coastguard Worker       {
241*2d1272b8SAndroid Build Coastguard Worker 	info[i].myanmar_position() = info[i - 1].myanmar_position();
242*2d1272b8SAndroid Build Coastguard Worker 	continue;
243*2d1272b8SAndroid Build Coastguard Worker       }
244*2d1272b8SAndroid Build Coastguard Worker 
245*2d1272b8SAndroid Build Coastguard Worker       if (pos == POS_AFTER_MAIN && info[i].myanmar_category() == M_Cat(VBlw))
246*2d1272b8SAndroid Build Coastguard Worker       {
247*2d1272b8SAndroid Build Coastguard Worker 	pos = POS_BELOW_C;
248*2d1272b8SAndroid Build Coastguard Worker 	info[i].myanmar_position() = pos;
249*2d1272b8SAndroid Build Coastguard Worker 	continue;
250*2d1272b8SAndroid Build Coastguard Worker       }
251*2d1272b8SAndroid Build Coastguard Worker 
252*2d1272b8SAndroid Build Coastguard Worker       if (pos == POS_BELOW_C && info[i].myanmar_category() == M_Cat(A))
253*2d1272b8SAndroid Build Coastguard Worker       {
254*2d1272b8SAndroid Build Coastguard Worker 	info[i].myanmar_position() = POS_BEFORE_SUB;
255*2d1272b8SAndroid Build Coastguard Worker 	continue;
256*2d1272b8SAndroid Build Coastguard Worker       }
257*2d1272b8SAndroid Build Coastguard Worker       if (pos == POS_BELOW_C && info[i].myanmar_category() == M_Cat(VBlw))
258*2d1272b8SAndroid Build Coastguard Worker       {
259*2d1272b8SAndroid Build Coastguard Worker 	info[i].myanmar_position() = pos;
260*2d1272b8SAndroid Build Coastguard Worker 	continue;
261*2d1272b8SAndroid Build Coastguard Worker       }
262*2d1272b8SAndroid Build Coastguard Worker       if (pos == POS_BELOW_C && info[i].myanmar_category() != M_Cat(A))
263*2d1272b8SAndroid Build Coastguard Worker       {
264*2d1272b8SAndroid Build Coastguard Worker 	pos = POS_AFTER_SUB;
265*2d1272b8SAndroid Build Coastguard Worker 	info[i].myanmar_position() = pos;
266*2d1272b8SAndroid Build Coastguard Worker 	continue;
267*2d1272b8SAndroid Build Coastguard Worker       }
268*2d1272b8SAndroid Build Coastguard Worker       info[i].myanmar_position() = pos;
269*2d1272b8SAndroid Build Coastguard Worker     }
270*2d1272b8SAndroid Build Coastguard Worker   }
271*2d1272b8SAndroid Build Coastguard Worker 
272*2d1272b8SAndroid Build Coastguard Worker   /* Sit tight, rock 'n roll! */
273*2d1272b8SAndroid Build Coastguard Worker   buffer->sort (start, end, compare_myanmar_order);
274*2d1272b8SAndroid Build Coastguard Worker 
275*2d1272b8SAndroid Build Coastguard Worker   /* Flip left-matra sequence. */
276*2d1272b8SAndroid Build Coastguard Worker   unsigned first_left_matra = end;
277*2d1272b8SAndroid Build Coastguard Worker   unsigned last_left_matra = end;
278*2d1272b8SAndroid Build Coastguard Worker   for (unsigned int i = start; i < end; i++)
279*2d1272b8SAndroid Build Coastguard Worker   {
280*2d1272b8SAndroid Build Coastguard Worker     if (info[i].myanmar_position() == POS_PRE_M)
281*2d1272b8SAndroid Build Coastguard Worker     {
282*2d1272b8SAndroid Build Coastguard Worker       if (first_left_matra == end)
283*2d1272b8SAndroid Build Coastguard Worker 	first_left_matra = i;
284*2d1272b8SAndroid Build Coastguard Worker       last_left_matra = i;
285*2d1272b8SAndroid Build Coastguard Worker     }
286*2d1272b8SAndroid Build Coastguard Worker   }
287*2d1272b8SAndroid Build Coastguard Worker   /* https://github.com/harfbuzz/harfbuzz/issues/3863 */
288*2d1272b8SAndroid Build Coastguard Worker   if (first_left_matra < last_left_matra)
289*2d1272b8SAndroid Build Coastguard Worker   {
290*2d1272b8SAndroid Build Coastguard Worker     /* No need to merge clusters, done already? */
291*2d1272b8SAndroid Build Coastguard Worker     buffer->reverse_range (first_left_matra, last_left_matra + 1);
292*2d1272b8SAndroid Build Coastguard Worker     /* Reverse back VS, etc. */
293*2d1272b8SAndroid Build Coastguard Worker     unsigned i = first_left_matra;
294*2d1272b8SAndroid Build Coastguard Worker     for (unsigned j = i; j <= last_left_matra; j++)
295*2d1272b8SAndroid Build Coastguard Worker       if (info[j].myanmar_category() == M_Cat(VPre))
296*2d1272b8SAndroid Build Coastguard Worker       {
297*2d1272b8SAndroid Build Coastguard Worker 	buffer->reverse_range (i, j + 1);
298*2d1272b8SAndroid Build Coastguard Worker 	i = j + 1;
299*2d1272b8SAndroid Build Coastguard Worker       }
300*2d1272b8SAndroid Build Coastguard Worker   }
301*2d1272b8SAndroid Build Coastguard Worker }
302*2d1272b8SAndroid Build Coastguard Worker 
303*2d1272b8SAndroid Build Coastguard Worker static void
reorder_syllable_myanmar(const hb_ot_shape_plan_t * plan HB_UNUSED,hb_face_t * face HB_UNUSED,hb_buffer_t * buffer,unsigned int start,unsigned int end)304*2d1272b8SAndroid Build Coastguard Worker reorder_syllable_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED,
305*2d1272b8SAndroid Build Coastguard Worker 			  hb_face_t *face HB_UNUSED,
306*2d1272b8SAndroid Build Coastguard Worker 			  hb_buffer_t *buffer,
307*2d1272b8SAndroid Build Coastguard Worker 			  unsigned int start, unsigned int end)
308*2d1272b8SAndroid Build Coastguard Worker {
309*2d1272b8SAndroid Build Coastguard Worker   myanmar_syllable_type_t syllable_type = (myanmar_syllable_type_t) (buffer->info[start].syllable() & 0x0F);
310*2d1272b8SAndroid Build Coastguard Worker   switch (syllable_type) {
311*2d1272b8SAndroid Build Coastguard Worker 
312*2d1272b8SAndroid Build Coastguard Worker     case myanmar_broken_cluster: /* We already inserted dotted-circles, so just call the consonant_syllable. */
313*2d1272b8SAndroid Build Coastguard Worker     case myanmar_consonant_syllable:
314*2d1272b8SAndroid Build Coastguard Worker       initial_reordering_consonant_syllable  (buffer, start, end);
315*2d1272b8SAndroid Build Coastguard Worker       break;
316*2d1272b8SAndroid Build Coastguard Worker 
317*2d1272b8SAndroid Build Coastguard Worker     case myanmar_non_myanmar_cluster:
318*2d1272b8SAndroid Build Coastguard Worker       break;
319*2d1272b8SAndroid Build Coastguard Worker   }
320*2d1272b8SAndroid Build Coastguard Worker }
321*2d1272b8SAndroid Build Coastguard Worker 
322*2d1272b8SAndroid Build Coastguard Worker static bool
reorder_myanmar(const hb_ot_shape_plan_t * plan,hb_font_t * font,hb_buffer_t * buffer)323*2d1272b8SAndroid Build Coastguard Worker reorder_myanmar (const hb_ot_shape_plan_t *plan,
324*2d1272b8SAndroid Build Coastguard Worker 		 hb_font_t *font,
325*2d1272b8SAndroid Build Coastguard Worker 		 hb_buffer_t *buffer)
326*2d1272b8SAndroid Build Coastguard Worker {
327*2d1272b8SAndroid Build Coastguard Worker   bool ret = false;
328*2d1272b8SAndroid Build Coastguard Worker   if (buffer->message (font, "start reordering myanmar"))
329*2d1272b8SAndroid Build Coastguard Worker   {
330*2d1272b8SAndroid Build Coastguard Worker     if (hb_syllabic_insert_dotted_circles (font, buffer,
331*2d1272b8SAndroid Build Coastguard Worker 					   myanmar_broken_cluster,
332*2d1272b8SAndroid Build Coastguard Worker 					   M_Cat(DOTTEDCIRCLE)))
333*2d1272b8SAndroid Build Coastguard Worker       ret = true;
334*2d1272b8SAndroid Build Coastguard Worker 
335*2d1272b8SAndroid Build Coastguard Worker     foreach_syllable (buffer, start, end)
336*2d1272b8SAndroid Build Coastguard Worker       reorder_syllable_myanmar (plan, font->face, buffer, start, end);
337*2d1272b8SAndroid Build Coastguard Worker     (void) buffer->message (font, "end reordering myanmar");
338*2d1272b8SAndroid Build Coastguard Worker   }
339*2d1272b8SAndroid Build Coastguard Worker 
340*2d1272b8SAndroid Build Coastguard Worker   HB_BUFFER_DEALLOCATE_VAR (buffer, myanmar_category);
341*2d1272b8SAndroid Build Coastguard Worker   HB_BUFFER_DEALLOCATE_VAR (buffer, myanmar_position);
342*2d1272b8SAndroid Build Coastguard Worker 
343*2d1272b8SAndroid Build Coastguard Worker   return ret;
344*2d1272b8SAndroid Build Coastguard Worker }
345*2d1272b8SAndroid Build Coastguard Worker 
346*2d1272b8SAndroid Build Coastguard Worker 
347*2d1272b8SAndroid Build Coastguard Worker const hb_ot_shaper_t _hb_ot_shaper_myanmar =
348*2d1272b8SAndroid Build Coastguard Worker {
349*2d1272b8SAndroid Build Coastguard Worker   collect_features_myanmar,
350*2d1272b8SAndroid Build Coastguard Worker   nullptr, /* override_features */
351*2d1272b8SAndroid Build Coastguard Worker   nullptr, /* data_create */
352*2d1272b8SAndroid Build Coastguard Worker   nullptr, /* data_destroy */
353*2d1272b8SAndroid Build Coastguard Worker   nullptr, /* preprocess_text */
354*2d1272b8SAndroid Build Coastguard Worker   nullptr, /* postprocess_glyphs */
355*2d1272b8SAndroid Build Coastguard Worker   nullptr, /* decompose */
356*2d1272b8SAndroid Build Coastguard Worker   nullptr, /* compose */
357*2d1272b8SAndroid Build Coastguard Worker   setup_masks_myanmar,
358*2d1272b8SAndroid Build Coastguard Worker   nullptr, /* reorder_marks */
359*2d1272b8SAndroid Build Coastguard Worker   HB_TAG_NONE, /* gpos_tag */
360*2d1272b8SAndroid Build Coastguard Worker   HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
361*2d1272b8SAndroid Build Coastguard Worker   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY,
362*2d1272b8SAndroid Build Coastguard Worker   false, /* fallback_position */
363*2d1272b8SAndroid Build Coastguard Worker };
364*2d1272b8SAndroid Build Coastguard Worker 
365*2d1272b8SAndroid Build Coastguard Worker 
366*2d1272b8SAndroid Build Coastguard Worker #ifndef HB_NO_OT_SHAPER_MYANMAR_ZAWGYI
367*2d1272b8SAndroid Build Coastguard Worker /* Ugly Zawgyi encoding.
368*2d1272b8SAndroid Build Coastguard Worker  * Disable all auto processing.
369*2d1272b8SAndroid Build Coastguard Worker  * https://github.com/harfbuzz/harfbuzz/issues/1162 */
370*2d1272b8SAndroid Build Coastguard Worker const hb_ot_shaper_t _hb_ot_shaper_myanmar_zawgyi =
371*2d1272b8SAndroid Build Coastguard Worker {
372*2d1272b8SAndroid Build Coastguard Worker   nullptr, /* collect_features */
373*2d1272b8SAndroid Build Coastguard Worker   nullptr, /* override_features */
374*2d1272b8SAndroid Build Coastguard Worker   nullptr, /* data_create */
375*2d1272b8SAndroid Build Coastguard Worker   nullptr, /* data_destroy */
376*2d1272b8SAndroid Build Coastguard Worker   nullptr, /* preprocess_text */
377*2d1272b8SAndroid Build Coastguard Worker   nullptr, /* postprocess_glyphs */
378*2d1272b8SAndroid Build Coastguard Worker   nullptr, /* decompose */
379*2d1272b8SAndroid Build Coastguard Worker   nullptr, /* compose */
380*2d1272b8SAndroid Build Coastguard Worker   nullptr, /* setup_masks */
381*2d1272b8SAndroid Build Coastguard Worker   nullptr, /* reorder_marks */
382*2d1272b8SAndroid Build Coastguard Worker   HB_TAG_NONE, /* gpos_tag */
383*2d1272b8SAndroid Build Coastguard Worker   HB_OT_SHAPE_NORMALIZATION_MODE_NONE,
384*2d1272b8SAndroid Build Coastguard Worker   HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
385*2d1272b8SAndroid Build Coastguard Worker   false, /* fallback_position */
386*2d1272b8SAndroid Build Coastguard Worker };
387*2d1272b8SAndroid Build Coastguard Worker #endif
388*2d1272b8SAndroid Build Coastguard Worker 
389*2d1272b8SAndroid Build Coastguard Worker 
390*2d1272b8SAndroid Build Coastguard Worker #endif
391