• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2011,2012,2013  Google, Inc.
3  *
4  *  This is part of HarfBuzz, a text shaping library.
5  *
6  * Permission is hereby granted, without written agreement and without
7  * license or royalty fees, to use, copy, modify, and distribute this
8  * software and its documentation for any purpose, provided that the
9  * above copyright notice and the following two paragraphs appear in
10  * all copies of this software.
11  *
12  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16  * DAMAGE.
17  *
18  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
21  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23  *
24  * Google Author(s): Behdad Esfahbod
25  */
26 
27 #include "hb.hh"
28 
29 #ifndef HB_NO_OT_SHAPE
30 
31 #include "hb-ot-shape-complex-myanmar.hh"
32 #include "hb-ot-shape-complex-myanmar-machine.hh"
33 
34 
35 /*
36  * Myanmar shaper.
37  */
38 
39 static const hb_tag_t
40 myanmar_basic_features[] =
41 {
42   /*
43    * Basic features.
44    * These features are applied in order, one at a time, after reordering.
45    */
46   HB_TAG('r','p','h','f'),
47   HB_TAG('p','r','e','f'),
48   HB_TAG('b','l','w','f'),
49   HB_TAG('p','s','t','f'),
50 };
51 static const hb_tag_t
52 myanmar_other_features[] =
53 {
54   /*
55    * Other features.
56    * These features are applied all at once, after clearing syllables.
57    */
58   HB_TAG('p','r','e','s'),
59   HB_TAG('a','b','v','s'),
60   HB_TAG('b','l','w','s'),
61   HB_TAG('p','s','t','s'),
62 };
63 
64 static void
65 setup_syllables_myanmar (const hb_ot_shape_plan_t *plan,
66 			 hb_font_t *font,
67 			 hb_buffer_t *buffer);
68 static void
69 reorder_myanmar (const hb_ot_shape_plan_t *plan,
70 		 hb_font_t *font,
71 		 hb_buffer_t *buffer);
72 
73 static void
collect_features_myanmar(hb_ot_shape_planner_t * plan)74 collect_features_myanmar (hb_ot_shape_planner_t *plan)
75 {
76   hb_ot_map_builder_t *map = &plan->map;
77 
78   /* Do this before any lookups have been applied. */
79   map->add_gsub_pause (setup_syllables_myanmar);
80 
81   map->enable_feature (HB_TAG('l','o','c','l'));
82   /* The Indic specs do not require ccmp, but we apply it here since if
83    * there is a use of it, it's typically at the beginning. */
84   map->enable_feature (HB_TAG('c','c','m','p'));
85 
86 
87   map->add_gsub_pause (reorder_myanmar);
88 
89   for (unsigned int i = 0; i < ARRAY_LENGTH (myanmar_basic_features); i++)
90   {
91     map->enable_feature (myanmar_basic_features[i], F_MANUAL_ZWJ);
92     map->add_gsub_pause (nullptr);
93   }
94 
95   map->add_gsub_pause (_hb_clear_syllables);
96 
97   for (unsigned int i = 0; i < ARRAY_LENGTH (myanmar_other_features); i++)
98     map->enable_feature (myanmar_other_features[i], F_MANUAL_ZWJ);
99 }
100 
101 static void
setup_masks_myanmar(const hb_ot_shape_plan_t * plan HB_UNUSED,hb_buffer_t * buffer,hb_font_t * font HB_UNUSED)102 setup_masks_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED,
103 		     hb_buffer_t              *buffer,
104 		     hb_font_t                *font HB_UNUSED)
105 {
106   HB_BUFFER_ALLOCATE_VAR (buffer, myanmar_category);
107   HB_BUFFER_ALLOCATE_VAR (buffer, myanmar_position);
108 
109   /* We cannot setup masks here.  We save information about characters
110    * and setup masks later on in a pause-callback. */
111 
112   unsigned int count = buffer->len;
113   hb_glyph_info_t *info = buffer->info;
114   for (unsigned int i = 0; i < count; i++)
115     set_myanmar_properties (info[i]);
116 }
117 
118 static void
setup_syllables_myanmar(const hb_ot_shape_plan_t * plan HB_UNUSED,hb_font_t * font HB_UNUSED,hb_buffer_t * buffer)119 setup_syllables_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED,
120 			 hb_font_t *font HB_UNUSED,
121 			 hb_buffer_t *buffer)
122 {
123   find_syllables_myanmar (buffer);
124   foreach_syllable (buffer, start, end)
125     buffer->unsafe_to_break (start, end);
126 }
127 
128 static int
compare_myanmar_order(const hb_glyph_info_t * pa,const hb_glyph_info_t * pb)129 compare_myanmar_order (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb)
130 {
131   int a = pa->myanmar_position();
132   int b = pb->myanmar_position();
133 
134   return a < b ? -1 : a == b ? 0 : +1;
135 }
136 
137 
138 /* Rules from:
139  * https://docs.microsoft.com/en-us/typography/script-development/myanmar */
140 
141 static void
initial_reordering_consonant_syllable(hb_buffer_t * buffer,unsigned int start,unsigned int end)142 initial_reordering_consonant_syllable (hb_buffer_t *buffer,
143 				       unsigned int start, unsigned int end)
144 {
145   hb_glyph_info_t *info = buffer->info;
146 
147   unsigned int base = end;
148   bool has_reph = false;
149 
150   {
151     unsigned int limit = start;
152     if (start + 3 <= end &&
153 	info[start  ].myanmar_category() == OT_Ra &&
154 	info[start+1].myanmar_category() == OT_As &&
155 	info[start+2].myanmar_category() == OT_H)
156     {
157       limit += 3;
158       base = start;
159       has_reph = true;
160     }
161 
162     {
163       if (!has_reph)
164 	base = limit;
165 
166       for (unsigned int i = limit; i < end; i++)
167 	if (is_consonant (info[i]))
168 	{
169 	  base = i;
170 	  break;
171 	}
172     }
173   }
174 
175   /* Reorder! */
176   {
177     unsigned int i = start;
178     for (; i < start + (has_reph ? 3 : 0); i++)
179       info[i].myanmar_position() = POS_AFTER_MAIN;
180     for (; i < base; i++)
181       info[i].myanmar_position() = POS_PRE_C;
182     if (i < end)
183     {
184       info[i].myanmar_position() = POS_BASE_C;
185       i++;
186     }
187     indic_position_t pos = POS_AFTER_MAIN;
188     /* The following loop may be ugly, but it implements all of
189      * Myanmar reordering! */
190     for (; i < end; i++)
191     {
192       if (info[i].myanmar_category() == OT_MR) /* Pre-base reordering */
193       {
194 	info[i].myanmar_position() = POS_PRE_C;
195 	continue;
196       }
197       if (info[i].myanmar_position() < POS_BASE_C) /* Left matra */
198       {
199 	continue;
200       }
201       if (info[i].myanmar_category() == OT_VS)
202       {
203 	info[i].myanmar_position() = info[i - 1].myanmar_position();
204 	continue;
205       }
206 
207       if (pos == POS_AFTER_MAIN && info[i].myanmar_category() == OT_VBlw)
208       {
209 	pos = POS_BELOW_C;
210 	info[i].myanmar_position() = pos;
211 	continue;
212       }
213 
214       if (pos == POS_BELOW_C && info[i].myanmar_category() == OT_A)
215       {
216 	info[i].myanmar_position() = POS_BEFORE_SUB;
217 	continue;
218       }
219       if (pos == POS_BELOW_C && info[i].myanmar_category() == OT_VBlw)
220       {
221 	info[i].myanmar_position() = pos;
222 	continue;
223       }
224       if (pos == POS_BELOW_C && info[i].myanmar_category() != OT_A)
225       {
226 	pos = POS_AFTER_SUB;
227 	info[i].myanmar_position() = pos;
228 	continue;
229       }
230       info[i].myanmar_position() = pos;
231     }
232   }
233 
234   /* Sit tight, rock 'n roll! */
235   buffer->sort (start, end, compare_myanmar_order);
236 }
237 
238 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)239 reorder_syllable_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED,
240 			  hb_face_t *face HB_UNUSED,
241 			  hb_buffer_t *buffer,
242 			  unsigned int start, unsigned int end)
243 {
244   myanmar_syllable_type_t syllable_type = (myanmar_syllable_type_t) (buffer->info[start].syllable() & 0x0F);
245   switch (syllable_type) {
246 
247     case myanmar_broken_cluster: /* We already inserted dotted-circles, so just call the consonant_syllable. */
248     case myanmar_consonant_syllable:
249       initial_reordering_consonant_syllable  (buffer, start, end);
250       break;
251 
252     case myanmar_punctuation_cluster:
253     case myanmar_non_myanmar_cluster:
254       break;
255   }
256 }
257 
258 static void
reorder_myanmar(const hb_ot_shape_plan_t * plan,hb_font_t * font,hb_buffer_t * buffer)259 reorder_myanmar (const hb_ot_shape_plan_t *plan,
260 		 hb_font_t *font,
261 		 hb_buffer_t *buffer)
262 {
263   if (buffer->message (font, "start reordering myanmar"))
264   {
265     hb_syllabic_insert_dotted_circles (font, buffer,
266 				       myanmar_broken_cluster,
267 				       OT_GB);
268 
269     foreach_syllable (buffer, start, end)
270       reorder_syllable_myanmar (plan, font->face, buffer, start, end);
271     (void) buffer->message (font, "end reordering myanmar");
272   }
273 
274   HB_BUFFER_DEALLOCATE_VAR (buffer, myanmar_category);
275   HB_BUFFER_DEALLOCATE_VAR (buffer, myanmar_position);
276 }
277 
278 
279 const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar =
280 {
281   collect_features_myanmar,
282   nullptr, /* override_features */
283   nullptr, /* data_create */
284   nullptr, /* data_destroy */
285   nullptr, /* preprocess_text */
286   nullptr, /* postprocess_glyphs */
287   HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
288   nullptr, /* decompose */
289   nullptr, /* compose */
290   setup_masks_myanmar,
291   HB_TAG_NONE, /* gpos_tag */
292   nullptr, /* reorder_marks */
293   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY,
294   false, /* fallback_position */
295 };
296 
297 
298 /* Ugly Zawgyi encoding.
299  * Disable all auto processing.
300  * https://github.com/harfbuzz/harfbuzz/issues/1162 */
301 const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar_zawgyi =
302 {
303   nullptr, /* collect_features */
304   nullptr, /* override_features */
305   nullptr, /* data_create */
306   nullptr, /* data_destroy */
307   nullptr, /* preprocess_text */
308   nullptr, /* postprocess_glyphs */
309   HB_OT_SHAPE_NORMALIZATION_MODE_NONE,
310   nullptr, /* decompose */
311   nullptr, /* compose */
312   nullptr, /* setup_masks */
313   HB_TAG_NONE, /* gpos_tag */
314   nullptr, /* reorder_marks */
315   HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
316   false, /* fallback_position */
317 };
318 
319 
320 #endif
321