Merge branch 'upstream' into tizen
[platform/upstream/harfbuzz.git] / src / hb-ot-shape-complex-myanmar.cc
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    * constrained to the syllable.
46    */
47   HB_TAG('r','p','h','f'),
48   HB_TAG('p','r','e','f'),
49   HB_TAG('b','l','w','f'),
50   HB_TAG('p','s','t','f'),
51 };
52 static const hb_tag_t
53 myanmar_other_features[] =
54 {
55   /*
56    * Other features.
57    * These features are applied all at once, after clearing syllables.
58    */
59   HB_TAG('p','r','e','s'),
60   HB_TAG('a','b','v','s'),
61   HB_TAG('b','l','w','s'),
62   HB_TAG('p','s','t','s'),
63 };
64
65 static void
66 setup_syllables_myanmar (const hb_ot_shape_plan_t *plan,
67                          hb_font_t *font,
68                          hb_buffer_t *buffer);
69 static void
70 reorder_myanmar (const hb_ot_shape_plan_t *plan,
71                  hb_font_t *font,
72                  hb_buffer_t *buffer);
73
74 static void
75 collect_features_myanmar (hb_ot_shape_planner_t *plan)
76 {
77   hb_ot_map_builder_t *map = &plan->map;
78
79   /* Do this before any lookups have been applied. */
80   map->add_gsub_pause (setup_syllables_myanmar);
81
82   map->enable_feature (HB_TAG('l','o','c','l'));
83   /* The Indic specs do not require ccmp, but we apply it here since if
84    * there is a use of it, it's typically at the beginning. */
85   map->enable_feature (HB_TAG('c','c','m','p'));
86
87
88   map->add_gsub_pause (reorder_myanmar);
89
90   for (unsigned int i = 0; i < ARRAY_LENGTH (myanmar_basic_features); i++)
91   {
92     map->enable_feature (myanmar_basic_features[i], F_MANUAL_ZWJ);
93     map->add_gsub_pause (nullptr);
94   }
95
96   map->add_gsub_pause (_hb_clear_syllables);
97
98   for (unsigned int i = 0; i < ARRAY_LENGTH (myanmar_other_features); i++)
99     map->enable_feature (myanmar_other_features[i], F_MANUAL_ZWJ);
100 }
101
102 static void
103 setup_masks_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED,
104                      hb_buffer_t              *buffer,
105                      hb_font_t                *font HB_UNUSED)
106 {
107   HB_BUFFER_ALLOCATE_VAR (buffer, myanmar_category);
108   HB_BUFFER_ALLOCATE_VAR (buffer, myanmar_position);
109
110   /* We cannot setup masks here.  We save information about characters
111    * and setup masks later on in a pause-callback. */
112
113   unsigned int count = buffer->len;
114   hb_glyph_info_t *info = buffer->info;
115   for (unsigned int i = 0; i < count; i++)
116     set_myanmar_properties (info[i]);
117 }
118
119 static void
120 setup_syllables_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED,
121                          hb_font_t *font HB_UNUSED,
122                          hb_buffer_t *buffer)
123 {
124   find_syllables_myanmar (buffer);
125   foreach_syllable (buffer, start, end)
126     buffer->unsafe_to_break (start, end);
127 }
128
129 static int
130 compare_myanmar_order (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb)
131 {
132   int a = pa->myanmar_position();
133   int b = pb->myanmar_position();
134
135   return a < b ? -1 : a == b ? 0 : +1;
136 }
137
138
139 /* Rules from:
140  * https://docs.microsoft.com/en-us/typography/script-development/myanmar */
141
142 static void
143 initial_reordering_consonant_syllable (hb_buffer_t *buffer,
144                                        unsigned int start, unsigned int end)
145 {
146   hb_glyph_info_t *info = buffer->info;
147
148   unsigned int base = end;
149   bool has_reph = false;
150
151   {
152     unsigned int limit = start;
153     if (start + 3 <= end &&
154         info[start  ].myanmar_category() == OT_Ra &&
155         info[start+1].myanmar_category() == OT_As &&
156         info[start+2].myanmar_category() == OT_H)
157     {
158       limit += 3;
159       base = start;
160       has_reph = true;
161     }
162
163     {
164       if (!has_reph)
165         base = limit;
166
167       for (unsigned int i = limit; i < end; i++)
168         if (is_consonant (info[i]))
169         {
170           base = i;
171           break;
172         }
173     }
174   }
175
176   /* Reorder! */
177   {
178     unsigned int i = start;
179     for (; i < start + (has_reph ? 3 : 0); i++)
180       info[i].myanmar_position() = POS_AFTER_MAIN;
181     for (; i < base; i++)
182       info[i].myanmar_position() = POS_PRE_C;
183     if (i < end)
184     {
185       info[i].myanmar_position() = POS_BASE_C;
186       i++;
187     }
188     myanmar_position_t pos = POS_AFTER_MAIN;
189     /* The following loop may be ugly, but it implements all of
190      * Myanmar reordering! */
191     for (; i < end; i++)
192     {
193       if (info[i].myanmar_category() == OT_MR) /* Pre-base reordering */
194       {
195         info[i].myanmar_position() = POS_PRE_C;
196         continue;
197       }
198       if (info[i].myanmar_position() < POS_BASE_C) /* Left matra */
199       {
200         continue;
201       }
202       if (info[i].myanmar_category() == OT_VS)
203       {
204         info[i].myanmar_position() = info[i - 1].myanmar_position();
205         continue;
206       }
207
208       if (pos == POS_AFTER_MAIN && info[i].myanmar_category() == OT_VBlw)
209       {
210         pos = POS_BELOW_C;
211         info[i].myanmar_position() = pos;
212         continue;
213       }
214
215       if (pos == POS_BELOW_C && info[i].myanmar_category() == OT_A)
216       {
217         info[i].myanmar_position() = POS_BEFORE_SUB;
218         continue;
219       }
220       if (pos == POS_BELOW_C && info[i].myanmar_category() == OT_VBlw)
221       {
222         info[i].myanmar_position() = pos;
223         continue;
224       }
225       if (pos == POS_BELOW_C && info[i].myanmar_category() != OT_A)
226       {
227         pos = POS_AFTER_SUB;
228         info[i].myanmar_position() = pos;
229         continue;
230       }
231       info[i].myanmar_position() = pos;
232     }
233   }
234
235   /* Sit tight, rock 'n roll! */
236   buffer->sort (start, end, compare_myanmar_order);
237 }
238
239 static void
240 reorder_syllable_myanmar (const hb_ot_shape_plan_t *plan HB_UNUSED,
241                           hb_face_t *face HB_UNUSED,
242                           hb_buffer_t *buffer,
243                           unsigned int start, unsigned int end)
244 {
245   myanmar_syllable_type_t syllable_type = (myanmar_syllable_type_t) (buffer->info[start].syllable() & 0x0F);
246   switch (syllable_type) {
247
248     case myanmar_broken_cluster: /* We already inserted dotted-circles, so just call the consonant_syllable. */
249     case myanmar_consonant_syllable:
250       initial_reordering_consonant_syllable  (buffer, start, end);
251       break;
252
253     case myanmar_punctuation_cluster:
254     case myanmar_non_myanmar_cluster:
255       break;
256   }
257 }
258
259 static void
260 reorder_myanmar (const hb_ot_shape_plan_t *plan,
261                  hb_font_t *font,
262                  hb_buffer_t *buffer)
263 {
264   if (buffer->message (font, "start reordering myanmar"))
265   {
266     hb_syllabic_insert_dotted_circles (font, buffer,
267                                        myanmar_broken_cluster,
268                                        OT_GB);
269
270     foreach_syllable (buffer, start, end)
271       reorder_syllable_myanmar (plan, font->face, buffer, start, end);
272     (void) buffer->message (font, "end reordering myanmar");
273   }
274
275   HB_BUFFER_DEALLOCATE_VAR (buffer, myanmar_category);
276   HB_BUFFER_DEALLOCATE_VAR (buffer, myanmar_position);
277 }
278
279
280 const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar =
281 {
282   collect_features_myanmar,
283   nullptr, /* override_features */
284   nullptr, /* data_create */
285   nullptr, /* data_destroy */
286   nullptr, /* preprocess_text */
287   nullptr, /* postprocess_glyphs */
288   HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
289   nullptr, /* decompose */
290   nullptr, /* compose */
291   setup_masks_myanmar,
292   HB_TAG_NONE, /* gpos_tag */
293   nullptr, /* reorder_marks */
294   HB_OT_SHAPE_ZERO_WIDTH_MARKS_BY_GDEF_EARLY,
295   false, /* fallback_position */
296 };
297
298
299 /* Ugly Zawgyi encoding.
300  * Disable all auto processing.
301  * https://github.com/harfbuzz/harfbuzz/issues/1162 */
302 const hb_ot_complex_shaper_t _hb_ot_complex_shaper_myanmar_zawgyi =
303 {
304   nullptr, /* collect_features */
305   nullptr, /* override_features */
306   nullptr, /* data_create */
307   nullptr, /* data_destroy */
308   nullptr, /* preprocess_text */
309   nullptr, /* postprocess_glyphs */
310   HB_OT_SHAPE_NORMALIZATION_MODE_NONE,
311   nullptr, /* decompose */
312   nullptr, /* compose */
313   nullptr, /* setup_masks */
314   HB_TAG_NONE, /* gpos_tag */
315   nullptr, /* reorder_marks */
316   HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE,
317   false, /* fallback_position */
318 };
319
320
321 #endif