Imported Upstream version 0.9.3
[platform/upstream/harfbuzz.git] / src / hb-ot-shape-complex-indic.cc
1 /*
2  * Copyright © 2011,2012  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-ot-shape-complex-indic-private.hh"
28 #include "hb-ot-layout-private.hh"
29
30
31 /*
32  * Global Indic shaper options.
33  */
34
35 struct indic_options_t
36 {
37   int initialized : 1;
38   int uniscribe_bug_compatible : 1;
39 };
40
41 union indic_options_union_t {
42   int i;
43   indic_options_t opts;
44 };
45 ASSERT_STATIC (sizeof (int) == sizeof (indic_options_union_t));
46
47 static indic_options_union_t
48 indic_options_init (void)
49 {
50   indic_options_union_t u;
51   u.i = 0;
52   u.opts.initialized = 1;
53
54   char *c = getenv ("HB_OT_INDIC_OPTIONS");
55   u.opts.uniscribe_bug_compatible = c && strstr (c, "uniscribe-bug-compatible");
56
57   return u;
58 }
59
60 static inline indic_options_t
61 indic_options (void)
62 {
63   static indic_options_union_t options;
64
65   if (unlikely (!options.i)) {
66     /* This is idempotent and threadsafe. */
67     options = indic_options_init ();
68   }
69
70   return options.opts;
71 }
72
73
74 /*
75  * Indic configurations.  Note that we do not want to keep every single script-specific
76  * behavior in these tables necessarily.  This should mainly be used for per-script
77  * properties that are cheaper keeping here, than in the code.  Ie. if, say, one and
78  * only one script has an exception, that one script can be if'ed directly in the code,
79  * instead of adding a new flag in these structs.
80  */
81
82 enum base_position_t {
83   BASE_POS_FIRST,
84   BASE_POS_LAST
85 };
86 enum reph_position_t {
87   REPH_POS_DEFAULT     = POS_BEFORE_POST,
88
89   REPH_POS_AFTER_MAIN  = POS_AFTER_MAIN,
90   REPH_POS_BEFORE_SUB  = POS_BEFORE_SUB,
91   REPH_POS_AFTER_SUB   = POS_AFTER_SUB,
92   REPH_POS_BEFORE_POST = POS_BEFORE_POST,
93   REPH_POS_AFTER_POST  = POS_AFTER_POST
94 };
95 enum reph_mode_t {
96   REPH_MODE_IMPLICIT,  /* Reph formed out of initial Ra,H sequence. */
97   REPH_MODE_EXPLICIT,  /* Reph formed out of initial Ra,H,ZWJ sequence. */
98   REPH_MODE_VIS_REPHA, /* Encoded Repha character, no reordering needed. */
99   REPH_MODE_LOG_REPHA  /* Encoded Repha character, needs reordering. */
100 };
101 struct indic_config_t
102 {
103   hb_script_t     script;
104   bool            has_old_spec;
105   hb_codepoint_t  virama;
106   base_position_t base_pos;
107   reph_position_t reph_pos;
108   reph_mode_t     reph_mode;
109 };
110
111 static const indic_config_t indic_configs[] =
112 {
113   /* Default.  Should be first. */
114   {HB_SCRIPT_INVALID,   false,     0,BASE_POS_LAST, REPH_POS_DEFAULT,    REPH_MODE_IMPLICIT},
115   {HB_SCRIPT_DEVANAGARI,true, 0x094D,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT},
116   {HB_SCRIPT_BENGALI,   true, 0x09CD,BASE_POS_LAST, REPH_POS_AFTER_SUB,  REPH_MODE_IMPLICIT},
117   {HB_SCRIPT_GURMUKHI,  true, 0x0A4D,BASE_POS_LAST, REPH_POS_BEFORE_SUB, REPH_MODE_IMPLICIT},
118   {HB_SCRIPT_GUJARATI,  true, 0x0ACD,BASE_POS_LAST, REPH_POS_BEFORE_POST,REPH_MODE_IMPLICIT},
119   {HB_SCRIPT_ORIYA,     true, 0x0B4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_IMPLICIT},
120   {HB_SCRIPT_TAMIL,     true, 0x0BCD,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT},
121   {HB_SCRIPT_TELUGU,    true, 0x0C4D,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_EXPLICIT},
122   {HB_SCRIPT_KANNADA,   true, 0x0CCD,BASE_POS_LAST, REPH_POS_AFTER_POST, REPH_MODE_IMPLICIT},
123   {HB_SCRIPT_MALAYALAM, true, 0x0D4D,BASE_POS_LAST, REPH_POS_AFTER_MAIN, REPH_MODE_LOG_REPHA},
124   {HB_SCRIPT_SINHALA,   false,0x0DCA,BASE_POS_FIRST,REPH_POS_AFTER_MAIN, REPH_MODE_EXPLICIT},
125   {HB_SCRIPT_KHMER,     false,0x17D2,BASE_POS_FIRST,REPH_POS_DEFAULT,    REPH_MODE_VIS_REPHA},
126 };
127
128
129
130 /*
131  * Indic shaper.
132  */
133
134 struct feature_list_t {
135   hb_tag_t tag;
136   hb_bool_t is_global;
137 };
138
139 static const feature_list_t
140 indic_features[] =
141 {
142   /*
143    * Basic features.
144    * These features are applied in order, one at a time, after initial_reordering.
145    */
146   {HB_TAG('n','u','k','t'), true},
147   {HB_TAG('a','k','h','n'), true},
148   {HB_TAG('r','p','h','f'), false},
149   {HB_TAG('r','k','r','f'), true},
150   {HB_TAG('p','r','e','f'), false},
151   {HB_TAG('h','a','l','f'), false},
152   {HB_TAG('b','l','w','f'), false},
153   {HB_TAG('a','b','v','f'), false},
154   {HB_TAG('p','s','t','f'), false},
155   {HB_TAG('c','f','a','r'), false},
156   {HB_TAG('c','j','c','t'), true},
157   {HB_TAG('v','a','t','u'), true},
158   /*
159    * Other features.
160    * These features are applied all at once, after final_reordering.
161    */
162   {HB_TAG('i','n','i','t'), false},
163   {HB_TAG('p','r','e','s'), true},
164   {HB_TAG('a','b','v','s'), true},
165   {HB_TAG('b','l','w','s'), true},
166   {HB_TAG('p','s','t','s'), true},
167   {HB_TAG('h','a','l','n'), true},
168   /* Positioning features, though we don't care about the types. */
169   {HB_TAG('d','i','s','t'), true},
170   {HB_TAG('a','b','v','m'), true},
171   {HB_TAG('b','l','w','m'), true},
172 };
173
174 /*
175  * Must be in the same order as the indic_features array.
176  */
177 enum {
178   _NUKT,
179   _AKHN,
180   RPHF,
181   _RKRF,
182   PREF,
183   HALF,
184   BLWF,
185   ABVF,
186   PSTF,
187   CFAR,
188   _CJCT,
189   _VATU,
190
191   INIT,
192   _PRES,
193   _ABVS,
194   _BLWS,
195   _PSTS,
196   _HALN,
197   _DIST,
198   _ABVM,
199   _BLWM,
200
201   INDIC_NUM_FEATURES,
202   INDIC_BASIC_FEATURES = INIT /* Don't forget to update this! */
203 };
204
205 static void
206 initial_reordering (const hb_ot_shape_plan_t *plan,
207                     hb_font_t *font,
208                     hb_buffer_t *buffer);
209 static void
210 final_reordering (const hb_ot_shape_plan_t *plan,
211                   hb_font_t *font,
212                   hb_buffer_t *buffer);
213
214 static void
215 collect_features_indic (hb_ot_shape_planner_t *plan)
216 {
217   hb_ot_map_builder_t *map = &plan->map;
218
219   map->add_bool_feature (HB_TAG('l','o','c','l'));
220   /* The Indic specs do not require ccmp, but we apply it here since if
221    * there is a use of it, it's typically at the beginning. */
222   map->add_bool_feature (HB_TAG('c','c','m','p'));
223
224
225   unsigned int i = 0;
226   map->add_gsub_pause (initial_reordering);
227   for (; i < INDIC_BASIC_FEATURES; i++) {
228     map->add_bool_feature (indic_features[i].tag, indic_features[i].is_global);
229     map->add_gsub_pause (NULL);
230   }
231   map->add_gsub_pause (final_reordering);
232   for (; i < INDIC_NUM_FEATURES; i++) {
233     map->add_bool_feature (indic_features[i].tag, indic_features[i].is_global);
234   }
235 }
236
237 static void
238 override_features_indic (hb_ot_shape_planner_t *plan)
239 {
240   /* Uniscribe does not apply 'kern'. */
241   if (indic_options ().uniscribe_bug_compatible)
242     plan->map.add_feature (HB_TAG('k','e','r','n'), 0, true);
243 }
244
245
246 struct would_substitute_feature_t
247 {
248   inline void init (const hb_ot_map_t *map, hb_tag_t feature_tag)
249   {
250     map->get_stage_lookups (0/*GSUB*/,
251                             map->get_feature_stage (0/*GSUB*/, feature_tag),
252                             &lookups, &count);
253   }
254
255   inline bool would_substitute (hb_codepoint_t    *glyphs,
256                                 unsigned int       glyphs_count,
257                                 hb_face_t         *face) const
258   {
259     for (unsigned int i = 0; i < count; i++)
260       if (hb_ot_layout_would_substitute_lookup_fast (face, glyphs, glyphs_count, lookups[i].index))
261         return true;
262     return false;
263   }
264
265   private:
266   const hb_ot_map_t::lookup_map_t *lookups;
267   unsigned int count;
268 };
269
270 struct indic_shape_plan_t
271 {
272   ASSERT_POD ();
273
274   inline bool get_virama_glyph (hb_font_t *font, hb_codepoint_t *pglyph) const
275   {
276     hb_codepoint_t glyph = virama_glyph;
277     if (unlikely (virama_glyph == (hb_codepoint_t) -1))
278     {
279       if (!config->virama || !font->get_glyph (config->virama, 0, &glyph))
280         glyph = 0;
281       /* Technically speaking, the spec says we should apply 'locl' to virama too.
282        * Maybe one day... */
283
284       /* Our get_glyph() function needs a font, so we can't get the virama glyph
285        * during shape planning...  Instead, overwrite it here.  It's safe.  Don't worry! */
286       (const_cast<indic_shape_plan_t *> (this))->virama_glyph = glyph;
287     }
288
289     *pglyph = glyph;
290     return glyph != 0;
291   }
292
293   const indic_config_t *config;
294
295   bool is_old_spec;
296   hb_codepoint_t virama_glyph;
297
298   would_substitute_feature_t pref;
299   would_substitute_feature_t blwf;
300   would_substitute_feature_t pstf;
301
302   hb_mask_t mask_array[INDIC_NUM_FEATURES];
303 };
304
305 static void *
306 data_create_indic (const hb_ot_shape_plan_t *plan)
307 {
308   indic_shape_plan_t *indic_plan = (indic_shape_plan_t *) calloc (1, sizeof (indic_shape_plan_t));
309   if (unlikely (!indic_plan))
310     return NULL;
311
312   indic_plan->config = &indic_configs[0];
313   for (unsigned int i = 1; i < ARRAY_LENGTH (indic_configs); i++)
314     if (plan->props.script == indic_configs[i].script) {
315       indic_plan->config = &indic_configs[i];
316       break;
317     }
318
319   indic_plan->is_old_spec = indic_plan->config->has_old_spec && ((plan->map.get_chosen_script (0) & 0x000000FF) != '2');
320   indic_plan->virama_glyph = (hb_codepoint_t) -1;
321
322   indic_plan->pref.init (&plan->map, HB_TAG('p','r','e','f'));
323   indic_plan->blwf.init (&plan->map, HB_TAG('b','l','w','f'));
324   indic_plan->pstf.init (&plan->map, HB_TAG('p','s','t','f'));
325
326   for (unsigned int i = 0; i < ARRAY_LENGTH (indic_plan->mask_array); i++)
327     indic_plan->mask_array[i] = indic_features[i].is_global ? 0 : plan->map.get_1_mask (indic_features[i].tag);
328
329   return indic_plan;
330 }
331
332 static void
333 data_destroy_indic (void *data)
334 {
335   free (data);
336 }
337
338 static indic_position_t
339 consonant_position_from_face (const indic_shape_plan_t *indic_plan,
340                               hb_codepoint_t *glyphs, unsigned int glyphs_len,
341                               hb_face_t      *face)
342 {
343   if (indic_plan->pref.would_substitute (glyphs, glyphs_len, face)) return POS_BELOW_C;
344   if (indic_plan->blwf.would_substitute (glyphs, glyphs_len, face)) return POS_BELOW_C;
345   if (indic_plan->pstf.would_substitute (glyphs, glyphs_len, face)) return POS_POST_C;
346   return POS_BASE_C;
347 }
348
349
350 static void
351 setup_masks_indic (const hb_ot_shape_plan_t *plan HB_UNUSED,
352                    hb_buffer_t              *buffer,
353                    hb_font_t                *font HB_UNUSED)
354 {
355   HB_BUFFER_ALLOCATE_VAR (buffer, indic_category);
356   HB_BUFFER_ALLOCATE_VAR (buffer, indic_position);
357
358   /* We cannot setup masks here.  We save information about characters
359    * and setup masks later on in a pause-callback. */
360
361   unsigned int count = buffer->len;
362   for (unsigned int i = 0; i < count; i++)
363     set_indic_properties (buffer->info[i]);
364 }
365
366 static int
367 compare_indic_order (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb)
368 {
369   int a = pa->indic_position();
370   int b = pb->indic_position();
371
372   return a < b ? -1 : a == b ? 0 : +1;
373 }
374
375
376
377 static void
378 update_consonant_positions (const hb_ot_shape_plan_t *plan,
379                             hb_font_t         *font,
380                             hb_buffer_t       *buffer)
381 {
382   const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data;
383
384   unsigned int consonant_pos = indic_plan->is_old_spec ? 0 : 1;
385   hb_codepoint_t glyphs[2];
386   if (indic_plan->get_virama_glyph (font, &glyphs[1 - consonant_pos]))
387   {
388     hb_face_t *face = font->face;
389     unsigned int count = buffer->len;
390     for (unsigned int i = 0; i < count; i++)
391       if (buffer->info[i].indic_position() == POS_BASE_C) {
392         glyphs[consonant_pos] = buffer->info[i].codepoint;
393         buffer->info[i].indic_position() = consonant_position_from_face (indic_plan, glyphs, 2, face);
394       }
395   }
396 }
397
398
399 /* Rules from:
400  * https://www.microsoft.com/typography/otfntdev/devanot/shaping.aspx */
401
402 static void
403 initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan, hb_buffer_t *buffer,
404                                        unsigned int start, unsigned int end)
405 {
406   const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data;
407   hb_glyph_info_t *info = buffer->info;
408
409
410   /* 1. Find base consonant:
411    *
412    * The shaping engine finds the base consonant of the syllable, using the
413    * following algorithm: starting from the end of the syllable, move backwards
414    * until a consonant is found that does not have a below-base or post-base
415    * form (post-base forms have to follow below-base forms), or that is not a
416    * pre-base reordering Ra, or arrive at the first consonant. The consonant
417    * stopped at will be the base.
418    *
419    *   o If the syllable starts with Ra + Halant (in a script that has Reph)
420    *     and has more than one consonant, Ra is excluded from candidates for
421    *     base consonants.
422    */
423
424   unsigned int base = end;
425   bool has_reph = false;
426
427   {
428     /* -> If the syllable starts with Ra + Halant (in a script that has Reph)
429      *    and has more than one consonant, Ra is excluded from candidates for
430      *    base consonants. */
431     unsigned int limit = start;
432     if (indic_plan->mask_array[RPHF] &&
433         start + 3 <= end &&
434         info[start].indic_category() == OT_Ra &&
435         info[start + 1].indic_category() == OT_H &&
436         (/* TODO Handle other Reph modes. */
437          (indic_plan->config->reph_mode == REPH_MODE_IMPLICIT && !is_joiner (info[start + 2])) ||
438          (indic_plan->config->reph_mode == REPH_MODE_EXPLICIT && info[start + 2].indic_category() == OT_ZWJ)
439         ))
440     {
441       limit += 2;
442       while (limit < end && is_joiner (info[limit]))
443         limit++;
444       base = start;
445       has_reph = true;
446     };
447
448     switch (indic_plan->config->base_pos == BASE_POS_LAST)
449     {
450       case BASE_POS_LAST:
451       {
452         /* -> starting from the end of the syllable, move backwards */
453         unsigned int i = end;
454         bool seen_below = false;
455         do {
456           i--;
457           /* -> until a consonant is found */
458           if (is_consonant (info[i]))
459           {
460             /* -> that does not have a below-base or post-base form
461              * (post-base forms have to follow below-base forms), */
462             if (info[i].indic_position() != POS_BELOW_C &&
463                 (info[i].indic_position() != POS_POST_C || seen_below))
464             {
465               base = i;
466               break;
467             }
468             if (info[i].indic_position() == POS_BELOW_C)
469               seen_below = true;
470
471             /* -> or that is not a pre-base reordering Ra,
472              *
473              * IMPLEMENTATION NOTES:
474              *
475              * Our pre-base reordering Ra's are marked POS_BELOW, so will be skipped
476              * by the logic above already.
477              */
478
479             /* -> or arrive at the first consonant. The consonant stopped at will
480              * be the base. */
481             base = i;
482           }
483           else
484           {
485             /* A ZWJ after a Halant stops the base search, and requests an explicit
486              * half form.
487              * A ZWJ before a Halant, requests a subjoined form instead, and hence
488              * search continues.  This is particularly important for Bengali
489              * sequence Ra,H,Ya that shouls form Ya-Phalaa by subjoining Ya. */
490             if (start < i &&
491                 info[i].indic_category() == OT_ZWJ &&
492                 info[i - 1].indic_category() == OT_H)
493               break;
494           }
495         } while (i > limit);
496       }
497       break;
498
499       case BASE_POS_FIRST:
500       {
501         /* In scripts without half forms (eg. Khmer), the first consonant is always the base. */
502
503         if (!has_reph)
504           base = limit;
505
506         /* Find the last base consonant that is not blocked by ZWJ.  If there is
507          * a ZWJ right before a base consonant, that would request a subjoined form. */
508         for (unsigned int i = limit; i < end; i++)
509           if (is_consonant (info[i]) && info[i].indic_position() == POS_BASE_C)
510           {
511             if (limit < i && info[i - 1].indic_category() == OT_ZWJ)
512               break;
513             else
514               base = i;
515           }
516
517         /* Mark all subsequent consonants as below. */
518         for (unsigned int i = base + 1; i < end; i++)
519           if (is_consonant (info[i]) && info[i].indic_position() == POS_BASE_C)
520             info[i].indic_position() = POS_BELOW_C;
521       }
522       break;
523
524       default:
525       abort ();
526     }
527
528     /* -> If the syllable starts with Ra + Halant (in a script that has Reph)
529      *    and has more than one consonant, Ra is excluded from candidates for
530      *    base consonants.
531      *
532      *  Only do this for unforced Reph. (ie. not for Ra,H,ZWJ. */
533     if (has_reph && base == start && start + 2 == limit) {
534       /* Have no other consonant, so Reph is not formed and Ra becomes base. */
535       has_reph = false;
536     }
537   }
538
539   if (base < end)
540     info[base].indic_position() = POS_BASE_C;
541
542
543   /* 2. Decompose and reorder Matras:
544    *
545    * Each matra and any syllable modifier sign in the cluster are moved to the
546    * appropriate position relative to the consonant(s) in the cluster. The
547    * shaping engine decomposes two- or three-part matras into their constituent
548    * parts before any repositioning. Matra characters are classified by which
549    * consonant in a conjunct they have affinity for and are reordered to the
550    * following positions:
551    *
552    *   o Before first half form in the syllable
553    *   o After subjoined consonants
554    *   o After post-form consonant
555    *   o After main consonant (for above marks)
556    *
557    * IMPLEMENTATION NOTES:
558    *
559    * The normalize() routine has already decomposed matras for us, so we don't
560    * need to worry about that.
561    */
562
563
564   /* 3.  Reorder marks to canonical order:
565    *
566    * Adjacent nukta and halant or nukta and vedic sign are always repositioned
567    * if necessary, so that the nukta is first.
568    *
569    * IMPLEMENTATION NOTES:
570    *
571    * We don't need to do this: the normalize() routine already did this for us.
572    */
573
574
575   /* Reorder characters */
576
577   for (unsigned int i = start; i < base; i++)
578     info[i].indic_position() = MIN (POS_PRE_C, (indic_position_t) info[i].indic_position());
579
580   if (base < end)
581     info[base].indic_position() = POS_BASE_C;
582
583   /* Mark final consonants.  A final consonant is one appearing after a matra,
584    * like in Khmer. */
585   for (unsigned int i = base + 1; i < end; i++)
586     if (info[i].indic_category() == OT_M) {
587       for (unsigned int j = i + 1; j < end; j++)
588         if (is_consonant (info[j])) {
589           info[j].indic_position() = POS_FINAL_C;
590           break;
591         }
592       break;
593     }
594
595   /* Handle beginning Ra */
596   if (has_reph)
597     info[start].indic_position() = POS_RA_TO_BECOME_REPH;
598
599   /* For old-style Indic script tags, move the first post-base Halant after
600    * last consonant. */
601   if (indic_plan->is_old_spec) {
602     for (unsigned int i = base + 1; i < end; i++)
603       if (info[i].indic_category() == OT_H) {
604         unsigned int j;
605         for (j = end - 1; j > i; j--)
606           if (is_consonant (info[j]))
607             break;
608         if (j > i) {
609           /* Move Halant to after last consonant. */
610           hb_glyph_info_t t = info[i];
611           memmove (&info[i], &info[i + 1], (j - i) * sizeof (info[0]));
612           info[j] = t;
613         }
614         break;
615       }
616   }
617
618   /* Attach misc marks to previous char to move with them. */
619   {
620     indic_position_t last_pos = POS_START;
621     for (unsigned int i = start; i < end; i++)
622     {
623       if ((FLAG (info[i].indic_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | HALANT_OR_COENG_FLAGS)))
624       {
625         info[i].indic_position() = last_pos;
626         if (unlikely (indic_options ().uniscribe_bug_compatible &&
627                       info[i].indic_category() == OT_H &&
628                       info[i].indic_position() == POS_PRE_M))
629         {
630           /*
631            * Uniscribe doesn't move the Halant with Left Matra.
632            * TEST: U+092B,U+093F,U+094DE
633            */
634           for (unsigned int j = i; j > start; j--)
635             if (info[j - 1].indic_position() != POS_PRE_M) {
636               info[i].indic_position() = info[j - 1].indic_position();
637               break;
638             }
639         }
640       } else if (info[i].indic_position() != POS_SMVD) {
641         last_pos = (indic_position_t) info[i].indic_position();
642       }
643     }
644   }
645   /* Re-attach ZWJ, ZWNJ, and halant to next char, for after-base consonants. */
646   {
647     unsigned int last_halant = end;
648     for (unsigned int i = base + 1; i < end; i++)
649       if (is_halant_or_coeng (info[i]))
650         last_halant = i;
651       else if (is_consonant (info[i])) {
652         for (unsigned int j = last_halant; j < i; j++)
653           if (info[j].indic_position() != POS_SMVD)
654             info[j].indic_position() = info[i].indic_position();
655       }
656   }
657
658   {
659     /* Things are out-of-control for post base positions, they may shuffle
660      * around like crazy, so merge clusters.  For pre-base stuff, we handle
661      * cluster issues in final reordering. */
662     buffer->merge_clusters (base, end);
663     /* Sit tight, rock 'n roll! */
664     hb_bubble_sort (info + start, end - start, compare_indic_order);
665     /* Find base again */
666     base = end;
667     for (unsigned int i = start; i < end; i++)
668       if (info[i].indic_position() == POS_BASE_C) {
669         base = i;
670         break;
671       }
672   }
673
674   /* Setup masks now */
675
676   {
677     hb_mask_t mask;
678
679     /* Reph */
680     for (unsigned int i = start; i < end && info[i].indic_position() == POS_RA_TO_BECOME_REPH; i++)
681       info[i].mask |= indic_plan->mask_array[RPHF];
682
683     /* Pre-base */
684     mask = indic_plan->mask_array[HALF];
685     for (unsigned int i = start; i < base; i++)
686       info[i].mask  |= mask;
687     /* Base */
688     mask = 0;
689     if (base < end)
690       info[base].mask |= mask;
691     /* Post-base */
692     mask = indic_plan->mask_array[BLWF] | indic_plan->mask_array[ABVF] | indic_plan->mask_array[PSTF];
693     for (unsigned int i = base + 1; i < end; i++)
694       info[i].mask  |= mask;
695   }
696
697   /* XXX This will not match for old-Indic spec since the Halant-Ra order is reversed already. */
698   if (indic_plan->mask_array[PREF] && base + 2 < end)
699   {
700     /* Find a Halant,Ra sequence and mark it for pre-base reordering processing. */
701     for (unsigned int i = base + 1; i + 1 < end; i++)
702       if (is_halant_or_coeng (info[i]) &&
703           info[i + 1].indic_category() == OT_Ra)
704       {
705         info[i++].mask |= indic_plan->mask_array[PREF];
706         info[i++].mask |= indic_plan->mask_array[PREF];
707
708         /* Mark the subsequent stuff with 'cfar'.  Used in Khmer.
709          * Read the feature spec.
710          * This allows distinguishing the following cases with MS Khmer fonts:
711          * U+1784,U+17D2,U+179A,U+17D2,U+1782
712          * U+1784,U+17D2,U+1782,U+17D2,U+179A
713          */
714         for (; i < end; i++)
715           info[i].mask |= indic_plan->mask_array[CFAR];
716
717         break;
718       }
719   }
720
721   /* Apply ZWJ/ZWNJ effects */
722   for (unsigned int i = start + 1; i < end; i++)
723     if (is_joiner (info[i])) {
724       bool non_joiner = info[i].indic_category() == OT_ZWNJ;
725       unsigned int j = i;
726
727       do {
728         j--;
729
730         /* A ZWJ disables CJCT, however, it's mere presence is enough
731          * to disable ligation.  No explicit action needed. */
732
733         /* A ZWNJ disables HALF. */
734         if (non_joiner)
735           info[j].mask &= ~indic_plan->mask_array[HALF];
736
737       } while (j > start && !is_consonant (info[j]));
738     }
739 }
740
741
742 static void
743 initial_reordering_vowel_syllable (const hb_ot_shape_plan_t *plan,
744                                    hb_buffer_t *buffer,
745                                    unsigned int start, unsigned int end)
746 {
747   /* We made the vowels look like consonants.  So let's call the consonant logic! */
748   initial_reordering_consonant_syllable (plan, buffer, start, end);
749 }
750
751 static void
752 initial_reordering_standalone_cluster (const hb_ot_shape_plan_t *plan,
753                                        hb_buffer_t *buffer,
754                                        unsigned int start, unsigned int end)
755 {
756   /* We treat NBSP/dotted-circle as if they are consonants, so we should just chain.
757    * Only if not in compatibility mode that is... */
758
759   if (indic_options ().uniscribe_bug_compatible)
760   {
761     /* For dotted-circle, this is what Uniscribe does:
762      * If dotted-circle is the last glyph, it just does nothing.
763      * Ie. It doesn't form Reph. */
764     if (buffer->info[end - 1].indic_category() == OT_DOTTEDCIRCLE)
765       return;
766   }
767
768   initial_reordering_consonant_syllable (plan, buffer, start, end);
769 }
770
771 static void
772 initial_reordering_non_indic (const hb_ot_shape_plan_t *plan HB_UNUSED,
773                               hb_buffer_t *buffer HB_UNUSED,
774                               unsigned int start HB_UNUSED, unsigned int end HB_UNUSED)
775 {
776   /* Nothing to do right now.  If we ever switch to using the output
777    * buffer in the reordering process, we'd need to next_glyph() here. */
778 }
779
780 #include "hb-ot-shape-complex-indic-machine.hh"
781
782 static void
783 initial_reordering (const hb_ot_shape_plan_t *plan,
784                     hb_font_t *font,
785                     hb_buffer_t *buffer)
786 {
787   update_consonant_positions (plan, font, buffer);
788   find_syllables (plan, buffer);
789 }
790
791 static void
792 final_reordering_syllable (const hb_ot_shape_plan_t *plan,
793                            hb_buffer_t *buffer,
794                            unsigned int start, unsigned int end)
795 {
796   const indic_shape_plan_t *indic_plan = (const indic_shape_plan_t *) plan->data;
797   hb_glyph_info_t *info = buffer->info;
798
799   /* 4. Final reordering:
800    *
801    * After the localized forms and basic shaping forms GSUB features have been
802    * applied (see below), the shaping engine performs some final glyph
803    * reordering before applying all the remaining font features to the entire
804    * cluster.
805    */
806
807   /* Find base again */
808   unsigned int base;
809   for (base = start; base < end; base++)
810     if (info[base].indic_position() >= POS_BASE_C) {
811       if (start < base && info[base].indic_position() > POS_BASE_C)
812         base--;
813       break;
814     }
815
816
817   /*   o Reorder matras:
818    *
819    *     If a pre-base matra character had been reordered before applying basic
820    *     features, the glyph can be moved closer to the main consonant based on
821    *     whether half-forms had been formed. Actual position for the matra is
822    *     defined as “after last standalone halant glyph, after initial matra
823    *     position and before the main consonant”. If ZWJ or ZWNJ follow this
824    *     halant, position is moved after it.
825    */
826
827   if (start + 1 < end && start < base) /* Otherwise there can't be any pre-base matra characters. */
828   {
829     /* If we lost track of base, alas, position before last thingy. */
830     unsigned int new_pos = base == end ? base - 2 : base - 1;
831
832     /* Malayalam does not have "half" forms or explicit virama forms.
833      * The glyphs formed by 'half' are Chillus.  We want to position
834      * matra after them all.
835      */
836     if (buffer->props.script != HB_SCRIPT_MALAYALAM)
837     {
838       while (new_pos > start &&
839              !(is_one_of (info[new_pos], (FLAG (OT_M) | FLAG (OT_H) | FLAG (OT_Coeng)))))
840         new_pos--;
841
842       /* If we found no Halant we are done.
843        * Otherwise only proceed if the Halant does
844        * not belong to the Matra itself! */
845       if (is_halant_or_coeng (info[new_pos]) &&
846           info[new_pos].indic_position() != POS_PRE_M)
847       {
848         /* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */
849         if (new_pos + 1 < end && is_joiner (info[new_pos + 1]))
850           new_pos++;
851       }
852       else
853         new_pos = start; /* No move. */
854     }
855
856     if (start < new_pos)
857     {
858       /* Now go see if there's actually any matras... */
859       for (unsigned int i = new_pos; i > start; i--)
860         if (info[i - 1].indic_position () == POS_PRE_M)
861         {
862           unsigned int old_pos = i - 1;
863           hb_glyph_info_t tmp = info[old_pos];
864           memmove (&info[old_pos], &info[old_pos + 1], (new_pos - old_pos) * sizeof (info[0]));
865           info[new_pos] = tmp;
866           new_pos--;
867         }
868       buffer->merge_clusters (new_pos, MIN (end, base + 1));
869     } else {
870       for (unsigned int i = start; i < base; i++)
871         if (info[i].indic_position () == POS_PRE_M) {
872           buffer->merge_clusters (i, MIN (end, base + 1));
873           break;
874         }
875     }
876   }
877
878
879   /*   o Reorder reph:
880    *
881    *     Reph’s original position is always at the beginning of the syllable,
882    *     (i.e. it is not reordered at the character reordering stage). However,
883    *     it will be reordered according to the basic-forms shaping results.
884    *     Possible positions for reph, depending on the script, are; after main,
885    *     before post-base consonant forms, and after post-base consonant forms.
886    */
887
888   /* If there's anything after the Ra that has the REPH pos, it ought to be halant.
889    * Which means that the font has failed to ligate the Reph.  In which case, we
890    * shouldn't move. */
891   if (start + 1 < end &&
892       info[start].indic_position() == POS_RA_TO_BECOME_REPH &&
893       info[start + 1].indic_position() != POS_RA_TO_BECOME_REPH)
894   {
895     unsigned int new_reph_pos;
896     reph_position_t reph_pos = indic_plan->config->reph_pos;
897
898     /* XXX Figure out old behavior too */
899
900     /*       1. If reph should be positioned after post-base consonant forms,
901      *          proceed to step 5.
902      */
903     if (reph_pos == REPH_POS_AFTER_POST)
904     {
905       goto reph_step_5;
906     }
907
908     /*       2. If the reph repositioning class is not after post-base: target
909      *          position is after the first explicit halant glyph between the
910      *          first post-reph consonant and last main consonant. If ZWJ or ZWNJ
911      *          are following this halant, position is moved after it. If such
912      *          position is found, this is the target position. Otherwise,
913      *          proceed to the next step.
914      *
915      *          Note: in old-implementation fonts, where classifications were
916      *          fixed in shaping engine, there was no case where reph position
917      *          will be found on this step.
918      */
919     {
920       new_reph_pos = start + 1;
921       while (new_reph_pos < base && !is_halant_or_coeng (info[new_reph_pos]))
922         new_reph_pos++;
923
924       if (new_reph_pos < base && is_halant_or_coeng (info[new_reph_pos])) {
925         /* ->If ZWJ or ZWNJ are following this halant, position is moved after it. */
926         if (new_reph_pos + 1 < base && is_joiner (info[new_reph_pos + 1]))
927           new_reph_pos++;
928         goto reph_move;
929       }
930     }
931
932     /*       3. If reph should be repositioned after the main consonant: find the
933      *          first consonant not ligated with main, or find the first
934      *          consonant that is not a potential pre-base reordering Ra.
935      */
936     if (reph_pos == REPH_POS_AFTER_MAIN)
937     {
938       new_reph_pos = base;
939       /* XXX Skip potential pre-base reordering Ra. */
940       while (new_reph_pos + 1 < end && info[new_reph_pos + 1].indic_position() <= POS_AFTER_MAIN)
941         new_reph_pos++;
942       if (new_reph_pos < end)
943         goto reph_move;
944     }
945
946     /*       4. If reph should be positioned before post-base consonant, find
947      *          first post-base classified consonant not ligated with main. If no
948      *          consonant is found, the target position should be before the
949      *          first matra, syllable modifier sign or vedic sign.
950      */
951     /* This is our take on what step 4 is trying to say (and failing, BADLY). */
952     if (reph_pos == REPH_POS_AFTER_SUB)
953     {
954       new_reph_pos = base;
955       while (new_reph_pos < end &&
956              !( FLAG (info[new_reph_pos + 1].indic_position()) & (FLAG (POS_POST_C) | FLAG (POS_AFTER_POST) | FLAG (POS_SMVD))))
957         new_reph_pos++;
958       if (new_reph_pos < end)
959         goto reph_move;
960     }
961
962     /*       5. If no consonant is found in steps 3 or 4, move reph to a position
963      *          immediately before the first post-base matra, syllable modifier
964      *          sign or vedic sign that has a reordering class after the intended
965      *          reph position. For example, if the reordering position for reph
966      *          is post-main, it will skip above-base matras that also have a
967      *          post-main position.
968      */
969     reph_step_5:
970     {
971       /* Copied from step 2. */
972       new_reph_pos = start + 1;
973       while (new_reph_pos < base && !is_halant_or_coeng (info[new_reph_pos]))
974         new_reph_pos++;
975
976       if (new_reph_pos < base && is_halant_or_coeng (info[new_reph_pos])) {
977         /* ->If ZWJ or ZWNJ are following this halant, position is moved after it. */
978         if (new_reph_pos + 1 < base && is_joiner (info[new_reph_pos + 1]))
979           new_reph_pos++;
980         goto reph_move;
981       }
982     }
983
984     /*       6. Otherwise, reorder reph to the end of the syllable.
985      */
986     {
987       new_reph_pos = end - 1;
988       while (new_reph_pos > start && info[new_reph_pos].indic_position() == POS_SMVD)
989         new_reph_pos--;
990
991       /*
992        * If the Reph is to be ending up after a Matra,Halant sequence,
993        * position it before that Halant so it can interact with the Matra.
994        * However, if it's a plain Consonant,Halant we shouldn't do that.
995        * Uniscribe doesn't do this.
996        * TEST: U+0930,U+094D,U+0915,U+094B,U+094D
997        */
998       if (!indic_options ().uniscribe_bug_compatible &&
999           unlikely (is_halant_or_coeng (info[new_reph_pos]))) {
1000         for (unsigned int i = base + 1; i < new_reph_pos; i++)
1001           if (info[i].indic_category() == OT_M) {
1002             /* Ok, got it. */
1003             new_reph_pos--;
1004           }
1005       }
1006       goto reph_move;
1007     }
1008
1009     reph_move:
1010     {
1011       /* Yay, one big cluster! Merge before moving. */
1012       buffer->merge_clusters (start, end);
1013
1014       /* Move */
1015       hb_glyph_info_t reph = info[start];
1016       memmove (&info[start], &info[start + 1], (new_reph_pos - start) * sizeof (info[0]));
1017       info[new_reph_pos] = reph;
1018     }
1019   }
1020
1021
1022   /*   o Reorder pre-base reordering consonants:
1023    *
1024    *     If a pre-base reordering consonant is found, reorder it according to
1025    *     the following rules:
1026    */
1027
1028   if (indic_plan->mask_array[PREF] && base + 1 < end) /* Otherwise there can't be any pre-base reordering Ra. */
1029   {
1030     for (unsigned int i = base + 1; i < end; i++)
1031       if ((info[i].mask & indic_plan->mask_array[PREF]) != 0)
1032       {
1033         /*       1. Only reorder a glyph produced by substitution during application
1034          *          of the <pref> feature. (Note that a font may shape a Ra consonant with
1035          *          the feature generally but block it in certain contexts.)
1036          */
1037         if (i + 1 == end || (info[i + 1].mask & indic_plan->mask_array[PREF]) == 0)
1038         {
1039           /*
1040            *       2. Try to find a target position the same way as for pre-base matra.
1041            *          If it is found, reorder pre-base consonant glyph.
1042            *
1043            *       3. If position is not found, reorder immediately before main
1044            *          consonant.
1045            */
1046
1047           unsigned int new_pos = base;
1048           while (new_pos > start &&
1049                  !(is_one_of (info[new_pos - 1], FLAG(OT_M) | HALANT_OR_COENG_FLAGS)))
1050             new_pos--;
1051
1052           /* In Khmer coeng model, a V,Ra can go *after* matras.  If it goes after a
1053            * split matra, it should be reordered to *before* the left part of such matra. */
1054           if (new_pos > start && info[new_pos - 1].indic_category() == OT_M)
1055           {
1056             unsigned int old_pos = i;
1057             for (unsigned int i = base + 1; i < old_pos; i++)
1058               if (info[i].indic_category() == OT_M)
1059               {
1060                 new_pos--;
1061                 break;
1062               }
1063           }
1064
1065           if (new_pos > start && is_halant_or_coeng (info[new_pos - 1]))
1066             /* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */
1067             if (new_pos < end && is_joiner (info[new_pos]))
1068               new_pos++;
1069
1070           {
1071             unsigned int old_pos = i;
1072             buffer->merge_clusters (new_pos, old_pos + 1);
1073             hb_glyph_info_t tmp = info[old_pos];
1074             memmove (&info[new_pos + 1], &info[new_pos], (old_pos - new_pos) * sizeof (info[0]));
1075             info[new_pos] = tmp;
1076           }
1077         }
1078
1079         break;
1080       }
1081   }
1082
1083
1084   /* Apply 'init' to the Left Matra if it's a word start. */
1085   if (info[start].indic_position () == POS_PRE_M &&
1086       (!start ||
1087        !(FLAG (_hb_glyph_info_get_general_category (&info[start - 1])) &
1088          FLAG_RANGE (HB_UNICODE_GENERAL_CATEGORY_FORMAT, HB_UNICODE_GENERAL_CATEGORY_NON_SPACING_MARK))))
1089     info[start].mask |= indic_plan->mask_array[INIT];
1090
1091
1092   /*
1093    * Finish off the clusters and go home!
1094    */
1095   if (indic_options ().uniscribe_bug_compatible)
1096   {
1097     /* Uniscribe merges the entire cluster.
1098      * This means, half forms are submerged into the main consonants cluster.
1099      * This is unnecessary, and makes cursor positioning harder, but that's what
1100      * Uniscribe does. */
1101     buffer->merge_clusters (start, end);
1102   }
1103 }
1104
1105
1106 static void
1107 final_reordering (const hb_ot_shape_plan_t *plan,
1108                   hb_font_t *font,
1109                   hb_buffer_t *buffer)
1110 {
1111   unsigned int count = buffer->len;
1112   if (!count) return;
1113
1114   hb_glyph_info_t *info = buffer->info;
1115   unsigned int last = 0;
1116   unsigned int last_syllable = info[0].syllable();
1117   for (unsigned int i = 1; i < count; i++)
1118     if (last_syllable != info[i].syllable()) {
1119       final_reordering_syllable (plan, buffer, last, i);
1120       last = i;
1121       last_syllable = info[last].syllable();
1122     }
1123   final_reordering_syllable (plan, buffer, last, count);
1124
1125   HB_BUFFER_DEALLOCATE_VAR (buffer, indic_category);
1126   HB_BUFFER_DEALLOCATE_VAR (buffer, indic_position);
1127 }
1128
1129
1130 const hb_ot_complex_shaper_t _hb_ot_complex_shaper_indic =
1131 {
1132   "indic",
1133   collect_features_indic,
1134   override_features_indic,
1135   data_create_indic,
1136   data_destroy_indic,
1137   NULL, /* preprocess_text */
1138   NULL, /* normalization_preference */
1139   setup_masks_indic,
1140   false, /* zero_width_attached_marks */
1141 };